From 88913f2b231c7bad0a535dcc11aab4dbf5ad9127 Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Wed, 21 Dec 2011 14:42:42 +0100 Subject: [PATCH] Convert CRLF (dos) to LF (unix) Prior to this change, roughly 5% (~300 out of 6000+) of files under the source tree had CRLF line endings as opposed to the majority which have LF endings. This change normalizes these files to LF for consistency going forward. Command used: $ git ls-files | xargs file | grep CRLF | cut -d":" -f1 | xargs dos2unix Issue: SPR-5608 --- build.versions | 8 +- .../AsyncExecutionInterceptor.java | 206 +- .../TrickyAspectJPointcutExpressionTests.java | 348 +-- .../aop/support/ClassUtilsTests.java | 82 +- ...nterfaceDrivenDependencyInjectionAspect.aj | 108 +- .../cache/aspectj/AbstractCacheAspect.aj | 146 +- .../cache/aspectj/AnnotationCacheAspect.aj | 230 +- .../AbstractMethodMockingControl.aj | 394 ++-- ...otationDrivenStaticEntityMockingControl.aj | 136 +- .../staticmock/MockStaticEntityMethods.java | 68 +- .../aspectj/AbstractAsyncExecutionAspect.aj | 150 +- .../aspectj/AnnotationAsyncExecutionAspect.aj | 108 +- .../aspectj/AbstractTransactionAspect.aj | 186 +- .../aspectj/AnnotationTransactionAspect.aj | 150 +- .../AutoProxyWithCodeStyleAspectsTests.java | 64 +- .../aop/aspectj/autoproxy/CodeStyleAspect.aj | 72 +- ...SpringConfiguredWithAutoProxyingTests.java | 64 +- .../cache/aspectj/AbstractAnnotationTest.java | 1190 +++++------ .../cache/aspectj/AspectJAnnotationTest.java | 66 +- .../AnnotatedClassCacheableService.java | 274 +-- .../cache/config/CacheableService.java | 138 +- .../cache/config/DefaultCacheableService.java | 286 +-- ...nDrivenStaticEntityMockingControlTest.java | 292 +-- .../mock/staticmock/Delegate.java | 184 +- .../mock/staticmock/Person.java | 48 +- .../mock/staticmock/Person_Roo_Entity.aj | 200 +- .../AnnotationAsyncExecutionAspectTests.java | 356 ++-- .../ClassWithPrivateAnnotatedMember.java | 68 +- .../ClassWithProtectedAnnotatedMember.java | 68 +- .../transaction/aspectj/ITransactional.java | 20 +- ...ethodAnnotationOnClassWithNoInterface.java | 38 +- .../aspectj/TransactionAspectTests.java | 522 ++--- ...lAnnotationOnlyOnClassWithNoInterface.java | 40 +- org.springframework.aspects/template.mf | 40 +- .../beans/factory/annotation/Value.java | 122 +- .../factory/config/BeanExpressionContext.java | 168 +- .../config/BeanExpressionResolver.java | 90 +- .../config/ProviderCreatingFactoryBean.java | 190 +- .../beans/factory/support/ManagedArray.java | 90 +- .../support/SecurityContextProvider.java | 70 +- .../SimpleSecurityContextProvider.java | 116 +- .../SimpleConstructorNamespaceHandler.java | 300 +-- .../beans/propertyeditors/CurrencyEditor.java | 86 +- .../beans/propertyeditors/TimeZoneEditor.java | 92 +- .../beans/propertyeditors/UUIDEditor.java | 100 +- .../src/test/java/com/foo/Component.java | 52 +- .../foo/ComponentBeanDefinitionParser.java | 104 +- .../ComponentBeanDefinitionParserTest.java | 146 +- .../java/com/foo/ComponentFactoryBean.java | 70 +- .../com/foo/ComponentNamespaceHandler.java | 20 +- .../security/CallbacksSecurityTests.java | 1048 ++++----- .../beans/factory/support/security/policy.all | 4 +- .../security/support/ConstructorBean.java | 60 +- .../security/support/CustomCallbackBean.java | 60 +- .../security/support/CustomFactoryBean.java | 78 +- .../support/security/support/DestroyBean.java | 56 +- .../support/security/support/FactoryBean.java | 72 +- .../support/security/support/InitBean.java | 56 +- .../security/support/PropertyBean.java | 60 +- .../src/test/java/test/beans/DummyBean.java | 136 +- .../.settings/org.eclipse.jdt.ui.prefs | 8 +- .../commonj/TimerManagerAccessor.java | 326 +-- .../commonj/TimerManagerTaskScheduler.java | 348 +-- .../context/EmbeddedValueResolverAware.java | 82 +- .../AnnotatedBeanDefinitionReader.java | 354 +-- .../context/annotation/DependsOn.java | 108 +- .../Jsr330ScopeMetadataResolver.java | 222 +- .../annotation/ScopedProxyCreator.java | 86 +- .../GenericApplicationListenerAdapter.java | 146 +- .../event/SmartApplicationListener.java | 84 +- .../BeanExpressionContextAccessor.java | 110 +- .../expression/BeanFactoryAccessor.java | 110 +- .../expression/BeanFactoryResolver.java | 102 +- .../context/expression/MapAccessor.java | 168 +- .../StandardBeanExpressionResolver.java | 306 +-- .../support/GenericXmlApplicationContext.java | 268 +-- .../number/AbstractNumberFormatter.java | 148 +- .../GlassFishClassLoaderAdapter.java | 256 +-- .../jboss/JBossClassLoaderAdapter.java | 66 +- .../jboss/JBossLoadTimeWeaver.java | 182 +- .../classloading/jboss/JBossMCAdapter.java | 288 +-- .../jboss/JBossMCTranslatorAdapter.java | 162 +- .../jboss/JBossModulesAdapter.java | 140 +- .../classloading/jboss/package-info.java | 16 +- .../oc4j/OC4JClassLoaderAdapter.java | 174 +- .../oc4j/OC4JClassPreprocessorAdapter.java | 188 +- .../WebSphereClassLoaderAdapter.java | 222 +- .../WebSphereClassPreDefinePlugin.java | 200 +- .../websphere/WebSphereLoadTimeWeaver.java | 140 +- .../classloading/websphere/package-info.java | 16 +- .../jndi/JndiLocatorDelegate.java | 138 +- .../scheduling/TaskScheduler.java | 278 +-- .../springframework/scheduling/Trigger.java | 82 +- .../scheduling/TriggerContext.java | 96 +- .../scheduling/annotation/Async.java | 98 +- .../scheduling/annotation/AsyncResult.java | 126 +- .../scheduling/annotation/Scheduled.java | 142 +- .../concurrent/ConcurrentTaskScheduler.java | 374 ++-- .../ExecutorConfigurationSupport.java | 320 +-- .../concurrent/ReschedulingRunnable.java | 248 +-- .../concurrent/ThreadPoolTaskScheduler.java | 502 ++--- .../config/ScheduledTaskRegistrar.java | 426 ++-- .../scheduling/config/package-info.java | 18 +- .../scheduling/support/CronTrigger.java | 184 +- .../support/ScheduledMethodRunnable.java | 148 +- .../support/SimpleTriggerContext.java | 126 +- .../validation/annotation/package-info.java | 16 +- .../BeanValidationPostProcessor.java | 234 +- .../beanvalidation/CustomValidatorBean.java | 172 +- .../LocalValidatorFactoryBean.java | 514 ++--- .../LocaleContextMessageInterpolator.java | 112 +- .../MessageSourceResourceBundleLocator.java | 110 +- .../SpringConstraintValidatorFactory.java | 106 +- .../SpringValidatorAdapter.java | 432 ++-- .../beanvalidation/package-info.java | 22 +- .../cache/NoOpCacheManagerTests.java | 122 +- .../concurrent/ConcurrentCacheTests.java | 78 +- .../ConcurrentMapCacheManagerTests.java | 126 +- .../cache/config/AbstractAnnotationTests.java | 1240 +++++------ .../AnnotatedClassCacheableService.java | 274 +-- .../AnnotationNamespaceDrivenTests.java | 88 +- .../cache/config/AnnotationTests.java | 64 +- .../config/CacheAdviceNamespaceTests.java | 84 +- .../cache/config/CacheableService.java | 138 +- .../cache/config/DefaultCacheableService.java | 286 +-- .../cache/config/SomeKeyGenerator.java | 46 +- .../cache/ehcache/EhCacheCacheTests.java | 122 +- .../vendor/AbstractNativeCacheTests.java | 174 +- .../context/annotation/BeanAge.java | 32 +- ...PathFactoryBeanDefinitionScannerTests.java | 190 +- .../FooServiceDependentConverter.java | 76 +- .../annotation/jsr330/SpringAtInjectTck.java | 126 +- .../context/annotation4/DependencyBean.java | 54 +- .../annotation4/FactoryMethodComponent.java | 154 +- .../context/annotation4/SimpleBean.java | 72 +- .../context/annotation5/MyRepository.java | 74 +- .../ApplicationContextExpressionTests.java | 864 ++++---- .../GenericApplicationContextTests.java | 72 +- .../context/support/ResourceConverter.java | 64 +- .../context/support/Spr7283Tests.java | 96 +- .../annotation/AnnotationTestBeanFactory.java | 90 +- .../FactoryCreatedAnnotationTestBean.java | 50 +- .../annotation/AsyncExecutionTests.java | 522 ++--- .../groovy/GroovyAspectIntegrationTests.java | 200 +- .../scripting/groovy/GroovyAspectTests.java | 202 +- .../scripting/groovy/GroovyServiceImpl.grv | 20 +- .../springframework/scripting/groovy/Log.java | 30 +- .../scripting/groovy/LogUserAdvice.java | 82 +- .../scripting/groovy/TestService.java | 10 +- .../scripting/groovy/TestServiceImpl.java | 16 +- .../BeanValidationPostProcessorTests.java | 312 +-- .../beanvalidation/ValidatorFactoryTests.java | 540 ++--- .../core/ExceptionDepthComparator.java | 192 +- .../ConvertingPropertyEditorAdapter.java | 144 +- .../io/AbstractFileResolvingResource.java | 402 ++-- .../core/io/ClassRelativeResourceLoader.java | 150 +- .../org/springframework/core/io/VfsUtils.java | 504 ++--- .../core/io/WritableResource.java | 104 +- .../core/io/support/VfsPatternUtils.java | 106 +- .../core/serializer/support/package-info.java | 18 +- .../task/support/ExecutorServiceAdapter.java | 174 +- .../core/type/MethodMetadata.java | 158 +- .../core/type/StandardMethodMetadata.java | 216 +- .../AnnotationAttributesReadingVisitor.java | 300 +-- .../util/CompositeIterator.java | 148 +- .../util/LinkedCaseInsensitiveMap.java | 298 +-- .../core/ExceptionDepthComparatorTests.java | 210 +- .../core/GenericTypeResolverTests.java | 194 +- .../core/convert/TypeDescriptorTests.java | 1602 +++++++------- .../type/CachingMetadataReaderLeakTest.java | 158 +- .../util/CompositeIteratorTests.java | 196 +- .../expression/AccessException.java | 88 +- .../expression/BeanResolver.java | 74 +- .../expression/ConstructorExecutor.java | 90 +- .../expression/ConstructorResolver.java | 88 +- .../ExpressionInvocationTargetException.java | 98 +- .../expression/MethodExecutor.java | 88 +- .../expression/MethodFilter.java | 90 +- .../expression/MethodResolver.java | 88 +- .../springframework/expression/Operation.java | 58 +- .../expression/PropertyAccessor.java | 162 +- .../expression/TypeConverter.java | 106 +- .../expression/TypedValue.java | 160 +- .../common/TemplateParserContext.java | 130 +- .../expression/spel/ExpressionState.java | 484 ++--- .../spel/InternalParseException.java | 76 +- .../spel/SpelEvaluationException.java | 184 +- .../expression/spel/SpelMessage.java | 312 +-- .../expression/spel/SpelNode.java | 190 +- .../expression/spel/SpelParseException.java | 214 +- .../spel/SpelParserConfiguration.java | 94 +- .../expression/spel/ast/AstUtils.java | 144 +- .../expression/spel/ast/FormatHelper.java | 168 +- .../expression/spel/ast/InlineList.java | 240 +-- .../expression/spel/ast/IntLiteral.java | 80 +- .../expression/spel/ast/TypeCode.java | 122 +- .../spel/generated/SpringExpressions.g | 536 ++--- .../InternalSpelExpressionParser.java | 1700 +++++++-------- .../spel/standard/SpelExpressionParser.java | 126 +- .../expression/spel/standard/Token.java | 172 +- .../expression/spel/standard/TokenKind.java | 114 +- .../expression/spel/standard/Tokenizer.java | 1014 ++++----- .../spel/support/BooleanTypedValue.java | 92 +- .../spel/support/ReflectionHelper.java | 1014 ++++----- .../ReflectiveConstructorExecutor.java | 148 +- .../ReflectiveConstructorResolver.java | 240 +-- .../support/ReflectiveMethodExecutor.java | 154 +- .../support/ReflectiveMethodResolver.java | 394 ++-- .../support/ReflectivePropertyAccessor.java | 1054 ++++----- .../support/StandardOperatorOverloader.java | 76 +- .../spel/support/StandardTypeConverter.java | 152 +- .../expression/spel/SpelUtilities.java | 116 +- .../spel/ast/FormatHelperTests.java | 88 +- .../PropertiesConversionSpelTests.java | 212 +- .../spel/standard/SpelParserTests.java | 740 +++---- .../spel/support/StandardComponentsTests.java | 158 +- .../spel/testresources/TestAddress.java | 42 +- .../spel/testresources/TestPerson.java | 36 +- .../test/util/SerializationTestUtils.java | 200 +- .../config/DatabasePopulatorConfigUtils.java | 164 +- ...nitializeDatabaseBeanDefinitionParser.java | 110 +- .../embedded/OutputStreamFactory.java | 84 +- .../init/DatabasePopulatorUtils.java | 122 +- .../OracleJdbc4NativeJdbcExtractor.java | 120 +- .../jms/support/converter/MessageType.java | 64 +- .../hibernate3/LocalRegionFactoryProxy.java | 246 +-- .../hibernate4/LocalSessionFactoryBean.java | 670 +++--- .../SmartPersistenceUnitInfo.java | 80 +- .../HibernateJpaSessionFactoryBean.java | 112 +- .../CglibProxyBridgeMethodTests.java | 146 +- .../oxm/castor/CastorMappingException.java | 78 +- .../main/resources/META-INF/spring.schemas | 6 +- .../mock/web/portlet/MockCacheControl.java | 140 +- .../mock/web/portlet/MockEvent.java | 174 +- .../ServletWrappingPortletContext.java | 290 +-- .../expression/ExpressionUsageTests.java | 166 +- .../interceptor/TransactionAspectUtils.java | 270 +-- .../jta/ManagedTransactionAdapter.java | 178 +- .../TransactionManagerConfiguration.java | 90 +- .../web/portlet/NoHandlerFoundException.java | 106 +- .../bind/annotation/ActionMapping.java | 126 +- .../portlet/bind/annotation/EventMapping.java | 104 +- .../bind/annotation/RenderMapping.java | 124 +- .../bind/annotation/ResourceMapping.java | 98 +- .../portlet/context/PortletContextScope.java | 222 +- .../PortletModeParameterLookupKey.java | 128 +- .../web/portlet/mvc/EventAwareController.java | 86 +- .../portlet/mvc/ResourceAwareController.java | 96 +- .../mock/web/portlet/MockCacheControl.java | 140 +- .../mock/web/portlet/MockEvent.java | 174 +- .../ServletWrappingPortletContext.java | 290 +-- .../PortletApplicationContextScopeTests.java | 254 +-- .../servlet/mvc/condition/package-info.java | 16 +- .../mvc/method/annotation/package-info.java | 20 +- .../web/servlet/mvc/method/package-info.java | 18 +- .../SpringTilesApplicationContextFactory.java | 224 +- .../web/DelegatingServletInputStream.java | 132 +- .../web/DelegatingServletOutputStream.java | 148 +- .../mock/web/HeaderValueHolder.java | 192 +- .../mock/web/MockBodyContent.java | 394 ++-- .../mock/web/MockFilterChain.java | 140 +- .../mock/web/MockHttpServletRequest.java | 1896 ++++++++--------- .../mock/web/MockHttpSession.java | 492 ++--- .../mock/web/MockJspWriter.java | 382 ++-- .../mock/web/MockMultipartFile.java | 268 +-- .../web/MockMultipartHttpServletRequest.java | 262 +-- .../mock/web/MockPageContext.java | 740 +++---- .../mock/web/MockRequestDispatcher.java | 182 +- .../mock/web/MockServletConfig.java | 206 +- .../mock/web/MockServletContext.java | 984 ++++----- .../util/SerializationTestUtils.java | 130 +- .../view/tiles2/TilesConfigurerTests.java | 104 +- .../springframework/http/MediaTypeEditor.java | 100 +- .../xml/XmlAwareFormHttpMessageConverter.java | 70 +- ...sfiedServletRequestParameterException.java | 176 +- .../web/bind/annotation/Mapping.java | 70 +- .../web/bind/annotation/ValueConstants.java | 76 +- .../web/context/ContextCleanupListener.java | 154 +- .../DestructionCallbackBindingListener.java | 108 +- .../context/support/ServletContextScope.java | 222 +- .../web/method/annotation/package-info.java | 16 +- .../web/method/support/package-info.java | 16 +- .../StandardMultipartHttpServletRequest.java | 350 +-- .../StandardServletMultipartResolver.java | 146 +- .../web/DelegatingServletInputStream.java | 132 +- .../web/DelegatingServletOutputStream.java | 142 +- .../mock/web/HeaderValueHolder.java | 192 +- .../mock/web/MockHttpServletRequest.java | 1896 ++++++++--------- .../mock/web/MockHttpSession.java | 492 ++--- .../mock/web/MockRequestDispatcher.java | 182 +- .../mock/web/MockServletContext.java | 1014 ++++----- .../WebApplicationContextScopeTests.java | 200 +- .../SpringBeanAutowiringSupportTests.java | 124 +- 293 files changed, 31091 insertions(+), 31091 deletions(-) diff --git a/build.versions b/build.versions index a4e1c28bdb..bdbac64d93 100644 --- a/build.versions +++ b/build.versions @@ -1,4 +1,4 @@ -# common dependency versions -aspectj.version=1.6.8.RELEASE -junit.version=4.9.0 -testng.version=5.12.1 +# common dependency versions +aspectj.version=1.6.8.RELEASE +junit.version=4.9.0 +testng.version=5.12.1 diff --git a/org.springframework.aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionInterceptor.java b/org.springframework.aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionInterceptor.java index e64de27c6c..6039ce304c 100644 --- a/org.springframework.aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionInterceptor.java +++ b/org.springframework.aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionInterceptor.java @@ -1,103 +1,103 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.aop.interceptor; - -import java.util.concurrent.Callable; -import java.util.concurrent.Executor; -import java.util.concurrent.Future; - -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; - -import org.springframework.core.Ordered; -import org.springframework.core.task.AsyncTaskExecutor; -import org.springframework.core.task.support.TaskExecutorAdapter; -import org.springframework.util.Assert; -import org.springframework.util.ReflectionUtils; - -/** - * AOP Alliance MethodInterceptor that processes method invocations - * asynchronously, using a given {@link org.springframework.core.task.AsyncTaskExecutor}. - * Typically used with the {@link org.springframework.context.task.Async} annotation. - * - *

In terms of target method signatures, any parameter types are supported. - * However, the return type is constrained to either void or - * java.util.concurrent.Future. In the latter case, the Future handle - * returned from the proxy will be an actual asynchronous Future that can be used - * to track the result of the asynchronous method execution. However, since the - * target method needs to implement the same signature, it will have to return - * a temporary Future handle that just passes the return value through - * (like Spring's {@link org.springframework.scheduling.annotation.AsyncResult} - * or EJB 3.1's javax.ejb.AsyncResult). - * - * @author Juergen Hoeller - * @since 3.0 - * @see org.springframework.scheduling.annotation.Async - * @see org.springframework.scheduling.annotation.AsyncAnnotationAdvisor - */ -public class AsyncExecutionInterceptor implements MethodInterceptor, Ordered { - - private final AsyncTaskExecutor asyncExecutor; - - - /** - * Create a new AsyncExecutionInterceptor. - * @param asyncExecutor the Spring AsyncTaskExecutor to delegate to - */ - public AsyncExecutionInterceptor(AsyncTaskExecutor asyncExecutor) { - Assert.notNull(asyncExecutor, "TaskExecutor must not be null"); - this.asyncExecutor = asyncExecutor; - } - - /** - * Create a new AsyncExecutionInterceptor. - * @param asyncExecutor the java.util.concurrent Executor - * to delegate to (typically a {@link java.util.concurrent.ExecutorService} - */ - public AsyncExecutionInterceptor(Executor asyncExecutor) { - this.asyncExecutor = new TaskExecutorAdapter(asyncExecutor); - } - - - public Object invoke(final MethodInvocation invocation) throws Throwable { - Future result = this.asyncExecutor.submit(new Callable() { - public Object call() throws Exception { - try { - Object result = invocation.proceed(); - if (result instanceof Future) { - return ((Future) result).get(); - } - } - catch (Throwable ex) { - ReflectionUtils.rethrowException(ex); - } - return null; - } - }); - if (Future.class.isAssignableFrom(invocation.getMethod().getReturnType())) { - return result; - } - else { - return null; - } - } - - public int getOrder() { - return Ordered.HIGHEST_PRECEDENCE; - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.interceptor; + +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; +import java.util.concurrent.Future; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; + +import org.springframework.core.Ordered; +import org.springframework.core.task.AsyncTaskExecutor; +import org.springframework.core.task.support.TaskExecutorAdapter; +import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; + +/** + * AOP Alliance MethodInterceptor that processes method invocations + * asynchronously, using a given {@link org.springframework.core.task.AsyncTaskExecutor}. + * Typically used with the {@link org.springframework.context.task.Async} annotation. + * + *

In terms of target method signatures, any parameter types are supported. + * However, the return type is constrained to either void or + * java.util.concurrent.Future. In the latter case, the Future handle + * returned from the proxy will be an actual asynchronous Future that can be used + * to track the result of the asynchronous method execution. However, since the + * target method needs to implement the same signature, it will have to return + * a temporary Future handle that just passes the return value through + * (like Spring's {@link org.springframework.scheduling.annotation.AsyncResult} + * or EJB 3.1's javax.ejb.AsyncResult). + * + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.scheduling.annotation.Async + * @see org.springframework.scheduling.annotation.AsyncAnnotationAdvisor + */ +public class AsyncExecutionInterceptor implements MethodInterceptor, Ordered { + + private final AsyncTaskExecutor asyncExecutor; + + + /** + * Create a new AsyncExecutionInterceptor. + * @param asyncExecutor the Spring AsyncTaskExecutor to delegate to + */ + public AsyncExecutionInterceptor(AsyncTaskExecutor asyncExecutor) { + Assert.notNull(asyncExecutor, "TaskExecutor must not be null"); + this.asyncExecutor = asyncExecutor; + } + + /** + * Create a new AsyncExecutionInterceptor. + * @param asyncExecutor the java.util.concurrent Executor + * to delegate to (typically a {@link java.util.concurrent.ExecutorService} + */ + public AsyncExecutionInterceptor(Executor asyncExecutor) { + this.asyncExecutor = new TaskExecutorAdapter(asyncExecutor); + } + + + public Object invoke(final MethodInvocation invocation) throws Throwable { + Future result = this.asyncExecutor.submit(new Callable() { + public Object call() throws Exception { + try { + Object result = invocation.proceed(); + if (result instanceof Future) { + return ((Future) result).get(); + } + } + catch (Throwable ex) { + ReflectionUtils.rethrowException(ex); + } + return null; + } + }); + if (Future.class.isAssignableFrom(invocation.getMethod().getReturnType())) { + return result; + } + else { + return null; + } + } + + public int getOrder() { + return Ordered.HIGHEST_PRECEDENCE; + } + +} diff --git a/org.springframework.aop/src/test/java/org/springframework/aop/aspectj/TrickyAspectJPointcutExpressionTests.java b/org.springframework.aop/src/test/java/org/springframework/aop/aspectj/TrickyAspectJPointcutExpressionTests.java index be1fb06e37..227c1553c3 100644 --- a/org.springframework.aop/src/test/java/org/springframework/aop/aspectj/TrickyAspectJPointcutExpressionTests.java +++ b/org.springframework.aop/src/test/java/org/springframework/aop/aspectj/TrickyAspectJPointcutExpressionTests.java @@ -1,174 +1,174 @@ -package org.springframework.aop.aspectj; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import java.lang.annotation.Documented; -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; -import java.lang.reflect.Method; - -import org.junit.Test; -import org.springframework.aop.Advisor; -import org.springframework.aop.MethodBeforeAdvice; -import org.springframework.aop.ThrowsAdvice; -import org.springframework.aop.framework.ProxyFactory; -import org.springframework.aop.support.DefaultPointcutAdvisor; -import org.springframework.core.OverridingClassLoader; - -/** - * @author Dave Syer - */ -public class TrickyAspectJPointcutExpressionTests { - - @Test - public void testManualProxyJavaWithUnconditionalPointcut() throws Exception { - TestService target = new TestServiceImpl(); - LogUserAdvice logAdvice = new LogUserAdvice(); - testAdvice(new DefaultPointcutAdvisor(logAdvice), logAdvice, target, "TestServiceImpl"); - } - - @Test - public void testManualProxyJavaWithStaticPointcut() throws Exception { - TestService target = new TestServiceImpl(); - LogUserAdvice logAdvice = new LogUserAdvice(); - AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); - pointcut.setExpression(String.format("execution(* %s.TestService.*(..))", getClass().getName())); - testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl"); - } - - @Test - public void testManualProxyJavaWithDynamicPointcut() throws Exception { - TestService target = new TestServiceImpl(); - LogUserAdvice logAdvice = new LogUserAdvice(); - AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); - pointcut.setExpression(String.format("@within(%s.Log)", getClass().getName())); - testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl"); - } - - @Test - public void testManualProxyJavaWithDynamicPointcutAndProxyTargetClass() throws Exception { - TestService target = new TestServiceImpl(); - LogUserAdvice logAdvice = new LogUserAdvice(); - AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); - pointcut.setExpression(String.format("@within(%s.Log)", getClass().getName())); - testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl", true); - } - - @Test - public void testManualProxyJavaWithStaticPointcutAndTwoClassLoaders() throws Exception { - - LogUserAdvice logAdvice = new LogUserAdvice(); - AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); - pointcut.setExpression(String.format("execution(* %s.TestService.*(..))", getClass().getName())); - - // Test with default class loader first... - testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, new TestServiceImpl(), "TestServiceImpl"); - - // Then try again with a different class loader on the target... - SimpleThrowawayClassLoader loader = new SimpleThrowawayClassLoader(new TestServiceImpl().getClass().getClassLoader()); - // Make sure the interface is loaded from the parent class loader - loader.excludeClass(TestService.class.getName()); - loader.excludeClass(TestException.class.getName()); - TestService other = (TestService) loader.loadClass(TestServiceImpl.class.getName()).newInstance(); - testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, other, "TestServiceImpl"); - - } - - private void testAdvice(Advisor advisor, LogUserAdvice logAdvice, TestService target, String message) - throws Exception { - testAdvice(advisor, logAdvice, target, message, false); - } - - private void testAdvice(Advisor advisor, LogUserAdvice logAdvice, TestService target, String message, - boolean proxyTargetClass) throws Exception { - - logAdvice.reset(); - - ProxyFactory factory = new ProxyFactory(target); - factory.setProxyTargetClass(proxyTargetClass); - factory.addAdvisor(advisor); - TestService bean = (TestService) factory.getProxy(); - - assertEquals(0, logAdvice.getCountThrows()); - try { - bean.sayHello(); - fail("Expected exception"); - } catch (TestException e) { - assertEquals(message, e.getMessage()); - } - assertEquals(1, logAdvice.getCountThrows()); - } - - public static class SimpleThrowawayClassLoader extends OverridingClassLoader { - - /** - * Create a new SimpleThrowawayClassLoader for the given class loader. - * @param parent the ClassLoader to build a throwaway ClassLoader for - */ - public SimpleThrowawayClassLoader(ClassLoader parent) { - super(parent); - } - - } - - public static class TestException extends RuntimeException { - - public TestException(String string) { - super(string); - } - - } - - @Target({ ElementType.METHOD, ElementType.TYPE }) - @Retention(RetentionPolicy.RUNTIME) - @Documented - @Inherited - public static @interface Log { - } - - public static interface TestService { - public String sayHello(); - } - - @Log - public static class TestServiceImpl implements TestService{ - public String sayHello() { - throw new TestException("TestServiceImpl"); - } - } - - public class LogUserAdvice implements MethodBeforeAdvice, ThrowsAdvice { - - private int countBefore = 0; - - private int countThrows = 0; - - public void before(Method method, Object[] objects, Object o) throws Throwable { - countBefore++; - } - - public void afterThrowing(Exception e) throws Throwable { - countThrows++; - throw e; - } - - public int getCountBefore() { - return countBefore; - } - - public int getCountThrows() { - return countThrows; - } - - public void reset() { - countThrows = 0; - countBefore = 0; - } - - } - -} +package org.springframework.aop.aspectj; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.lang.annotation.Documented; +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; +import java.lang.reflect.Method; + +import org.junit.Test; +import org.springframework.aop.Advisor; +import org.springframework.aop.MethodBeforeAdvice; +import org.springframework.aop.ThrowsAdvice; +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.support.DefaultPointcutAdvisor; +import org.springframework.core.OverridingClassLoader; + +/** + * @author Dave Syer + */ +public class TrickyAspectJPointcutExpressionTests { + + @Test + public void testManualProxyJavaWithUnconditionalPointcut() throws Exception { + TestService target = new TestServiceImpl(); + LogUserAdvice logAdvice = new LogUserAdvice(); + testAdvice(new DefaultPointcutAdvisor(logAdvice), logAdvice, target, "TestServiceImpl"); + } + + @Test + public void testManualProxyJavaWithStaticPointcut() throws Exception { + TestService target = new TestServiceImpl(); + LogUserAdvice logAdvice = new LogUserAdvice(); + AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); + pointcut.setExpression(String.format("execution(* %s.TestService.*(..))", getClass().getName())); + testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl"); + } + + @Test + public void testManualProxyJavaWithDynamicPointcut() throws Exception { + TestService target = new TestServiceImpl(); + LogUserAdvice logAdvice = new LogUserAdvice(); + AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); + pointcut.setExpression(String.format("@within(%s.Log)", getClass().getName())); + testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl"); + } + + @Test + public void testManualProxyJavaWithDynamicPointcutAndProxyTargetClass() throws Exception { + TestService target = new TestServiceImpl(); + LogUserAdvice logAdvice = new LogUserAdvice(); + AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); + pointcut.setExpression(String.format("@within(%s.Log)", getClass().getName())); + testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl", true); + } + + @Test + public void testManualProxyJavaWithStaticPointcutAndTwoClassLoaders() throws Exception { + + LogUserAdvice logAdvice = new LogUserAdvice(); + AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); + pointcut.setExpression(String.format("execution(* %s.TestService.*(..))", getClass().getName())); + + // Test with default class loader first... + testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, new TestServiceImpl(), "TestServiceImpl"); + + // Then try again with a different class loader on the target... + SimpleThrowawayClassLoader loader = new SimpleThrowawayClassLoader(new TestServiceImpl().getClass().getClassLoader()); + // Make sure the interface is loaded from the parent class loader + loader.excludeClass(TestService.class.getName()); + loader.excludeClass(TestException.class.getName()); + TestService other = (TestService) loader.loadClass(TestServiceImpl.class.getName()).newInstance(); + testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, other, "TestServiceImpl"); + + } + + private void testAdvice(Advisor advisor, LogUserAdvice logAdvice, TestService target, String message) + throws Exception { + testAdvice(advisor, logAdvice, target, message, false); + } + + private void testAdvice(Advisor advisor, LogUserAdvice logAdvice, TestService target, String message, + boolean proxyTargetClass) throws Exception { + + logAdvice.reset(); + + ProxyFactory factory = new ProxyFactory(target); + factory.setProxyTargetClass(proxyTargetClass); + factory.addAdvisor(advisor); + TestService bean = (TestService) factory.getProxy(); + + assertEquals(0, logAdvice.getCountThrows()); + try { + bean.sayHello(); + fail("Expected exception"); + } catch (TestException e) { + assertEquals(message, e.getMessage()); + } + assertEquals(1, logAdvice.getCountThrows()); + } + + public static class SimpleThrowawayClassLoader extends OverridingClassLoader { + + /** + * Create a new SimpleThrowawayClassLoader for the given class loader. + * @param parent the ClassLoader to build a throwaway ClassLoader for + */ + public SimpleThrowawayClassLoader(ClassLoader parent) { + super(parent); + } + + } + + public static class TestException extends RuntimeException { + + public TestException(String string) { + super(string); + } + + } + + @Target({ ElementType.METHOD, ElementType.TYPE }) + @Retention(RetentionPolicy.RUNTIME) + @Documented + @Inherited + public static @interface Log { + } + + public static interface TestService { + public String sayHello(); + } + + @Log + public static class TestServiceImpl implements TestService{ + public String sayHello() { + throw new TestException("TestServiceImpl"); + } + } + + public class LogUserAdvice implements MethodBeforeAdvice, ThrowsAdvice { + + private int countBefore = 0; + + private int countThrows = 0; + + public void before(Method method, Object[] objects, Object o) throws Throwable { + countBefore++; + } + + public void afterThrowing(Exception e) throws Throwable { + countThrows++; + throw e; + } + + public int getCountBefore() { + return countBefore; + } + + public int getCountThrows() { + return countThrows; + } + + public void reset() { + countThrows = 0; + countBefore = 0; + } + + } + +} diff --git a/org.springframework.aop/src/test/java/org/springframework/aop/support/ClassUtilsTests.java b/org.springframework.aop/src/test/java/org/springframework/aop/support/ClassUtilsTests.java index fe016f6f2b..1c250e966d 100644 --- a/org.springframework.aop/src/test/java/org/springframework/aop/support/ClassUtilsTests.java +++ b/org.springframework.aop/src/test/java/org/springframework/aop/support/ClassUtilsTests.java @@ -1,41 +1,41 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.aop.support; - -import junit.framework.TestCase; - -import org.springframework.aop.framework.ProxyFactory; -import test.beans.TestBean; -import org.springframework.util.ClassUtils; - -/** - * @author Colin Sampaleanu - * @author Juergen Hoeller - * @author Rob Harrop - * @author Rick Evans - */ -public class ClassUtilsTests extends TestCase { - - public void testGetShortNameForCglibClass() { - TestBean tb = new TestBean(); - ProxyFactory pf = new ProxyFactory(); - pf.setTarget(tb); - pf.setProxyTargetClass(true); - TestBean proxy = (TestBean) pf.getProxy(); - String className = ClassUtils.getShortName(proxy.getClass()); - assertEquals("Class name did not match", "TestBean", className); - } -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.aop.support; + +import junit.framework.TestCase; + +import org.springframework.aop.framework.ProxyFactory; +import test.beans.TestBean; +import org.springframework.util.ClassUtils; + +/** + * @author Colin Sampaleanu + * @author Juergen Hoeller + * @author Rob Harrop + * @author Rick Evans + */ +public class ClassUtilsTests extends TestCase { + + public void testGetShortNameForCglibClass() { + TestBean tb = new TestBean(); + ProxyFactory pf = new ProxyFactory(); + pf.setTarget(tb); + pf.setProxyTargetClass(true); + TestBean proxy = (TestBean) pf.getProxy(); + String className = ClassUtils.getShortName(proxy.getClass()); + assertEquals("Class name did not match", "TestBean", className); + } +} diff --git a/org.springframework.aspects/src/main/java/org/springframework/beans/factory/aspectj/GenericInterfaceDrivenDependencyInjectionAspect.aj b/org.springframework.aspects/src/main/java/org/springframework/beans/factory/aspectj/GenericInterfaceDrivenDependencyInjectionAspect.aj index 78f927ffad..82795313e7 100644 --- a/org.springframework.aspects/src/main/java/org/springframework/beans/factory/aspectj/GenericInterfaceDrivenDependencyInjectionAspect.aj +++ b/org.springframework.aspects/src/main/java/org/springframework/beans/factory/aspectj/GenericInterfaceDrivenDependencyInjectionAspect.aj @@ -1,54 +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.beans.factory.aspectj; - -/** - * Generic-based dependency injection aspect. - *

- * This aspect allows users to implement efficient, type-safe dependency injection without - * the use of the @Configurable annotation. - * - * The subaspect of this aspect doesn't need to include any AOP constructs. - * For example, here is a subaspect that configures the PricingStrategyClient objects. - *

- * aspect PricingStrategyDependencyInjectionAspect 
- *        extends GenericInterfaceDrivenDependencyInjectionAspect {
- *     private PricingStrategy pricingStrategy;
- *     
- *     public void configure(PricingStrategyClient bean) { 
- *         bean.setPricingStrategy(pricingStrategy); 
- *     }
- *     
- *     public void setPricingStrategy(PricingStrategy pricingStrategy) { 
- *         this.pricingStrategy = pricingStrategy; 
- *     } 
- * }
- * 
- * @author Ramnivas Laddad - * @since 3.0.0 - */ -public abstract aspect GenericInterfaceDrivenDependencyInjectionAspect extends AbstractInterfaceDrivenDependencyInjectionAspect { - declare parents: I implements ConfigurableObject; - - public pointcut inConfigurableBean() : within(I+); - - public final void configureBean(Object bean) { - configure((I)bean); - } - - // Unfortunately, erasure used with generics won't allow to use the same named method - protected abstract void configure(I bean); -} +/* + * 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.aspectj; + +/** + * Generic-based dependency injection aspect. + *

+ * This aspect allows users to implement efficient, type-safe dependency injection without + * the use of the @Configurable annotation. + * + * The subaspect of this aspect doesn't need to include any AOP constructs. + * For example, here is a subaspect that configures the PricingStrategyClient objects. + *

+ * aspect PricingStrategyDependencyInjectionAspect 
+ *        extends GenericInterfaceDrivenDependencyInjectionAspect {
+ *     private PricingStrategy pricingStrategy;
+ *     
+ *     public void configure(PricingStrategyClient bean) { 
+ *         bean.setPricingStrategy(pricingStrategy); 
+ *     }
+ *     
+ *     public void setPricingStrategy(PricingStrategy pricingStrategy) { 
+ *         this.pricingStrategy = pricingStrategy; 
+ *     } 
+ * }
+ * 
+ * @author Ramnivas Laddad + * @since 3.0.0 + */ +public abstract aspect GenericInterfaceDrivenDependencyInjectionAspect extends AbstractInterfaceDrivenDependencyInjectionAspect { + declare parents: I implements ConfigurableObject; + + public pointcut inConfigurableBean() : within(I+); + + public final void configureBean(Object bean) { + configure((I)bean); + } + + // Unfortunately, erasure used with generics won't allow to use the same named method + protected abstract void configure(I bean); +} diff --git a/org.springframework.aspects/src/main/java/org/springframework/cache/aspectj/AbstractCacheAspect.aj b/org.springframework.aspects/src/main/java/org/springframework/cache/aspectj/AbstractCacheAspect.aj index fd58ca3fa1..ccd9472516 100644 --- a/org.springframework.aspects/src/main/java/org/springframework/cache/aspectj/AbstractCacheAspect.aj +++ b/org.springframework.aspects/src/main/java/org/springframework/cache/aspectj/AbstractCacheAspect.aj @@ -1,73 +1,73 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cache.aspectj; - -import java.lang.reflect.Method; - -import org.aspectj.lang.annotation.SuppressAjWarnings; -import org.aspectj.lang.reflect.MethodSignature; -import org.springframework.cache.interceptor.CacheAspectSupport; -import org.springframework.cache.interceptor.CacheOperationSource; - -/** - * Abstract superaspect for AspectJ cache aspects. Concrete subaspects will implement the - * {@link #cacheMethodExecution} pointcut using a strategy such as Java 5 annotations. - * - *

Suitable for use inside or outside the Spring IoC container. Set the - * {@link #setCacheManager cacheManager} property appropriately, allowing use of any cache - * implementation supported by Spring. - * - *

NB: If a method implements an interface that is itself cache annotated, the - * relevant Spring cache definition will not be resolved. - * - * @author Costin Leau - * @since 3.1 - */ -public abstract aspect AbstractCacheAspect extends CacheAspectSupport { - - protected AbstractCacheAspect() { - } - - /** - * Construct object using the given caching metadata retrieval strategy. - * @param cos {@link CacheOperationSource} implementation, retrieving Spring cache - * metadata for each joinpoint. - */ - protected AbstractCacheAspect(CacheOperationSource... cos) { - setCacheOperationSources(cos); - } - - @SuppressAjWarnings("adviceDidNotMatch") - Object around(final Object cachedObject) : cacheMethodExecution(cachedObject) { - MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature(); - Method method = methodSignature.getMethod(); - - Invoker aspectJInvoker = new Invoker() { - public Object invoke() { - return proceed(cachedObject); - } - }; - - return execute(aspectJInvoker, thisJoinPoint.getTarget(), method, thisJoinPoint.getArgs()); - } - - /** - * Concrete subaspects must implement this pointcut, to identify cached methods. - */ - protected abstract pointcut cacheMethodExecution(Object cachedObject); - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache.aspectj; + +import java.lang.reflect.Method; + +import org.aspectj.lang.annotation.SuppressAjWarnings; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.cache.interceptor.CacheAspectSupport; +import org.springframework.cache.interceptor.CacheOperationSource; + +/** + * Abstract superaspect for AspectJ cache aspects. Concrete subaspects will implement the + * {@link #cacheMethodExecution} pointcut using a strategy such as Java 5 annotations. + * + *

Suitable for use inside or outside the Spring IoC container. Set the + * {@link #setCacheManager cacheManager} property appropriately, allowing use of any cache + * implementation supported by Spring. + * + *

NB: If a method implements an interface that is itself cache annotated, the + * relevant Spring cache definition will not be resolved. + * + * @author Costin Leau + * @since 3.1 + */ +public abstract aspect AbstractCacheAspect extends CacheAspectSupport { + + protected AbstractCacheAspect() { + } + + /** + * Construct object using the given caching metadata retrieval strategy. + * @param cos {@link CacheOperationSource} implementation, retrieving Spring cache + * metadata for each joinpoint. + */ + protected AbstractCacheAspect(CacheOperationSource... cos) { + setCacheOperationSources(cos); + } + + @SuppressAjWarnings("adviceDidNotMatch") + Object around(final Object cachedObject) : cacheMethodExecution(cachedObject) { + MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature(); + Method method = methodSignature.getMethod(); + + Invoker aspectJInvoker = new Invoker() { + public Object invoke() { + return proceed(cachedObject); + } + }; + + return execute(aspectJInvoker, thisJoinPoint.getTarget(), method, thisJoinPoint.getArgs()); + } + + /** + * Concrete subaspects must implement this pointcut, to identify cached methods. + */ + protected abstract pointcut cacheMethodExecution(Object cachedObject); + +} diff --git a/org.springframework.aspects/src/main/java/org/springframework/cache/aspectj/AnnotationCacheAspect.aj b/org.springframework.aspects/src/main/java/org/springframework/cache/aspectj/AnnotationCacheAspect.aj index a0581c5b63..0687b3c54c 100644 --- a/org.springframework.aspects/src/main/java/org/springframework/cache/aspectj/AnnotationCacheAspect.aj +++ b/org.springframework.aspects/src/main/java/org/springframework/cache/aspectj/AnnotationCacheAspect.aj @@ -1,116 +1,116 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cache.aspectj; - -import org.springframework.cache.annotation.AnnotationCacheOperationSource; -import org.springframework.cache.annotation.CacheEvict; -import org.springframework.cache.annotation.CachePut; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.cache.annotation.Caching; - -/** - * Concrete AspectJ cache aspect using Spring's @{@link Cacheable} annotation. - * - *

When using this aspect, you must annotate the implementation class (and/or - * methods within that class), not the interface (if any) that the class - * implements. AspectJ follows Java's rule that annotations on interfaces are not - * inherited. - * - *

A {@code @Cacheable} annotation on a class specifies the default caching semantics - * for the execution of any public operation in the class. - * - *

A {@code @Cacheable} annotation on a method within the class overrides the default - * caching semantics given by the class annotation (if present). Any method may be - * annotated (regardless of visibility). Annotating non-public methods directly is the - * only way to get caching demarcation for the execution of such operations. - * - * @author Costin Leau - * @since 3.1 - */ -public aspect AnnotationCacheAspect extends AbstractCacheAspect { - - public AnnotationCacheAspect() { - super(new AnnotationCacheOperationSource(false)); - } - - /** - * Matches the execution of any public method in a type with the @{@link Cacheable} - * annotation, or any subtype of a type with the {@code @Cacheable} annotation. - */ - private pointcut executionOfAnyPublicMethodInAtCacheableType() : - execution(public * ((@Cacheable *)+).*(..)) && within(@Cacheable *); - - /** - * Matches the execution of any public method in a type with the @{@link CacheEvict} - * annotation, or any subtype of a type with the {@code CacheEvict} annotation. - */ - private pointcut executionOfAnyPublicMethodInAtCacheEvictType() : - execution(public * ((@CacheEvict *)+).*(..)) && within(@CacheEvict *); - - /** - * Matches the execution of any public method in a type with the @{@link CachePut} - * annotation, or any subtype of a type with the {@code CachePut} annotation. - */ - private pointcut executionOfAnyPublicMethodInAtCachePutType() : - execution(public * ((@CachePut *)+).*(..)) && within(@CachePut *); - - /** - * Matches the execution of any public method in a type with the @{@link Caching} - * annotation, or any subtype of a type with the {@code Caching} annotation. - */ - private pointcut executionOfAnyPublicMethodInAtCachingType() : - execution(public * ((@Caching *)+).*(..)) && within(@Caching *); - - /** - * Matches the execution of any method with the @{@link Cacheable} annotation. - */ - private pointcut executionOfCacheableMethod() : - execution(@Cacheable * *(..)); - - /** - * Matches the execution of any method with the @{@link CacheEvict} annotation. - */ - private pointcut executionOfCacheEvictMethod() : - execution(@CacheEvict * *(..)); - - /** - * Matches the execution of any method with the @{@link CachePut} annotation. - */ - private pointcut executionOfCachePutMethod() : - execution(@CachePut * *(..)); - - /** - * Matches the execution of any method with the @{@link Caching} annotation. - */ - private pointcut executionOfCachingMethod() : - execution(@Caching * *(..)); - - /** - * Definition of pointcut from super aspect - matched join points will have Spring - * cache management applied. - */ - protected pointcut cacheMethodExecution(Object cachedObject) : - (executionOfAnyPublicMethodInAtCacheableType() - || executionOfAnyPublicMethodInAtCacheEvictType() - || executionOfAnyPublicMethodInAtCachePutType() - || executionOfAnyPublicMethodInAtCachingType() - || executionOfCacheableMethod() - || executionOfCacheEvictMethod() - || executionOfCachePutMethod() - || executionOfCachingMethod()) - && this(cachedObject); +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache.aspectj; + +import org.springframework.cache.annotation.AnnotationCacheOperationSource; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; + +/** + * Concrete AspectJ cache aspect using Spring's @{@link Cacheable} annotation. + * + *

When using this aspect, you must annotate the implementation class (and/or + * methods within that class), not the interface (if any) that the class + * implements. AspectJ follows Java's rule that annotations on interfaces are not + * inherited. + * + *

A {@code @Cacheable} annotation on a class specifies the default caching semantics + * for the execution of any public operation in the class. + * + *

A {@code @Cacheable} annotation on a method within the class overrides the default + * caching semantics given by the class annotation (if present). Any method may be + * annotated (regardless of visibility). Annotating non-public methods directly is the + * only way to get caching demarcation for the execution of such operations. + * + * @author Costin Leau + * @since 3.1 + */ +public aspect AnnotationCacheAspect extends AbstractCacheAspect { + + public AnnotationCacheAspect() { + super(new AnnotationCacheOperationSource(false)); + } + + /** + * Matches the execution of any public method in a type with the @{@link Cacheable} + * annotation, or any subtype of a type with the {@code @Cacheable} annotation. + */ + private pointcut executionOfAnyPublicMethodInAtCacheableType() : + execution(public * ((@Cacheable *)+).*(..)) && within(@Cacheable *); + + /** + * Matches the execution of any public method in a type with the @{@link CacheEvict} + * annotation, or any subtype of a type with the {@code CacheEvict} annotation. + */ + private pointcut executionOfAnyPublicMethodInAtCacheEvictType() : + execution(public * ((@CacheEvict *)+).*(..)) && within(@CacheEvict *); + + /** + * Matches the execution of any public method in a type with the @{@link CachePut} + * annotation, or any subtype of a type with the {@code CachePut} annotation. + */ + private pointcut executionOfAnyPublicMethodInAtCachePutType() : + execution(public * ((@CachePut *)+).*(..)) && within(@CachePut *); + + /** + * Matches the execution of any public method in a type with the @{@link Caching} + * annotation, or any subtype of a type with the {@code Caching} annotation. + */ + private pointcut executionOfAnyPublicMethodInAtCachingType() : + execution(public * ((@Caching *)+).*(..)) && within(@Caching *); + + /** + * Matches the execution of any method with the @{@link Cacheable} annotation. + */ + private pointcut executionOfCacheableMethod() : + execution(@Cacheable * *(..)); + + /** + * Matches the execution of any method with the @{@link CacheEvict} annotation. + */ + private pointcut executionOfCacheEvictMethod() : + execution(@CacheEvict * *(..)); + + /** + * Matches the execution of any method with the @{@link CachePut} annotation. + */ + private pointcut executionOfCachePutMethod() : + execution(@CachePut * *(..)); + + /** + * Matches the execution of any method with the @{@link Caching} annotation. + */ + private pointcut executionOfCachingMethod() : + execution(@Caching * *(..)); + + /** + * Definition of pointcut from super aspect - matched join points will have Spring + * cache management applied. + */ + protected pointcut cacheMethodExecution(Object cachedObject) : + (executionOfAnyPublicMethodInAtCacheableType() + || executionOfAnyPublicMethodInAtCacheEvictType() + || executionOfAnyPublicMethodInAtCachePutType() + || executionOfAnyPublicMethodInAtCachingType() + || executionOfCacheableMethod() + || executionOfCacheEvictMethod() + || executionOfCachePutMethod() + || executionOfCachingMethod()) + && this(cachedObject); } \ No newline at end of file diff --git a/org.springframework.aspects/src/main/java/org/springframework/mock/staticmock/AbstractMethodMockingControl.aj b/org.springframework.aspects/src/main/java/org/springframework/mock/staticmock/AbstractMethodMockingControl.aj index a2c4b8acf6..6ca2bd728c 100644 --- a/org.springframework.aspects/src/main/java/org/springframework/mock/staticmock/AbstractMethodMockingControl.aj +++ b/org.springframework.aspects/src/main/java/org/springframework/mock/staticmock/AbstractMethodMockingControl.aj @@ -1,197 +1,197 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.staticmock; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; - -/** - * Abstract aspect to enable mocking of methods picked out by a pointcut. - * Sub-aspects must define the mockStaticsTestMethod() pointcut to - * indicate call stacks when mocking should be triggered, and the - * methodToMock() pointcut to pick out a method invocations to mock. - * - * @author Rod Johnson - * @author Ramnivas Laddad - */ -public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMethod()) { - - protected abstract pointcut mockStaticsTestMethod(); - - protected abstract pointcut methodToMock(); - - private boolean recording = true; - - static enum CallResponse { nothing, return_, throw_ }; - - // Represents a list of expected calls to static entity methods - // Public to allow inserted code to access: is this normal?? - public class Expectations { - - // Represents an expected call to a static entity method - private class Call { - private final String signature; - private final Object[] args; - - private Object responseObject; // return value or throwable - private CallResponse responseType = CallResponse.nothing; - - public Call(String name, Object[] args) { - this.signature = name; - this.args = args; - } - - public boolean hasResponseSpecified() { - return responseType != CallResponse.nothing; - } - - public void setReturnVal(Object retVal) { - this.responseObject = retVal; - responseType = CallResponse.return_; - } - - public void setThrow(Throwable throwable) { - this.responseObject = throwable; - responseType = CallResponse.throw_; - } - - public Object returnValue(String lastSig, Object[] args) { - checkSignature(lastSig, args); - return responseObject; - } - - public Object throwException(String lastSig, Object[] args) { - checkSignature(lastSig, args); - throw (RuntimeException)responseObject; - } - - private void checkSignature(String lastSig, Object[] args) { - if (!signature.equals(lastSig)) { - throw new IllegalArgumentException("Signature doesn't match"); - } - if (!Arrays.equals(this.args, args)) { - throw new IllegalArgumentException("Arguments don't match"); - } - } - } - - private List calls = new LinkedList(); - - // Calls already verified - private int verified; - - public void verify() { - if (verified != calls.size()) { - throw new IllegalStateException("Expected " + calls.size() - + " calls, received " + verified); - } - } - - /** - * Validate the call and provide the expected return value - * @param lastSig - * @param args - * @return - */ - public Object respond(String lastSig, Object[] args) { - Call call = nextCall(); - CallResponse responseType = call.responseType; - if (responseType == CallResponse.return_) { - return call.returnValue(lastSig, args); - } else if(responseType == CallResponse.throw_) { - return (RuntimeException)call.throwException(lastSig, args); - } else if(responseType == CallResponse.nothing) { - // do nothing - } - throw new IllegalStateException("Behavior of " + call + " not specified"); - } - - private Call nextCall() { - if (verified > calls.size() - 1) { - throw new IllegalStateException("Expected " + calls.size() - + " calls, received " + verified); - } - return calls.get(verified++); - } - - public void expectCall(String lastSig, Object lastArgs[]) { - Call call = new Call(lastSig, lastArgs); - calls.add(call); - } - - public boolean hasCalls() { - return !calls.isEmpty(); - } - - public void expectReturn(Object retVal) { - Call call = calls.get(calls.size() - 1); - if (call.hasResponseSpecified()) { - throw new IllegalStateException("No static method invoked before setting return value"); - } - call.setReturnVal(retVal); - } - - public void expectThrow(Throwable throwable) { - Call call = calls.get(calls.size() - 1); - if (call.hasResponseSpecified()) { - throw new IllegalStateException("No static method invoked before setting throwable"); - } - call.setThrow(throwable); - } - } - - private Expectations expectations = new Expectations(); - - after() returning : mockStaticsTestMethod() { - if (recording && (expectations.hasCalls())) { - throw new IllegalStateException( - "Calls recorded, yet playback state never reached: Create expectations then call " - + this.getClass().getSimpleName() + ".playback()"); - } - expectations.verify(); - } - - Object around() : methodToMock() && cflowbelow(mockStaticsTestMethod()) { - if (recording) { - expectations.expectCall(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs()); - // Return value doesn't matter - return null; - } else { - return expectations.respond(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs()); - } - } - - public void expectReturnInternal(Object retVal) { - if (!recording) { - throw new IllegalStateException("Not recording: Cannot set return value"); - } - expectations.expectReturn(retVal); - } - - public void expectThrowInternal(Throwable throwable) { - if (!recording) { - throw new IllegalStateException("Not recording: Cannot set throwable value"); - } - expectations.expectThrow(throwable); - } - - public void playbackInternal() { - recording = false; - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.staticmock; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * Abstract aspect to enable mocking of methods picked out by a pointcut. + * Sub-aspects must define the mockStaticsTestMethod() pointcut to + * indicate call stacks when mocking should be triggered, and the + * methodToMock() pointcut to pick out a method invocations to mock. + * + * @author Rod Johnson + * @author Ramnivas Laddad + */ +public abstract aspect AbstractMethodMockingControl percflow(mockStaticsTestMethod()) { + + protected abstract pointcut mockStaticsTestMethod(); + + protected abstract pointcut methodToMock(); + + private boolean recording = true; + + static enum CallResponse { nothing, return_, throw_ }; + + // Represents a list of expected calls to static entity methods + // Public to allow inserted code to access: is this normal?? + public class Expectations { + + // Represents an expected call to a static entity method + private class Call { + private final String signature; + private final Object[] args; + + private Object responseObject; // return value or throwable + private CallResponse responseType = CallResponse.nothing; + + public Call(String name, Object[] args) { + this.signature = name; + this.args = args; + } + + public boolean hasResponseSpecified() { + return responseType != CallResponse.nothing; + } + + public void setReturnVal(Object retVal) { + this.responseObject = retVal; + responseType = CallResponse.return_; + } + + public void setThrow(Throwable throwable) { + this.responseObject = throwable; + responseType = CallResponse.throw_; + } + + public Object returnValue(String lastSig, Object[] args) { + checkSignature(lastSig, args); + return responseObject; + } + + public Object throwException(String lastSig, Object[] args) { + checkSignature(lastSig, args); + throw (RuntimeException)responseObject; + } + + private void checkSignature(String lastSig, Object[] args) { + if (!signature.equals(lastSig)) { + throw new IllegalArgumentException("Signature doesn't match"); + } + if (!Arrays.equals(this.args, args)) { + throw new IllegalArgumentException("Arguments don't match"); + } + } + } + + private List calls = new LinkedList(); + + // Calls already verified + private int verified; + + public void verify() { + if (verified != calls.size()) { + throw new IllegalStateException("Expected " + calls.size() + + " calls, received " + verified); + } + } + + /** + * Validate the call and provide the expected return value + * @param lastSig + * @param args + * @return + */ + public Object respond(String lastSig, Object[] args) { + Call call = nextCall(); + CallResponse responseType = call.responseType; + if (responseType == CallResponse.return_) { + return call.returnValue(lastSig, args); + } else if(responseType == CallResponse.throw_) { + return (RuntimeException)call.throwException(lastSig, args); + } else if(responseType == CallResponse.nothing) { + // do nothing + } + throw new IllegalStateException("Behavior of " + call + " not specified"); + } + + private Call nextCall() { + if (verified > calls.size() - 1) { + throw new IllegalStateException("Expected " + calls.size() + + " calls, received " + verified); + } + return calls.get(verified++); + } + + public void expectCall(String lastSig, Object lastArgs[]) { + Call call = new Call(lastSig, lastArgs); + calls.add(call); + } + + public boolean hasCalls() { + return !calls.isEmpty(); + } + + public void expectReturn(Object retVal) { + Call call = calls.get(calls.size() - 1); + if (call.hasResponseSpecified()) { + throw new IllegalStateException("No static method invoked before setting return value"); + } + call.setReturnVal(retVal); + } + + public void expectThrow(Throwable throwable) { + Call call = calls.get(calls.size() - 1); + if (call.hasResponseSpecified()) { + throw new IllegalStateException("No static method invoked before setting throwable"); + } + call.setThrow(throwable); + } + } + + private Expectations expectations = new Expectations(); + + after() returning : mockStaticsTestMethod() { + if (recording && (expectations.hasCalls())) { + throw new IllegalStateException( + "Calls recorded, yet playback state never reached: Create expectations then call " + + this.getClass().getSimpleName() + ".playback()"); + } + expectations.verify(); + } + + Object around() : methodToMock() && cflowbelow(mockStaticsTestMethod()) { + if (recording) { + expectations.expectCall(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs()); + // Return value doesn't matter + return null; + } else { + return expectations.respond(thisJoinPointStaticPart.toLongString(), thisJoinPoint.getArgs()); + } + } + + public void expectReturnInternal(Object retVal) { + if (!recording) { + throw new IllegalStateException("Not recording: Cannot set return value"); + } + expectations.expectReturn(retVal); + } + + public void expectThrowInternal(Throwable throwable) { + if (!recording) { + throw new IllegalStateException("Not recording: Cannot set throwable value"); + } + expectations.expectThrow(throwable); + } + + public void playbackInternal() { + recording = false; + } + +} diff --git a/org.springframework.aspects/src/main/java/org/springframework/mock/staticmock/AnnotationDrivenStaticEntityMockingControl.aj b/org.springframework.aspects/src/main/java/org/springframework/mock/staticmock/AnnotationDrivenStaticEntityMockingControl.aj index 296a197316..1c35a47e97 100644 --- a/org.springframework.aspects/src/main/java/org/springframework/mock/staticmock/AnnotationDrivenStaticEntityMockingControl.aj +++ b/org.springframework.aspects/src/main/java/org/springframework/mock/staticmock/AnnotationDrivenStaticEntityMockingControl.aj @@ -1,68 +1,68 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.staticmock; - -/** - * Annotation-based aspect to use in test build to enable mocking static methods - * on JPA-annotated @Entity classes, as used by Roo for finders. - * - *

Mocking will occur in the call stack of any method in a class (typically a test class) - * that is annotated with the @MockStaticEntityMethods annotation. - * - *

Also provides static methods to simplify the programming model for - * entering playback mode and setting expected return values. - * - *

Usage: - *

    - *
  1. Annotate a test class with @MockStaticEntityMethods. - *
  2. In each test method, AnnotationDrivenStaticEntityMockingControl will begin in recording mode. - * Invoke static methods on Entity classes, with each recording-mode invocation - * being followed by an invocation to the static expectReturn() or expectThrow() - * method on AnnotationDrivenStaticEntityMockingControl. - *
  3. Invoke the static AnnotationDrivenStaticEntityMockingControl() method. - *
  4. Call the code you wish to test that uses the static methods. Verification will - * occur automatically. - *
- * - * @author Rod Johnson - * @author Ramnivas Laddad - * @see MockStaticEntityMethods - */ -public aspect AnnotationDrivenStaticEntityMockingControl extends AbstractMethodMockingControl { - - /** - * Stop recording mock calls and enter playback state - */ - public static void playback() { - AnnotationDrivenStaticEntityMockingControl.aspectOf().playbackInternal(); - } - - public static void expectReturn(Object retVal) { - AnnotationDrivenStaticEntityMockingControl.aspectOf().expectReturnInternal(retVal); - } - - public static void expectThrow(Throwable throwable) { - AnnotationDrivenStaticEntityMockingControl.aspectOf().expectThrowInternal(throwable); - } - - // Only matches directly annotated @Test methods, to allow methods in - // @MockStatics classes to invoke each other without resetting the mocking environment - protected pointcut mockStaticsTestMethod() : execution(public * (@MockStaticEntityMethods *).*(..)); - - protected pointcut methodToMock() : execution(public static * (@javax.persistence.Entity *).*(..)); - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.staticmock; + +/** + * Annotation-based aspect to use in test build to enable mocking static methods + * on JPA-annotated @Entity classes, as used by Roo for finders. + * + *

Mocking will occur in the call stack of any method in a class (typically a test class) + * that is annotated with the @MockStaticEntityMethods annotation. + * + *

Also provides static methods to simplify the programming model for + * entering playback mode and setting expected return values. + * + *

Usage: + *

    + *
  1. Annotate a test class with @MockStaticEntityMethods. + *
  2. In each test method, AnnotationDrivenStaticEntityMockingControl will begin in recording mode. + * Invoke static methods on Entity classes, with each recording-mode invocation + * being followed by an invocation to the static expectReturn() or expectThrow() + * method on AnnotationDrivenStaticEntityMockingControl. + *
  3. Invoke the static AnnotationDrivenStaticEntityMockingControl() method. + *
  4. Call the code you wish to test that uses the static methods. Verification will + * occur automatically. + *
+ * + * @author Rod Johnson + * @author Ramnivas Laddad + * @see MockStaticEntityMethods + */ +public aspect AnnotationDrivenStaticEntityMockingControl extends AbstractMethodMockingControl { + + /** + * Stop recording mock calls and enter playback state + */ + public static void playback() { + AnnotationDrivenStaticEntityMockingControl.aspectOf().playbackInternal(); + } + + public static void expectReturn(Object retVal) { + AnnotationDrivenStaticEntityMockingControl.aspectOf().expectReturnInternal(retVal); + } + + public static void expectThrow(Throwable throwable) { + AnnotationDrivenStaticEntityMockingControl.aspectOf().expectThrowInternal(throwable); + } + + // Only matches directly annotated @Test methods, to allow methods in + // @MockStatics classes to invoke each other without resetting the mocking environment + protected pointcut mockStaticsTestMethod() : execution(public * (@MockStaticEntityMethods *).*(..)); + + protected pointcut methodToMock() : execution(public static * (@javax.persistence.Entity *).*(..)); + +} diff --git a/org.springframework.aspects/src/main/java/org/springframework/mock/staticmock/MockStaticEntityMethods.java b/org.springframework.aspects/src/main/java/org/springframework/mock/staticmock/MockStaticEntityMethods.java index 438ad69c7c..1216c5f1e6 100644 --- a/org.springframework.aspects/src/main/java/org/springframework/mock/staticmock/MockStaticEntityMethods.java +++ b/org.springframework.aspects/src/main/java/org/springframework/mock/staticmock/MockStaticEntityMethods.java @@ -1,34 +1,34 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.mock.staticmock; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation to indicate a test class for whose @Test methods - * static methods on Entity classes should be mocked. - * - * @author Rod Johnson - * @see AbstractMethodMockingControl - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface MockStaticEntityMethods { - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.mock.staticmock; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to indicate a test class for whose @Test methods + * static methods on Entity classes should be mocked. + * + * @author Rod Johnson + * @see AbstractMethodMockingControl + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface MockStaticEntityMethods { + +} diff --git a/org.springframework.aspects/src/main/java/org/springframework/scheduling/aspectj/AbstractAsyncExecutionAspect.aj b/org.springframework.aspects/src/main/java/org/springframework/scheduling/aspectj/AbstractAsyncExecutionAspect.aj index af070a6996..c540227114 100644 --- a/org.springframework.aspects/src/main/java/org/springframework/scheduling/aspectj/AbstractAsyncExecutionAspect.aj +++ b/org.springframework.aspects/src/main/java/org/springframework/scheduling/aspectj/AbstractAsyncExecutionAspect.aj @@ -1,75 +1,75 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.scheduling.aspectj; - -import java.util.concurrent.Callable; -import java.util.concurrent.Executor; -import java.util.concurrent.Future; - -import org.aspectj.lang.reflect.MethodSignature; -import org.springframework.core.task.AsyncTaskExecutor; -import org.springframework.core.task.SimpleAsyncTaskExecutor; -import org.springframework.core.task.support.TaskExecutorAdapter; - -/** - * Abstract aspect that routes selected methods asynchronously. - * - *

This aspect needs to be injected with an implementation of - * {@link Executor} to activate it for a specific thread pool. - * Otherwise it will simply delegate all calls synchronously. - * - * @author Ramnivas Laddad - * @author Juergen Hoeller - * @since 3.0.5 - */ -public abstract aspect AbstractAsyncExecutionAspect { - - private AsyncTaskExecutor asyncExecutor; - - public void setExecutor(Executor executor) { - if (executor instanceof AsyncTaskExecutor) { - this.asyncExecutor = (AsyncTaskExecutor) executor; - } - else { - this.asyncExecutor = new TaskExecutorAdapter(executor); - } - } - - Object around() : asyncMethod() { - if (this.asyncExecutor == null) { - return proceed(); - } - Callable callable = new Callable() { - public Object call() throws Exception { - Object result = proceed(); - if (result instanceof Future) { - return ((Future) result).get(); - } - return null; - }}; - Future result = this.asyncExecutor.submit(callable); - if (Future.class.isAssignableFrom(((MethodSignature) thisJoinPointStaticPart.getSignature()).getReturnType())) { - return result; - } - else { - return null; - } - } - - public abstract pointcut asyncMethod(); - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling.aspectj; + +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; +import java.util.concurrent.Future; + +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.core.task.AsyncTaskExecutor; +import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.core.task.support.TaskExecutorAdapter; + +/** + * Abstract aspect that routes selected methods asynchronously. + * + *

This aspect needs to be injected with an implementation of + * {@link Executor} to activate it for a specific thread pool. + * Otherwise it will simply delegate all calls synchronously. + * + * @author Ramnivas Laddad + * @author Juergen Hoeller + * @since 3.0.5 + */ +public abstract aspect AbstractAsyncExecutionAspect { + + private AsyncTaskExecutor asyncExecutor; + + public void setExecutor(Executor executor) { + if (executor instanceof AsyncTaskExecutor) { + this.asyncExecutor = (AsyncTaskExecutor) executor; + } + else { + this.asyncExecutor = new TaskExecutorAdapter(executor); + } + } + + Object around() : asyncMethod() { + if (this.asyncExecutor == null) { + return proceed(); + } + Callable callable = new Callable() { + public Object call() throws Exception { + Object result = proceed(); + if (result instanceof Future) { + return ((Future) result).get(); + } + return null; + }}; + Future result = this.asyncExecutor.submit(callable); + if (Future.class.isAssignableFrom(((MethodSignature) thisJoinPointStaticPart.getSignature()).getReturnType())) { + return result; + } + else { + return null; + } + } + + public abstract pointcut asyncMethod(); + +} diff --git a/org.springframework.aspects/src/main/java/org/springframework/scheduling/aspectj/AnnotationAsyncExecutionAspect.aj b/org.springframework.aspects/src/main/java/org/springframework/scheduling/aspectj/AnnotationAsyncExecutionAspect.aj index ee37fd25e8..328e742670 100644 --- a/org.springframework.aspects/src/main/java/org/springframework/scheduling/aspectj/AnnotationAsyncExecutionAspect.aj +++ b/org.springframework.aspects/src/main/java/org/springframework/scheduling/aspectj/AnnotationAsyncExecutionAspect.aj @@ -1,54 +1,54 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.scheduling.aspectj; - -import java.util.concurrent.Future; -import org.springframework.scheduling.annotation.Async; - -/** - * Aspect to route methods based on the {@link Async} annotation. - * - *

This aspect routes methods marked with the {@link Async} annotation - * as well as methods in classes marked with the same. Any method expected - * to be routed asynchronously must return either void, {@link Future}, - * or a subtype of {@link Future}. This aspect, therefore, will produce - * a compile-time error for methods that violate this constraint on the return type. - * If, however, a class marked with @Async contains a method that - * violates this constraint, it produces only a warning. - * - * @author Ramnivas Laddad - * @since 3.0.5 - */ -public aspect AnnotationAsyncExecutionAspect extends AbstractAsyncExecutionAspect { - - private pointcut asyncMarkedMethod() - : execution(@Async (void || Future+) *(..)); - - private pointcut asyncTypeMarkedMethod() - : execution((void || Future+) (@Async *).*(..)); - - public pointcut asyncMethod() : asyncMarkedMethod() || asyncTypeMarkedMethod(); - - declare error: - execution(@Async !(void||Future) *(..)): - "Only methods that return void or Future may have an @Async annotation"; - - declare warning: - execution(!(void||Future) (@Async *).*(..)): - "Methods in a class marked with @Async that do not return void or Future will be routed synchronously"; - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling.aspectj; + +import java.util.concurrent.Future; +import org.springframework.scheduling.annotation.Async; + +/** + * Aspect to route methods based on the {@link Async} annotation. + * + *

This aspect routes methods marked with the {@link Async} annotation + * as well as methods in classes marked with the same. Any method expected + * to be routed asynchronously must return either void, {@link Future}, + * or a subtype of {@link Future}. This aspect, therefore, will produce + * a compile-time error for methods that violate this constraint on the return type. + * If, however, a class marked with @Async contains a method that + * violates this constraint, it produces only a warning. + * + * @author Ramnivas Laddad + * @since 3.0.5 + */ +public aspect AnnotationAsyncExecutionAspect extends AbstractAsyncExecutionAspect { + + private pointcut asyncMarkedMethod() + : execution(@Async (void || Future+) *(..)); + + private pointcut asyncTypeMarkedMethod() + : execution((void || Future+) (@Async *).*(..)); + + public pointcut asyncMethod() : asyncMarkedMethod() || asyncTypeMarkedMethod(); + + declare error: + execution(@Async !(void||Future) *(..)): + "Only methods that return void or Future may have an @Async annotation"; + + declare warning: + execution(!(void||Future) (@Async *).*(..)): + "Methods in a class marked with @Async that do not return void or Future will be routed synchronously"; + +} diff --git a/org.springframework.aspects/src/main/java/org/springframework/transaction/aspectj/AbstractTransactionAspect.aj b/org.springframework.aspects/src/main/java/org/springframework/transaction/aspectj/AbstractTransactionAspect.aj index 985ac62fb4..c1b23c1bcb 100644 --- a/org.springframework.aspects/src/main/java/org/springframework/transaction/aspectj/AbstractTransactionAspect.aj +++ b/org.springframework.aspects/src/main/java/org/springframework/transaction/aspectj/AbstractTransactionAspect.aj @@ -1,93 +1,93 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.transaction.aspectj; - -import java.lang.reflect.Method; - -import org.aspectj.lang.annotation.SuppressAjWarnings; -import org.aspectj.lang.reflect.MethodSignature; -import org.springframework.transaction.interceptor.TransactionAspectSupport; -import org.springframework.transaction.interceptor.TransactionAttributeSource; - -/** - * Abstract superaspect for AspectJ transaction aspects. Concrete - * subaspects will implement the transactionalMethodExecution() - * pointcut using a strategy such as Java 5 annotations. - * - *

Suitable for use inside or outside the Spring IoC container. - * Set the "transactionManager" property appropriately, allowing - * use of any transaction implementation supported by Spring. - * - *

NB: If a method implements an interface that is itself - * transactionally annotated, the relevant Spring transaction attribute - * will not be resolved. This behavior will vary from that of Spring AOP - * if proxying an interface (but not when proxying a class). We recommend that - * transaction annotations should be added to classes, rather than business - * interfaces, as they are an implementation detail rather than a contract - * specification validation. - * - * @author Rod Johnson - * @author Ramnivas Laddad - * @since 2.0 - */ -public abstract aspect AbstractTransactionAspect extends TransactionAspectSupport { - - /** - * Construct object using the given transaction metadata retrieval strategy. - * @param tas TransactionAttributeSource implementation, retrieving Spring - * transaction metadata for each joinpoint. Write the subclass to pass in null - * if it's intended to be configured by Setter Injection. - */ - protected AbstractTransactionAspect(TransactionAttributeSource tas) { - setTransactionAttributeSource(tas); - } - - @SuppressAjWarnings("adviceDidNotMatch") - before(Object txObject) : transactionalMethodExecution(txObject) { - MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature(); - Method method = methodSignature.getMethod(); - TransactionInfo txInfo = createTransactionIfNecessary(method, txObject.getClass()); - } - - @SuppressAjWarnings("adviceDidNotMatch") - after(Object txObject) throwing(Throwable t) : transactionalMethodExecution(txObject) { - try { - completeTransactionAfterThrowing(TransactionAspectSupport.currentTransactionInfo(), t); - } - catch (Throwable t2) { - logger.error("Failed to close transaction after throwing in a transactional method", t2); - } - } - - @SuppressAjWarnings("adviceDidNotMatch") - after(Object txObject) returning() : transactionalMethodExecution(txObject) { - commitTransactionAfterReturning(TransactionAspectSupport.currentTransactionInfo()); - } - - @SuppressAjWarnings("adviceDidNotMatch") - after(Object txObject) : transactionalMethodExecution(txObject) { - cleanupTransactionInfo(TransactionAspectSupport.currentTransactionInfo()); - } - - /** - * Concrete subaspects must implement this pointcut, to identify - * transactional methods. For each selected joinpoint, TransactionMetadata - * will be retrieved using Spring's TransactionAttributeSource interface. - */ - protected abstract pointcut transactionalMethodExecution(Object txObject); - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.aspectj; + +import java.lang.reflect.Method; + +import org.aspectj.lang.annotation.SuppressAjWarnings; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.transaction.interceptor.TransactionAspectSupport; +import org.springframework.transaction.interceptor.TransactionAttributeSource; + +/** + * Abstract superaspect for AspectJ transaction aspects. Concrete + * subaspects will implement the transactionalMethodExecution() + * pointcut using a strategy such as Java 5 annotations. + * + *

Suitable for use inside or outside the Spring IoC container. + * Set the "transactionManager" property appropriately, allowing + * use of any transaction implementation supported by Spring. + * + *

NB: If a method implements an interface that is itself + * transactionally annotated, the relevant Spring transaction attribute + * will not be resolved. This behavior will vary from that of Spring AOP + * if proxying an interface (but not when proxying a class). We recommend that + * transaction annotations should be added to classes, rather than business + * interfaces, as they are an implementation detail rather than a contract + * specification validation. + * + * @author Rod Johnson + * @author Ramnivas Laddad + * @since 2.0 + */ +public abstract aspect AbstractTransactionAspect extends TransactionAspectSupport { + + /** + * Construct object using the given transaction metadata retrieval strategy. + * @param tas TransactionAttributeSource implementation, retrieving Spring + * transaction metadata for each joinpoint. Write the subclass to pass in null + * if it's intended to be configured by Setter Injection. + */ + protected AbstractTransactionAspect(TransactionAttributeSource tas) { + setTransactionAttributeSource(tas); + } + + @SuppressAjWarnings("adviceDidNotMatch") + before(Object txObject) : transactionalMethodExecution(txObject) { + MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature(); + Method method = methodSignature.getMethod(); + TransactionInfo txInfo = createTransactionIfNecessary(method, txObject.getClass()); + } + + @SuppressAjWarnings("adviceDidNotMatch") + after(Object txObject) throwing(Throwable t) : transactionalMethodExecution(txObject) { + try { + completeTransactionAfterThrowing(TransactionAspectSupport.currentTransactionInfo(), t); + } + catch (Throwable t2) { + logger.error("Failed to close transaction after throwing in a transactional method", t2); + } + } + + @SuppressAjWarnings("adviceDidNotMatch") + after(Object txObject) returning() : transactionalMethodExecution(txObject) { + commitTransactionAfterReturning(TransactionAspectSupport.currentTransactionInfo()); + } + + @SuppressAjWarnings("adviceDidNotMatch") + after(Object txObject) : transactionalMethodExecution(txObject) { + cleanupTransactionInfo(TransactionAspectSupport.currentTransactionInfo()); + } + + /** + * Concrete subaspects must implement this pointcut, to identify + * transactional methods. For each selected joinpoint, TransactionMetadata + * will be retrieved using Spring's TransactionAttributeSource interface. + */ + protected abstract pointcut transactionalMethodExecution(Object txObject); + +} diff --git a/org.springframework.aspects/src/main/java/org/springframework/transaction/aspectj/AnnotationTransactionAspect.aj b/org.springframework.aspects/src/main/java/org/springframework/transaction/aspectj/AnnotationTransactionAspect.aj index 825b7a489c..f4b3109034 100644 --- a/org.springframework.aspects/src/main/java/org/springframework/transaction/aspectj/AnnotationTransactionAspect.aj +++ b/org.springframework.aspects/src/main/java/org/springframework/transaction/aspectj/AnnotationTransactionAspect.aj @@ -1,75 +1,75 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.transaction.aspectj; - -import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource; -import org.springframework.transaction.annotation.Transactional; - -/** - * Concrete AspectJ transaction aspect using Spring's @Transactional annotation. - * - *

When using this aspect, you must annotate the implementation class - * (and/or methods within that class), not the interface (if any) that - * the class implements. AspectJ follows Java's rule that annotations on - * interfaces are not inherited. - * - *

An @Transactional annotation on a class specifies the default transaction - * semantics for the execution of any public operation in the class. - * - *

An @Transactional annotation on a method within the class overrides the - * default transaction semantics given by the class annotation (if present). - * Any method may be annotated (regardless of visibility). - * Annotating non-public methods directly is the only way - * to get transaction demarcation for the execution of such operations. - * - * @author Rod Johnson - * @author Ramnivas Laddad - * @author Adrian Colyer - * @since 2.0 - * @see org.springframework.transaction.annotation.Transactional - */ -public aspect AnnotationTransactionAspect extends AbstractTransactionAspect { - - public AnnotationTransactionAspect() { - super(new AnnotationTransactionAttributeSource(false)); - } - - /** - * Matches the execution of any public method in a type with the - * Transactional annotation, or any subtype of a type with the - * Transactional annotation. - */ - private pointcut executionOfAnyPublicMethodInAtTransactionalType() : - execution(public * ((@Transactional *)+).*(..)) && within(@Transactional *); - - /** - * Matches the execution of any method with the - * Transactional annotation. - */ - private pointcut executionOfTransactionalMethod() : - execution(@Transactional * *(..)); - - /** - * Definition of pointcut from super aspect - matched join points - * will have Spring transaction management applied. - */ - protected pointcut transactionalMethodExecution(Object txObject) : - (executionOfAnyPublicMethodInAtTransactionalType() - || executionOfTransactionalMethod() ) - && this(txObject); - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.aspectj; + +import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource; +import org.springframework.transaction.annotation.Transactional; + +/** + * Concrete AspectJ transaction aspect using Spring's @Transactional annotation. + * + *

When using this aspect, you must annotate the implementation class + * (and/or methods within that class), not the interface (if any) that + * the class implements. AspectJ follows Java's rule that annotations on + * interfaces are not inherited. + * + *

An @Transactional annotation on a class specifies the default transaction + * semantics for the execution of any public operation in the class. + * + *

An @Transactional annotation on a method within the class overrides the + * default transaction semantics given by the class annotation (if present). + * Any method may be annotated (regardless of visibility). + * Annotating non-public methods directly is the only way + * to get transaction demarcation for the execution of such operations. + * + * @author Rod Johnson + * @author Ramnivas Laddad + * @author Adrian Colyer + * @since 2.0 + * @see org.springframework.transaction.annotation.Transactional + */ +public aspect AnnotationTransactionAspect extends AbstractTransactionAspect { + + public AnnotationTransactionAspect() { + super(new AnnotationTransactionAttributeSource(false)); + } + + /** + * Matches the execution of any public method in a type with the + * Transactional annotation, or any subtype of a type with the + * Transactional annotation. + */ + private pointcut executionOfAnyPublicMethodInAtTransactionalType() : + execution(public * ((@Transactional *)+).*(..)) && within(@Transactional *); + + /** + * Matches the execution of any method with the + * Transactional annotation. + */ + private pointcut executionOfTransactionalMethod() : + execution(@Transactional * *(..)); + + /** + * Definition of pointcut from super aspect - matched join points + * will have Spring transaction management applied. + */ + protected pointcut transactionalMethodExecution(Object txObject) : + (executionOfAnyPublicMethodInAtTransactionalType() + || executionOfTransactionalMethod() ) + && this(txObject); + +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/aop/aspectj/autoproxy/AutoProxyWithCodeStyleAspectsTests.java b/org.springframework.aspects/src/test/java/org/springframework/aop/aspectj/autoproxy/AutoProxyWithCodeStyleAspectsTests.java index d593e1d118..2dd6faa417 100644 --- a/org.springframework.aspects/src/test/java/org/springframework/aop/aspectj/autoproxy/AutoProxyWithCodeStyleAspectsTests.java +++ b/org.springframework.aspects/src/test/java/org/springframework/aop/aspectj/autoproxy/AutoProxyWithCodeStyleAspectsTests.java @@ -1,32 +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; - -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import junit.framework.TestCase; - -/** - * @author Adrian Colyer - */ -public class AutoProxyWithCodeStyleAspectsTests extends TestCase { - - public void testNoAutoproxyingOfAjcCompiledAspects() { - new ClassPathXmlApplicationContext("org/springframework/aop/aspectj/autoproxy/ajcAutoproxyTests.xml"); - } - -} +/* + * 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.context.support.ClassPathXmlApplicationContext; + +import junit.framework.TestCase; + +/** + * @author Adrian Colyer + */ +public class AutoProxyWithCodeStyleAspectsTests extends TestCase { + + public void testNoAutoproxyingOfAjcCompiledAspects() { + new ClassPathXmlApplicationContext("org/springframework/aop/aspectj/autoproxy/ajcAutoproxyTests.xml"); + } + +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/aop/aspectj/autoproxy/CodeStyleAspect.aj b/org.springframework.aspects/src/test/java/org/springframework/aop/aspectj/autoproxy/CodeStyleAspect.aj index f1038fe9bd..374bc00909 100644 --- a/org.springframework.aspects/src/test/java/org/springframework/aop/aspectj/autoproxy/CodeStyleAspect.aj +++ b/org.springframework.aspects/src/test/java/org/springframework/aop/aspectj/autoproxy/CodeStyleAspect.aj @@ -1,36 +1,36 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.aop.aspectj.autoproxy; - -/** - * @author Adrian Colyer - */ -public aspect CodeStyleAspect { - - private String foo; - - pointcut somePC() : call(* someMethod()); - - before() : somePC() { - System.out.println("match"); - } - - public void setFoo(String foo) { - this.foo = foo; - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.aop.aspectj.autoproxy; + +/** + * @author Adrian Colyer + */ +public aspect CodeStyleAspect { + + private String foo; + + pointcut somePC() : call(* someMethod()); + + before() : somePC() { + System.out.println("match"); + } + + public void setFoo(String foo) { + this.foo = foo; + } + +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/beans/factory/aspectj/SpringConfiguredWithAutoProxyingTests.java b/org.springframework.aspects/src/test/java/org/springframework/beans/factory/aspectj/SpringConfiguredWithAutoProxyingTests.java index aa8aef07a1..16e2522d93 100644 --- a/org.springframework.aspects/src/test/java/org/springframework/beans/factory/aspectj/SpringConfiguredWithAutoProxyingTests.java +++ b/org.springframework.aspects/src/test/java/org/springframework/beans/factory/aspectj/SpringConfiguredWithAutoProxyingTests.java @@ -1,33 +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.beans.factory.aspectj; - -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import junit.framework.TestCase; - -public class SpringConfiguredWithAutoProxyingTests extends TestCase { - - @Override - protected void setUp() throws Exception { - new ClassPathXmlApplicationContext("org/springframework/beans/factory/aspectj/springConfigured.xml"); - } - - public void testSpringConfiguredAndAutoProxyUsedTogether() { - ; // set up is sufficient to trigger failure if this is going to fail... - } +/* + * 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.aspectj; + +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import junit.framework.TestCase; + +public class SpringConfiguredWithAutoProxyingTests extends TestCase { + + @Override + protected void setUp() throws Exception { + new ClassPathXmlApplicationContext("org/springframework/beans/factory/aspectj/springConfigured.xml"); + } + + public void testSpringConfiguredAndAutoProxyUsedTogether() { + ; // set up is sufficient to trigger failure if this is going to fail... + } } \ No newline at end of file diff --git a/org.springframework.aspects/src/test/java/org/springframework/cache/aspectj/AbstractAnnotationTest.java b/org.springframework.aspects/src/test/java/org/springframework/cache/aspectj/AbstractAnnotationTest.java index e30127e516..b3f9d4937b 100644 --- a/org.springframework.aspects/src/test/java/org/springframework/cache/aspectj/AbstractAnnotationTest.java +++ b/org.springframework.aspects/src/test/java/org/springframework/cache/aspectj/AbstractAnnotationTest.java @@ -1,596 +1,596 @@ -/* - * Copyright 2010-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cache.aspectj; - -import static org.junit.Assert.*; - -import java.util.Collection; -import java.util.UUID; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.cache.Cache; -import org.springframework.cache.CacheManager; -import org.springframework.cache.config.AnnotatedClassCacheableService; -import org.springframework.cache.config.CacheableService; -import org.springframework.context.ApplicationContext; - -/** - * Abstract annotation test (containing several reusable methods). - * - * @author Costin Leau - * @author Chris Beams - */ -public abstract class AbstractAnnotationTest { - - protected ApplicationContext ctx; - - protected CacheableService cs; - - protected CacheableService ccs; - - protected CacheManager cm; - - /** @return a refreshed application context */ - protected abstract ApplicationContext getApplicationContext(); - - @Before - public void setup() { - ctx = getApplicationContext(); - cs = ctx.getBean("service", CacheableService.class); - ccs = ctx.getBean("classService", CacheableService.class); - cm = ctx.getBean(CacheManager.class); - Collection cn = cm.getCacheNames(); - assertTrue(cn.contains("default")); - } - - public void testCacheable(CacheableService service) throws Exception { - Object o1 = new Object(); - - Object r1 = service.cache(o1); - Object r2 = service.cache(o1); - Object r3 = service.cache(o1); - - assertSame(r1, r2); - assertSame(r1, r3); - } - - public void testEvict(CacheableService service) throws Exception { - Object o1 = new Object(); - - Object r1 = service.cache(o1); - Object r2 = service.cache(o1); - - assertSame(r1, r2); - service.invalidate(o1); - Object r3 = service.cache(o1); - Object r4 = service.cache(o1); - assertNotSame(r1, r3); - assertSame(r3, r4); - } - - public void testEvictEarly(CacheableService service) throws Exception { - Object o1 = new Object(); - - Object r1 = service.cache(o1); - Object r2 = service.cache(o1); - - assertSame(r1, r2); - try { - service.evictEarly(o1); - } catch (RuntimeException ex) { - // expected - } - - Object r3 = service.cache(o1); - Object r4 = service.cache(o1); - assertNotSame(r1, r3); - assertSame(r3, r4); - } - - public void testEvictException(CacheableService service) throws Exception { - Object o1 = new Object(); - - Object r1 = service.cache(o1); - Object r2 = service.cache(o1); - - assertSame(r1, r2); - try { - service.evictWithException(o1); - } catch (RuntimeException ex) { - // expected - } - // exception occurred, eviction skipped, data should still be in the cache - Object r3 = service.cache(o1); - assertSame(r1, r3); - } - - public void testEvictWKey(CacheableService service) throws Exception { - Object o1 = new Object(); - - Object r1 = service.cache(o1); - Object r2 = service.cache(o1); - - assertSame(r1, r2); - service.evict(o1, null); - Object r3 = service.cache(o1); - Object r4 = service.cache(o1); - assertNotSame(r1, r3); - assertSame(r3, r4); - } - - public void testEvictWKeyEarly(CacheableService service) throws Exception { - Object o1 = new Object(); - - Object r1 = service.cache(o1); - Object r2 = service.cache(o1); - - assertSame(r1, r2); - - try { - service.invalidateEarly(o1, null); - } catch (Exception ex) { - // expected - } - Object r3 = service.cache(o1); - Object r4 = service.cache(o1); - assertNotSame(r1, r3); - assertSame(r3, r4); - } - - public void testEvictAll(CacheableService service) throws Exception { - Object o1 = new Object(); - - Object r1 = service.cache(o1); - Object r2 = service.cache(o1); - - Object o2 = new Object(); - Object r10 = service.cache(o2); - - assertSame(r1, r2); - assertNotSame(r1, r10); - service.evictAll(new Object()); - Cache cache = cm.getCache("default"); - assertNull(cache.get(o1)); - assertNull(cache.get(o2)); - - Object r3 = service.cache(o1); - Object r4 = service.cache(o1); - assertNotSame(r1, r3); - assertSame(r3, r4); - } - - public void testConditionalExpression(CacheableService service) throws Exception { - Object r1 = service.conditional(4); - Object r2 = service.conditional(4); - - assertNotSame(r1, r2); - - Object r3 = service.conditional(3); - Object r4 = service.conditional(3); - - assertSame(r3, r4); - } - - public void testKeyExpression(CacheableService service) throws Exception { - Object r1 = service.key(5, 1); - Object r2 = service.key(5, 2); - - assertSame(r1, r2); - - Object r3 = service.key(1, 5); - Object r4 = service.key(2, 5); - - assertNotSame(r3, r4); - } - - public void testNullValue(CacheableService service) throws Exception { - Object key = new Object(); - assertNull(service.nullValue(key)); - int nr = service.nullInvocations().intValue(); - assertNull(service.nullValue(key)); - assertEquals(nr, service.nullInvocations().intValue()); - assertNull(service.nullValue(new Object())); - assertEquals(nr + 1, service.nullInvocations().intValue()); - } - - public void testMethodName(CacheableService service, String keyName) throws Exception { - Object key = new Object(); - Object r1 = service.name(key); - assertSame(r1, service.name(key)); - Cache cache = cm.getCache("default"); - // assert the method name is used - assertNotNull(cache.get(keyName)); - } - - public void testCheckedThrowable(CacheableService service) throws Exception { - String arg = UUID.randomUUID().toString(); - try { - service.throwChecked(arg); - fail("Excepted exception"); - } catch (Exception ex) { - assertEquals(arg, ex.getMessage()); - } - } - - public void testUncheckedThrowable(CacheableService service) throws Exception { - try { - service.throwUnchecked(Long.valueOf(1)); - fail("Excepted exception"); - } catch (RuntimeException ex) { - assertTrue("Excepted different exception type and got " + ex.getClass(), - ex instanceof UnsupportedOperationException); - // expected - } - } - - public void testNullArg(CacheableService service) { - Object r1 = service.cache(null); - assertSame(r1, service.cache(null)); - } - - public void testCacheUpdate(CacheableService service) { - Object o = new Object(); - Cache cache = cm.getCache("default"); - assertNull(cache.get(o)); - Object r1 = service.update(o); - assertSame(r1, cache.get(o).get()); - - o = new Object(); - assertNull(cache.get(o)); - Object r2 = service.update(o); - assertSame(r2, cache.get(o).get()); - } - - public void testConditionalCacheUpdate(CacheableService service) { - Integer one = Integer.valueOf(1); - Integer three = Integer.valueOf(3); - - Cache cache = cm.getCache("default"); - assertEquals(one, Integer.valueOf(service.conditionalUpdate(one).toString())); - assertNull(cache.get(one)); - - assertEquals(three, Integer.valueOf(service.conditionalUpdate(three).toString())); - assertEquals(three, Integer.valueOf(cache.get(three).get().toString())); - } - - public void testMultiCache(CacheableService service) { - Object o1 = new Object(); - Object o2 = new Object(); - - Cache primary = cm.getCache("primary"); - Cache secondary = cm.getCache("secondary"); - - assertNull(primary.get(o1)); - assertNull(secondary.get(o1)); - Object r1 = service.multiCache(o1); - assertSame(r1, primary.get(o1).get()); - assertSame(r1, secondary.get(o1).get()); - - Object r2 = service.multiCache(o1); - Object r3 = service.multiCache(o1); - - assertSame(r1, r2); - assertSame(r1, r3); - - assertNull(primary.get(o2)); - assertNull(secondary.get(o2)); - Object r4 = service.multiCache(o2); - assertSame(r4, primary.get(o2).get()); - assertSame(r4, secondary.get(o2).get()); - } - - public void testMultiEvict(CacheableService service) { - Object o1 = new Object(); - - Object r1 = service.multiCache(o1); - Object r2 = service.multiCache(o1); - - Cache primary = cm.getCache("primary"); - Cache secondary = cm.getCache("secondary"); - - assertSame(r1, r2); - assertSame(r1, primary.get(o1).get()); - assertSame(r1, secondary.get(o1).get()); - - service.multiEvict(o1); - assertNull(primary.get(o1)); - assertNull(secondary.get(o1)); - - Object r3 = service.multiCache(o1); - Object r4 = service.multiCache(o1); - assertNotSame(r1, r3); - assertSame(r3, r4); - - assertSame(r3, primary.get(o1).get()); - assertSame(r4, secondary.get(o1).get()); - } - - public void testMultiPut(CacheableService service) { - Object o = Integer.valueOf(1); - - Cache primary = cm.getCache("primary"); - Cache secondary = cm.getCache("secondary"); - - assertNull(primary.get(o)); - assertNull(secondary.get(o)); - Object r1 = service.multiUpdate(o); - assertSame(r1, primary.get(o).get()); - assertSame(r1, secondary.get(o).get()); - - o = Integer.valueOf(2); - assertNull(primary.get(o)); - assertNull(secondary.get(o)); - Object r2 = service.multiUpdate(o); - assertSame(r2, primary.get(o).get()); - assertSame(r2, secondary.get(o).get()); - } - - public void testMultiCacheAndEvict(CacheableService service) { - String methodName = "multiCacheAndEvict"; - - Cache primary = cm.getCache("primary"); - Cache secondary = cm.getCache("secondary"); - Object key = Integer.valueOf(1); - - secondary.put(key, key); - - assertNull(secondary.get(methodName)); - assertSame(key, secondary.get(key).get()); - - Object r1 = service.multiCacheAndEvict(key); - assertSame(r1, service.multiCacheAndEvict(key)); - - // assert the method name is used - assertSame(r1, primary.get(methodName).get()); - assertNull(secondary.get(methodName)); - assertNull(secondary.get(key)); - } - - public void testMultiConditionalCacheAndEvict(CacheableService service) { - Cache primary = cm.getCache("primary"); - Cache secondary = cm.getCache("secondary"); - Object key = Integer.valueOf(1); - - secondary.put(key, key); - - assertNull(primary.get(key)); - assertSame(key, secondary.get(key).get()); - - Object r1 = service.multiConditionalCacheAndEvict(key); - Object r3 = service.multiConditionalCacheAndEvict(key); - - assertTrue(!r1.equals(r3)); - assertNull(primary.get(key)); - - Object key2 = Integer.valueOf(3); - Object r2 = service.multiConditionalCacheAndEvict(key2); - assertSame(r2, service.multiConditionalCacheAndEvict(key2)); - - // assert the method name is used - assertSame(r2, primary.get(key2).get()); - assertNull(secondary.get(key2)); - } - - @Test - public void testCacheable() throws Exception { - testCacheable(cs); - } - - @Test - public void testInvalidate() throws Exception { - testEvict(cs); - } - - @Test - public void testEarlyInvalidate() throws Exception { - testEvictEarly(cs); - } - - @Test - public void testEvictWithException() throws Exception { - testEvictException(cs); - } - - @Test - public void testEvictAll() throws Exception { - testEvictAll(cs); - } - - @Test - public void testInvalidateWithKey() throws Exception { - testEvictWKey(cs); - } - - @Test - public void testEarlyInvalidateWithKey() throws Exception { - testEvictWKeyEarly(cs); - } - - @Test - public void testConditionalExpression() throws Exception { - testConditionalExpression(cs); - } - - @Test - public void testKeyExpression() throws Exception { - testKeyExpression(cs); - } - - @Test - public void testClassCacheCacheable() throws Exception { - testCacheable(ccs); - } - - @Test - public void testClassCacheInvalidate() throws Exception { - testEvict(ccs); - } - - @Test - public void testClassEarlyInvalidate() throws Exception { - testEvictEarly(ccs); - } - - @Test - public void testClassEvictAll() throws Exception { - testEvictAll(ccs); - } - - @Test - public void testClassEvictWithException() throws Exception { - testEvictException(ccs); - } - - @Test - public void testClassCacheInvalidateWKey() throws Exception { - testEvictWKey(ccs); - } - - @Test - public void testClassEarlyInvalidateWithKey() throws Exception { - testEvictWKeyEarly(ccs); - } - - @Test - public void testNullValue() throws Exception { - testNullValue(cs); - } - - @Test - public void testClassNullValue() throws Exception { - Object key = new Object(); - assertNull(ccs.nullValue(key)); - int nr = ccs.nullInvocations().intValue(); - assertNull(ccs.nullValue(key)); - assertEquals(nr, ccs.nullInvocations().intValue()); - assertNull(ccs.nullValue(new Object())); - // the check method is also cached - assertEquals(nr, ccs.nullInvocations().intValue()); - assertEquals(nr + 1, AnnotatedClassCacheableService.nullInvocations.intValue()); - } - - @Test - public void testMethodName() throws Exception { - testMethodName(cs, "name"); - } - - @Test - public void testClassMethodName() throws Exception { - testMethodName(ccs, "namedefault"); - } - - @Test - public void testNullArg() throws Exception { - testNullArg(cs); - } - - @Test - public void testClassNullArg() throws Exception { - testNullArg(ccs); - } - - @Test - public void testCheckedException() throws Exception { - testCheckedThrowable(cs); - } - - @Test - public void testClassCheckedException() throws Exception { - testCheckedThrowable(ccs); - } - - @Test - public void testUncheckedException() throws Exception { - testUncheckedThrowable(cs); - } - - @Test - public void testClassUncheckedException() throws Exception { - testUncheckedThrowable(ccs); - } - - @Test - public void testUpdate() { - testCacheUpdate(cs); - } - - @Test - public void testClassUpdate() { - testCacheUpdate(ccs); - } - - @Test - public void testConditionalUpdate() { - testConditionalCacheUpdate(cs); - } - - @Test - public void testClassConditionalUpdate() { - testConditionalCacheUpdate(ccs); - } - - @Test - public void testMultiCache() { - testMultiCache(cs); - } - - @Test - public void testClassMultiCache() { - testMultiCache(ccs); - } - - @Test - public void testMultiEvict() { - testMultiEvict(cs); - } - - @Test - public void testClassMultiEvict() { - testMultiEvict(ccs); - } - - @Test - public void testMultiPut() { - testMultiPut(cs); - } - - @Test - public void testClassMultiPut() { - testMultiPut(ccs); - } - - @Test - public void testMultiCacheAndEvict() { - testMultiCacheAndEvict(cs); - } - - @Test - public void testClassMultiCacheAndEvict() { - testMultiCacheAndEvict(ccs); - } - - @Test - public void testMultiConditionalCacheAndEvict() { - testMultiConditionalCacheAndEvict(cs); - } - - @Test - public void testClassMultiConditionalCacheAndEvict() { - testMultiConditionalCacheAndEvict(ccs); - } +/* + * Copyright 2010-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache.aspectj; + +import static org.junit.Assert.*; + +import java.util.Collection; +import java.util.UUID; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.cache.config.AnnotatedClassCacheableService; +import org.springframework.cache.config.CacheableService; +import org.springframework.context.ApplicationContext; + +/** + * Abstract annotation test (containing several reusable methods). + * + * @author Costin Leau + * @author Chris Beams + */ +public abstract class AbstractAnnotationTest { + + protected ApplicationContext ctx; + + protected CacheableService cs; + + protected CacheableService ccs; + + protected CacheManager cm; + + /** @return a refreshed application context */ + protected abstract ApplicationContext getApplicationContext(); + + @Before + public void setup() { + ctx = getApplicationContext(); + cs = ctx.getBean("service", CacheableService.class); + ccs = ctx.getBean("classService", CacheableService.class); + cm = ctx.getBean(CacheManager.class); + Collection cn = cm.getCacheNames(); + assertTrue(cn.contains("default")); + } + + public void testCacheable(CacheableService service) throws Exception { + Object o1 = new Object(); + + Object r1 = service.cache(o1); + Object r2 = service.cache(o1); + Object r3 = service.cache(o1); + + assertSame(r1, r2); + assertSame(r1, r3); + } + + public void testEvict(CacheableService service) throws Exception { + Object o1 = new Object(); + + Object r1 = service.cache(o1); + Object r2 = service.cache(o1); + + assertSame(r1, r2); + service.invalidate(o1); + Object r3 = service.cache(o1); + Object r4 = service.cache(o1); + assertNotSame(r1, r3); + assertSame(r3, r4); + } + + public void testEvictEarly(CacheableService service) throws Exception { + Object o1 = new Object(); + + Object r1 = service.cache(o1); + Object r2 = service.cache(o1); + + assertSame(r1, r2); + try { + service.evictEarly(o1); + } catch (RuntimeException ex) { + // expected + } + + Object r3 = service.cache(o1); + Object r4 = service.cache(o1); + assertNotSame(r1, r3); + assertSame(r3, r4); + } + + public void testEvictException(CacheableService service) throws Exception { + Object o1 = new Object(); + + Object r1 = service.cache(o1); + Object r2 = service.cache(o1); + + assertSame(r1, r2); + try { + service.evictWithException(o1); + } catch (RuntimeException ex) { + // expected + } + // exception occurred, eviction skipped, data should still be in the cache + Object r3 = service.cache(o1); + assertSame(r1, r3); + } + + public void testEvictWKey(CacheableService service) throws Exception { + Object o1 = new Object(); + + Object r1 = service.cache(o1); + Object r2 = service.cache(o1); + + assertSame(r1, r2); + service.evict(o1, null); + Object r3 = service.cache(o1); + Object r4 = service.cache(o1); + assertNotSame(r1, r3); + assertSame(r3, r4); + } + + public void testEvictWKeyEarly(CacheableService service) throws Exception { + Object o1 = new Object(); + + Object r1 = service.cache(o1); + Object r2 = service.cache(o1); + + assertSame(r1, r2); + + try { + service.invalidateEarly(o1, null); + } catch (Exception ex) { + // expected + } + Object r3 = service.cache(o1); + Object r4 = service.cache(o1); + assertNotSame(r1, r3); + assertSame(r3, r4); + } + + public void testEvictAll(CacheableService service) throws Exception { + Object o1 = new Object(); + + Object r1 = service.cache(o1); + Object r2 = service.cache(o1); + + Object o2 = new Object(); + Object r10 = service.cache(o2); + + assertSame(r1, r2); + assertNotSame(r1, r10); + service.evictAll(new Object()); + Cache cache = cm.getCache("default"); + assertNull(cache.get(o1)); + assertNull(cache.get(o2)); + + Object r3 = service.cache(o1); + Object r4 = service.cache(o1); + assertNotSame(r1, r3); + assertSame(r3, r4); + } + + public void testConditionalExpression(CacheableService service) throws Exception { + Object r1 = service.conditional(4); + Object r2 = service.conditional(4); + + assertNotSame(r1, r2); + + Object r3 = service.conditional(3); + Object r4 = service.conditional(3); + + assertSame(r3, r4); + } + + public void testKeyExpression(CacheableService service) throws Exception { + Object r1 = service.key(5, 1); + Object r2 = service.key(5, 2); + + assertSame(r1, r2); + + Object r3 = service.key(1, 5); + Object r4 = service.key(2, 5); + + assertNotSame(r3, r4); + } + + public void testNullValue(CacheableService service) throws Exception { + Object key = new Object(); + assertNull(service.nullValue(key)); + int nr = service.nullInvocations().intValue(); + assertNull(service.nullValue(key)); + assertEquals(nr, service.nullInvocations().intValue()); + assertNull(service.nullValue(new Object())); + assertEquals(nr + 1, service.nullInvocations().intValue()); + } + + public void testMethodName(CacheableService service, String keyName) throws Exception { + Object key = new Object(); + Object r1 = service.name(key); + assertSame(r1, service.name(key)); + Cache cache = cm.getCache("default"); + // assert the method name is used + assertNotNull(cache.get(keyName)); + } + + public void testCheckedThrowable(CacheableService service) throws Exception { + String arg = UUID.randomUUID().toString(); + try { + service.throwChecked(arg); + fail("Excepted exception"); + } catch (Exception ex) { + assertEquals(arg, ex.getMessage()); + } + } + + public void testUncheckedThrowable(CacheableService service) throws Exception { + try { + service.throwUnchecked(Long.valueOf(1)); + fail("Excepted exception"); + } catch (RuntimeException ex) { + assertTrue("Excepted different exception type and got " + ex.getClass(), + ex instanceof UnsupportedOperationException); + // expected + } + } + + public void testNullArg(CacheableService service) { + Object r1 = service.cache(null); + assertSame(r1, service.cache(null)); + } + + public void testCacheUpdate(CacheableService service) { + Object o = new Object(); + Cache cache = cm.getCache("default"); + assertNull(cache.get(o)); + Object r1 = service.update(o); + assertSame(r1, cache.get(o).get()); + + o = new Object(); + assertNull(cache.get(o)); + Object r2 = service.update(o); + assertSame(r2, cache.get(o).get()); + } + + public void testConditionalCacheUpdate(CacheableService service) { + Integer one = Integer.valueOf(1); + Integer three = Integer.valueOf(3); + + Cache cache = cm.getCache("default"); + assertEquals(one, Integer.valueOf(service.conditionalUpdate(one).toString())); + assertNull(cache.get(one)); + + assertEquals(three, Integer.valueOf(service.conditionalUpdate(three).toString())); + assertEquals(three, Integer.valueOf(cache.get(three).get().toString())); + } + + public void testMultiCache(CacheableService service) { + Object o1 = new Object(); + Object o2 = new Object(); + + Cache primary = cm.getCache("primary"); + Cache secondary = cm.getCache("secondary"); + + assertNull(primary.get(o1)); + assertNull(secondary.get(o1)); + Object r1 = service.multiCache(o1); + assertSame(r1, primary.get(o1).get()); + assertSame(r1, secondary.get(o1).get()); + + Object r2 = service.multiCache(o1); + Object r3 = service.multiCache(o1); + + assertSame(r1, r2); + assertSame(r1, r3); + + assertNull(primary.get(o2)); + assertNull(secondary.get(o2)); + Object r4 = service.multiCache(o2); + assertSame(r4, primary.get(o2).get()); + assertSame(r4, secondary.get(o2).get()); + } + + public void testMultiEvict(CacheableService service) { + Object o1 = new Object(); + + Object r1 = service.multiCache(o1); + Object r2 = service.multiCache(o1); + + Cache primary = cm.getCache("primary"); + Cache secondary = cm.getCache("secondary"); + + assertSame(r1, r2); + assertSame(r1, primary.get(o1).get()); + assertSame(r1, secondary.get(o1).get()); + + service.multiEvict(o1); + assertNull(primary.get(o1)); + assertNull(secondary.get(o1)); + + Object r3 = service.multiCache(o1); + Object r4 = service.multiCache(o1); + assertNotSame(r1, r3); + assertSame(r3, r4); + + assertSame(r3, primary.get(o1).get()); + assertSame(r4, secondary.get(o1).get()); + } + + public void testMultiPut(CacheableService service) { + Object o = Integer.valueOf(1); + + Cache primary = cm.getCache("primary"); + Cache secondary = cm.getCache("secondary"); + + assertNull(primary.get(o)); + assertNull(secondary.get(o)); + Object r1 = service.multiUpdate(o); + assertSame(r1, primary.get(o).get()); + assertSame(r1, secondary.get(o).get()); + + o = Integer.valueOf(2); + assertNull(primary.get(o)); + assertNull(secondary.get(o)); + Object r2 = service.multiUpdate(o); + assertSame(r2, primary.get(o).get()); + assertSame(r2, secondary.get(o).get()); + } + + public void testMultiCacheAndEvict(CacheableService service) { + String methodName = "multiCacheAndEvict"; + + Cache primary = cm.getCache("primary"); + Cache secondary = cm.getCache("secondary"); + Object key = Integer.valueOf(1); + + secondary.put(key, key); + + assertNull(secondary.get(methodName)); + assertSame(key, secondary.get(key).get()); + + Object r1 = service.multiCacheAndEvict(key); + assertSame(r1, service.multiCacheAndEvict(key)); + + // assert the method name is used + assertSame(r1, primary.get(methodName).get()); + assertNull(secondary.get(methodName)); + assertNull(secondary.get(key)); + } + + public void testMultiConditionalCacheAndEvict(CacheableService service) { + Cache primary = cm.getCache("primary"); + Cache secondary = cm.getCache("secondary"); + Object key = Integer.valueOf(1); + + secondary.put(key, key); + + assertNull(primary.get(key)); + assertSame(key, secondary.get(key).get()); + + Object r1 = service.multiConditionalCacheAndEvict(key); + Object r3 = service.multiConditionalCacheAndEvict(key); + + assertTrue(!r1.equals(r3)); + assertNull(primary.get(key)); + + Object key2 = Integer.valueOf(3); + Object r2 = service.multiConditionalCacheAndEvict(key2); + assertSame(r2, service.multiConditionalCacheAndEvict(key2)); + + // assert the method name is used + assertSame(r2, primary.get(key2).get()); + assertNull(secondary.get(key2)); + } + + @Test + public void testCacheable() throws Exception { + testCacheable(cs); + } + + @Test + public void testInvalidate() throws Exception { + testEvict(cs); + } + + @Test + public void testEarlyInvalidate() throws Exception { + testEvictEarly(cs); + } + + @Test + public void testEvictWithException() throws Exception { + testEvictException(cs); + } + + @Test + public void testEvictAll() throws Exception { + testEvictAll(cs); + } + + @Test + public void testInvalidateWithKey() throws Exception { + testEvictWKey(cs); + } + + @Test + public void testEarlyInvalidateWithKey() throws Exception { + testEvictWKeyEarly(cs); + } + + @Test + public void testConditionalExpression() throws Exception { + testConditionalExpression(cs); + } + + @Test + public void testKeyExpression() throws Exception { + testKeyExpression(cs); + } + + @Test + public void testClassCacheCacheable() throws Exception { + testCacheable(ccs); + } + + @Test + public void testClassCacheInvalidate() throws Exception { + testEvict(ccs); + } + + @Test + public void testClassEarlyInvalidate() throws Exception { + testEvictEarly(ccs); + } + + @Test + public void testClassEvictAll() throws Exception { + testEvictAll(ccs); + } + + @Test + public void testClassEvictWithException() throws Exception { + testEvictException(ccs); + } + + @Test + public void testClassCacheInvalidateWKey() throws Exception { + testEvictWKey(ccs); + } + + @Test + public void testClassEarlyInvalidateWithKey() throws Exception { + testEvictWKeyEarly(ccs); + } + + @Test + public void testNullValue() throws Exception { + testNullValue(cs); + } + + @Test + public void testClassNullValue() throws Exception { + Object key = new Object(); + assertNull(ccs.nullValue(key)); + int nr = ccs.nullInvocations().intValue(); + assertNull(ccs.nullValue(key)); + assertEquals(nr, ccs.nullInvocations().intValue()); + assertNull(ccs.nullValue(new Object())); + // the check method is also cached + assertEquals(nr, ccs.nullInvocations().intValue()); + assertEquals(nr + 1, AnnotatedClassCacheableService.nullInvocations.intValue()); + } + + @Test + public void testMethodName() throws Exception { + testMethodName(cs, "name"); + } + + @Test + public void testClassMethodName() throws Exception { + testMethodName(ccs, "namedefault"); + } + + @Test + public void testNullArg() throws Exception { + testNullArg(cs); + } + + @Test + public void testClassNullArg() throws Exception { + testNullArg(ccs); + } + + @Test + public void testCheckedException() throws Exception { + testCheckedThrowable(cs); + } + + @Test + public void testClassCheckedException() throws Exception { + testCheckedThrowable(ccs); + } + + @Test + public void testUncheckedException() throws Exception { + testUncheckedThrowable(cs); + } + + @Test + public void testClassUncheckedException() throws Exception { + testUncheckedThrowable(ccs); + } + + @Test + public void testUpdate() { + testCacheUpdate(cs); + } + + @Test + public void testClassUpdate() { + testCacheUpdate(ccs); + } + + @Test + public void testConditionalUpdate() { + testConditionalCacheUpdate(cs); + } + + @Test + public void testClassConditionalUpdate() { + testConditionalCacheUpdate(ccs); + } + + @Test + public void testMultiCache() { + testMultiCache(cs); + } + + @Test + public void testClassMultiCache() { + testMultiCache(ccs); + } + + @Test + public void testMultiEvict() { + testMultiEvict(cs); + } + + @Test + public void testClassMultiEvict() { + testMultiEvict(ccs); + } + + @Test + public void testMultiPut() { + testMultiPut(cs); + } + + @Test + public void testClassMultiPut() { + testMultiPut(ccs); + } + + @Test + public void testMultiCacheAndEvict() { + testMultiCacheAndEvict(cs); + } + + @Test + public void testClassMultiCacheAndEvict() { + testMultiCacheAndEvict(ccs); + } + + @Test + public void testMultiConditionalCacheAndEvict() { + testMultiConditionalCacheAndEvict(cs); + } + + @Test + public void testClassMultiConditionalCacheAndEvict() { + testMultiConditionalCacheAndEvict(ccs); + } } \ No newline at end of file diff --git a/org.springframework.aspects/src/test/java/org/springframework/cache/aspectj/AspectJAnnotationTest.java b/org.springframework.aspects/src/test/java/org/springframework/cache/aspectj/AspectJAnnotationTest.java index cd46258317..27c4e6d7d8 100644 --- a/org.springframework.aspects/src/test/java/org/springframework/cache/aspectj/AspectJAnnotationTest.java +++ b/org.springframework.aspects/src/test/java/org/springframework/cache/aspectj/AspectJAnnotationTest.java @@ -1,33 +1,33 @@ -/* - * Copyright 2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cache.aspectj; - -import org.springframework.context.ApplicationContext; -import org.springframework.context.support.GenericXmlApplicationContext; - - -/** - * @author Costin Leau - */ -public class AspectJAnnotationTest extends AbstractAnnotationTest { - - - @Override - protected ApplicationContext getApplicationContext() { - return new GenericXmlApplicationContext("/org/springframework/cache/config/annotation-cache-aspectj.xml"); - } -} +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache.aspectj; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.GenericXmlApplicationContext; + + +/** + * @author Costin Leau + */ +public class AspectJAnnotationTest extends AbstractAnnotationTest { + + + @Override + protected ApplicationContext getApplicationContext() { + return new GenericXmlApplicationContext("/org/springframework/cache/config/annotation-cache-aspectj.xml"); + } +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java b/org.springframework.aspects/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java index de138f5ecd..a6d1b4f7bd 100644 --- a/org.springframework.aspects/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java +++ b/org.springframework.aspects/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java @@ -1,138 +1,138 @@ -/* - * Copyright 2010-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cache.config; - -import java.util.concurrent.atomic.AtomicLong; - -import org.springframework.cache.annotation.CacheEvict; -import org.springframework.cache.annotation.CachePut; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.cache.annotation.Caching; - -/** - * @author Costin Leau - */ -@Cacheable("default") -public class AnnotatedClassCacheableService implements CacheableService { - - private final AtomicLong counter = new AtomicLong(); - public static final AtomicLong nullInvocations = new AtomicLong(); - - public Object cache(Object arg1) { - return counter.getAndIncrement(); - } - - public Object conditional(int field) { - return null; - } - - @CacheEvict("default") - public void invalidate(Object arg1) { - } - - @CacheEvict("default") - public void evictWithException(Object arg1) { - throw new RuntimeException("exception thrown - evict should NOT occur"); - } - - @CacheEvict(value = "default", allEntries = true) - public void evictAll(Object arg1) { - } - - @CacheEvict(value = "default", beforeInvocation = true) - public void evictEarly(Object arg1) { - throw new RuntimeException("exception thrown - evict should still occur"); - } - - @CacheEvict(value = "default", key = "#p0") - public void evict(Object arg1, Object arg2) { - } - - @CacheEvict(value = "default", key = "#p0", beforeInvocation = true) - public void invalidateEarly(Object arg1, Object arg2) { - throw new RuntimeException("exception thrown - evict should still occur"); - } - - @Cacheable(value = "default", key = "#p0") - public Object key(Object arg1, Object arg2) { - return counter.getAndIncrement(); - } - - @Cacheable(value = "default", key = "#root.methodName + #root.caches[0].name") - public Object name(Object arg1) { - return counter.getAndIncrement(); - } - - @Cacheable(value = "default", key = "#root.methodName + #root.method.name + #root.targetClass + #root.target") - public Object rootVars(Object arg1) { - return counter.getAndIncrement(); - } - - @CachePut("default") - public Object update(Object arg1) { - return counter.getAndIncrement(); - } - - @CachePut(value = "default", condition = "#arg.equals(3)") - public Object conditionalUpdate(Object arg) { - return arg; - } - - public Object nullValue(Object arg1) { - nullInvocations.incrementAndGet(); - return null; - } - - public Number nullInvocations() { - return nullInvocations.get(); - } - - public Long throwChecked(Object arg1) throws Exception { - throw new UnsupportedOperationException(arg1.toString()); - } - - public Long throwUnchecked(Object arg1) { - throw new UnsupportedOperationException(); - } - - // multi annotations - - @Caching(cacheable = { @Cacheable("primary"), @Cacheable("secondary") }) - public Object multiCache(Object arg1) { - return counter.getAndIncrement(); - } - - @Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0") }) - public Object multiEvict(Object arg1) { - return counter.getAndIncrement(); - } - - @Caching(cacheable = { @Cacheable(value = "primary", key = "#root.methodName") }, evict = { @CacheEvict("secondary") }) - public Object multiCacheAndEvict(Object arg1) { - return counter.getAndIncrement(); - } - - @Caching(cacheable = { @Cacheable(value = "primary", condition = "#p0 == 3") }, evict = { @CacheEvict("secondary") }) - public Object multiConditionalCacheAndEvict(Object arg1) { - return counter.getAndIncrement(); - } - - @Caching(put = { @CachePut("primary"), @CachePut("secondary") }) - public Object multiUpdate(Object arg1) { - return arg1; - } +/* + * Copyright 2010-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache.config; + +import java.util.concurrent.atomic.AtomicLong; + +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; + +/** + * @author Costin Leau + */ +@Cacheable("default") +public class AnnotatedClassCacheableService implements CacheableService { + + private final AtomicLong counter = new AtomicLong(); + public static final AtomicLong nullInvocations = new AtomicLong(); + + public Object cache(Object arg1) { + return counter.getAndIncrement(); + } + + public Object conditional(int field) { + return null; + } + + @CacheEvict("default") + public void invalidate(Object arg1) { + } + + @CacheEvict("default") + public void evictWithException(Object arg1) { + throw new RuntimeException("exception thrown - evict should NOT occur"); + } + + @CacheEvict(value = "default", allEntries = true) + public void evictAll(Object arg1) { + } + + @CacheEvict(value = "default", beforeInvocation = true) + public void evictEarly(Object arg1) { + throw new RuntimeException("exception thrown - evict should still occur"); + } + + @CacheEvict(value = "default", key = "#p0") + public void evict(Object arg1, Object arg2) { + } + + @CacheEvict(value = "default", key = "#p0", beforeInvocation = true) + public void invalidateEarly(Object arg1, Object arg2) { + throw new RuntimeException("exception thrown - evict should still occur"); + } + + @Cacheable(value = "default", key = "#p0") + public Object key(Object arg1, Object arg2) { + return counter.getAndIncrement(); + } + + @Cacheable(value = "default", key = "#root.methodName + #root.caches[0].name") + public Object name(Object arg1) { + return counter.getAndIncrement(); + } + + @Cacheable(value = "default", key = "#root.methodName + #root.method.name + #root.targetClass + #root.target") + public Object rootVars(Object arg1) { + return counter.getAndIncrement(); + } + + @CachePut("default") + public Object update(Object arg1) { + return counter.getAndIncrement(); + } + + @CachePut(value = "default", condition = "#arg.equals(3)") + public Object conditionalUpdate(Object arg) { + return arg; + } + + public Object nullValue(Object arg1) { + nullInvocations.incrementAndGet(); + return null; + } + + public Number nullInvocations() { + return nullInvocations.get(); + } + + public Long throwChecked(Object arg1) throws Exception { + throw new UnsupportedOperationException(arg1.toString()); + } + + public Long throwUnchecked(Object arg1) { + throw new UnsupportedOperationException(); + } + + // multi annotations + + @Caching(cacheable = { @Cacheable("primary"), @Cacheable("secondary") }) + public Object multiCache(Object arg1) { + return counter.getAndIncrement(); + } + + @Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0") }) + public Object multiEvict(Object arg1) { + return counter.getAndIncrement(); + } + + @Caching(cacheable = { @Cacheable(value = "primary", key = "#root.methodName") }, evict = { @CacheEvict("secondary") }) + public Object multiCacheAndEvict(Object arg1) { + return counter.getAndIncrement(); + } + + @Caching(cacheable = { @Cacheable(value = "primary", condition = "#p0 == 3") }, evict = { @CacheEvict("secondary") }) + public Object multiConditionalCacheAndEvict(Object arg1) { + return counter.getAndIncrement(); + } + + @Caching(put = { @CachePut("primary"), @CachePut("secondary") }) + public Object multiUpdate(Object arg1) { + return arg1; + } } \ No newline at end of file diff --git a/org.springframework.aspects/src/test/java/org/springframework/cache/config/CacheableService.java b/org.springframework.aspects/src/test/java/org/springframework/cache/config/CacheableService.java index 6c3b61169d..cdcb73b2cb 100644 --- a/org.springframework.aspects/src/test/java/org/springframework/cache/config/CacheableService.java +++ b/org.springframework.aspects/src/test/java/org/springframework/cache/config/CacheableService.java @@ -1,70 +1,70 @@ -/* - * Copyright 2010-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cache.config; - -/** - * Basic service interface. - * - * @author Costin Leau - */ -public interface CacheableService { - - T cache(Object arg1); - - void invalidate(Object arg1); - - void evictEarly(Object arg1); - - void evictAll(Object arg1); - - void evictWithException(Object arg1); - - void evict(Object arg1, Object arg2); - - void invalidateEarly(Object arg1, Object arg2); - - T conditional(int field); - - T key(Object arg1, Object arg2); - - T name(Object arg1); - - T nullValue(Object arg1); - - T update(Object arg1); - - T conditionalUpdate(Object arg2); - - Number nullInvocations(); - - T rootVars(Object arg1); - - T throwChecked(Object arg1) throws Exception; - - T throwUnchecked(Object arg1); - - // multi annotations - T multiCache(Object arg1); - - T multiEvict(Object arg1); - - T multiCacheAndEvict(Object arg1); - - T multiConditionalCacheAndEvict(Object arg1); - - T multiUpdate(Object arg1); +/* + * Copyright 2010-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache.config; + +/** + * Basic service interface. + * + * @author Costin Leau + */ +public interface CacheableService { + + T cache(Object arg1); + + void invalidate(Object arg1); + + void evictEarly(Object arg1); + + void evictAll(Object arg1); + + void evictWithException(Object arg1); + + void evict(Object arg1, Object arg2); + + void invalidateEarly(Object arg1, Object arg2); + + T conditional(int field); + + T key(Object arg1, Object arg2); + + T name(Object arg1); + + T nullValue(Object arg1); + + T update(Object arg1); + + T conditionalUpdate(Object arg2); + + Number nullInvocations(); + + T rootVars(Object arg1); + + T throwChecked(Object arg1) throws Exception; + + T throwUnchecked(Object arg1); + + // multi annotations + T multiCache(Object arg1); + + T multiEvict(Object arg1); + + T multiCacheAndEvict(Object arg1); + + T multiConditionalCacheAndEvict(Object arg1); + + T multiUpdate(Object arg1); } \ No newline at end of file diff --git a/org.springframework.aspects/src/test/java/org/springframework/cache/config/DefaultCacheableService.java b/org.springframework.aspects/src/test/java/org/springframework/cache/config/DefaultCacheableService.java index 3565a8a0f4..e8938a804e 100644 --- a/org.springframework.aspects/src/test/java/org/springframework/cache/config/DefaultCacheableService.java +++ b/org.springframework.aspects/src/test/java/org/springframework/cache/config/DefaultCacheableService.java @@ -1,144 +1,144 @@ -/* - * Copyright 2010-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cache.config; - -import java.util.concurrent.atomic.AtomicLong; - -import org.springframework.cache.annotation.CacheEvict; -import org.springframework.cache.annotation.CachePut; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.cache.annotation.Caching; - -/** - * Simple cacheable service - * - * @author Costin Leau - */ -public class DefaultCacheableService implements CacheableService { - - private final AtomicLong counter = new AtomicLong(); - private final AtomicLong nullInvocations = new AtomicLong(); - - @Cacheable("default") - public Long cache(Object arg1) { - return counter.getAndIncrement(); - } - - @CacheEvict("default") - public void invalidate(Object arg1) { - } - - @CacheEvict("default") - public void evictWithException(Object arg1) { - throw new RuntimeException("exception thrown - evict should NOT occur"); - } - - @CacheEvict(value = "default", allEntries = true) - public void evictAll(Object arg1) { - } - - @CacheEvict(value = "default", beforeInvocation = true) - public void evictEarly(Object arg1) { - throw new RuntimeException("exception thrown - evict should still occur"); - } - - @CacheEvict(value = "default", key = "#p0") - public void evict(Object arg1, Object arg2) { - } - - @CacheEvict(value = "default", key = "#p0", beforeInvocation = true) - public void invalidateEarly(Object arg1, Object arg2) { - throw new RuntimeException("exception thrown - evict should still occur"); - } - - @Cacheable(value = "default", condition = "#classField == 3") - public Long conditional(int classField) { - return counter.getAndIncrement(); - } - - @Cacheable(value = "default", key = "#p0") - public Long key(Object arg1, Object arg2) { - return counter.getAndIncrement(); - } - - @Cacheable(value = "default", key = "#root.methodName") - public Long name(Object arg1) { - return counter.getAndIncrement(); - } - - @Cacheable(value = "default", key = "#root.methodName + #root.method.name + #root.targetClass + #root.target") - public Long rootVars(Object arg1) { - return counter.getAndIncrement(); - } - - @CachePut("default") - public Long update(Object arg1) { - return counter.getAndIncrement(); - } - - @CachePut(value = "default", condition = "#arg.equals(3)") - public Long conditionalUpdate(Object arg) { - return Long.valueOf(arg.toString()); - } - - @Cacheable("default") - public Long nullValue(Object arg1) { - nullInvocations.incrementAndGet(); - return null; - } - - public Number nullInvocations() { - return nullInvocations.get(); - } - - @Cacheable("default") - public Long throwChecked(Object arg1) throws Exception { - throw new Exception(arg1.toString()); - } - - @Cacheable("default") - public Long throwUnchecked(Object arg1) { - throw new UnsupportedOperationException(arg1.toString()); - } - - // multi annotations - - @Caching(cacheable = { @Cacheable("primary"), @Cacheable("secondary") }) - public Long multiCache(Object arg1) { - return counter.getAndIncrement(); - } - - @Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0") }) - public Long multiEvict(Object arg1) { - return counter.getAndIncrement(); - } - - @Caching(cacheable = { @Cacheable(value = "primary", key = "#root.methodName") }, evict = { @CacheEvict("secondary") }) - public Long multiCacheAndEvict(Object arg1) { - return counter.getAndIncrement(); - } - - @Caching(cacheable = { @Cacheable(value = "primary", condition = "#p0 == 3") }, evict = { @CacheEvict("secondary") }) - public Long multiConditionalCacheAndEvict(Object arg1) { - return counter.getAndIncrement(); - } - - @Caching(put = { @CachePut("primary"), @CachePut("secondary") }) - public Long multiUpdate(Object arg1) { - return Long.valueOf(arg1.toString()); - } +/* + * Copyright 2010-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache.config; + +import java.util.concurrent.atomic.AtomicLong; + +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; + +/** + * Simple cacheable service + * + * @author Costin Leau + */ +public class DefaultCacheableService implements CacheableService { + + private final AtomicLong counter = new AtomicLong(); + private final AtomicLong nullInvocations = new AtomicLong(); + + @Cacheable("default") + public Long cache(Object arg1) { + return counter.getAndIncrement(); + } + + @CacheEvict("default") + public void invalidate(Object arg1) { + } + + @CacheEvict("default") + public void evictWithException(Object arg1) { + throw new RuntimeException("exception thrown - evict should NOT occur"); + } + + @CacheEvict(value = "default", allEntries = true) + public void evictAll(Object arg1) { + } + + @CacheEvict(value = "default", beforeInvocation = true) + public void evictEarly(Object arg1) { + throw new RuntimeException("exception thrown - evict should still occur"); + } + + @CacheEvict(value = "default", key = "#p0") + public void evict(Object arg1, Object arg2) { + } + + @CacheEvict(value = "default", key = "#p0", beforeInvocation = true) + public void invalidateEarly(Object arg1, Object arg2) { + throw new RuntimeException("exception thrown - evict should still occur"); + } + + @Cacheable(value = "default", condition = "#classField == 3") + public Long conditional(int classField) { + return counter.getAndIncrement(); + } + + @Cacheable(value = "default", key = "#p0") + public Long key(Object arg1, Object arg2) { + return counter.getAndIncrement(); + } + + @Cacheable(value = "default", key = "#root.methodName") + public Long name(Object arg1) { + return counter.getAndIncrement(); + } + + @Cacheable(value = "default", key = "#root.methodName + #root.method.name + #root.targetClass + #root.target") + public Long rootVars(Object arg1) { + return counter.getAndIncrement(); + } + + @CachePut("default") + public Long update(Object arg1) { + return counter.getAndIncrement(); + } + + @CachePut(value = "default", condition = "#arg.equals(3)") + public Long conditionalUpdate(Object arg) { + return Long.valueOf(arg.toString()); + } + + @Cacheable("default") + public Long nullValue(Object arg1) { + nullInvocations.incrementAndGet(); + return null; + } + + public Number nullInvocations() { + return nullInvocations.get(); + } + + @Cacheable("default") + public Long throwChecked(Object arg1) throws Exception { + throw new Exception(arg1.toString()); + } + + @Cacheable("default") + public Long throwUnchecked(Object arg1) { + throw new UnsupportedOperationException(arg1.toString()); + } + + // multi annotations + + @Caching(cacheable = { @Cacheable("primary"), @Cacheable("secondary") }) + public Long multiCache(Object arg1) { + return counter.getAndIncrement(); + } + + @Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0") }) + public Long multiEvict(Object arg1) { + return counter.getAndIncrement(); + } + + @Caching(cacheable = { @Cacheable(value = "primary", key = "#root.methodName") }, evict = { @CacheEvict("secondary") }) + public Long multiCacheAndEvict(Object arg1) { + return counter.getAndIncrement(); + } + + @Caching(cacheable = { @Cacheable(value = "primary", condition = "#p0 == 3") }, evict = { @CacheEvict("secondary") }) + public Long multiConditionalCacheAndEvict(Object arg1) { + return counter.getAndIncrement(); + } + + @Caching(put = { @CachePut("primary"), @CachePut("secondary") }) + public Long multiUpdate(Object arg1) { + return Long.valueOf(arg1.toString()); + } } \ No newline at end of file diff --git a/org.springframework.aspects/src/test/java/org/springframework/mock/staticmock/AnnotationDrivenStaticEntityMockingControlTest.java b/org.springframework.aspects/src/test/java/org/springframework/mock/staticmock/AnnotationDrivenStaticEntityMockingControlTest.java index 97b08f5541..e33e3aa3f3 100644 --- a/org.springframework.aspects/src/test/java/org/springframework/mock/staticmock/AnnotationDrivenStaticEntityMockingControlTest.java +++ b/org.springframework.aspects/src/test/java/org/springframework/mock/staticmock/AnnotationDrivenStaticEntityMockingControlTest.java @@ -1,146 +1,146 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.staticmock; - -import javax.persistence.PersistenceException; - -import junit.framework.Assert; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.*; - - -/** - * Test for static entity mocking framework. - * @author Rod Johnson - * @author Ramnivas Laddad - * - */ -@MockStaticEntityMethods -@RunWith(JUnit4.class) -public class AnnotationDrivenStaticEntityMockingControlTest { - - @Test - public void testNoArgIntReturn() { - int expectedCount = 13; - Person.countPeople(); - expectReturn(expectedCount); - playback(); - Assert.assertEquals(expectedCount, Person.countPeople()); - } - - @Test(expected=PersistenceException.class) - public void testNoArgThrows() { - Person.countPeople(); - expectThrow(new PersistenceException()); - playback(); - Person.countPeople(); - } - - @Test - public void testArgMethodMatches() { - long id = 13; - Person found = new Person(); - Person.findPerson(id); - expectReturn(found); - playback(); - Assert.assertEquals(found, Person.findPerson(id)); - } - - - @Test - public void testLongSeriesOfCalls() { - long id1 = 13; - long id2 = 24; - Person found1 = new Person(); - Person.findPerson(id1); - expectReturn(found1); - Person found2 = new Person(); - Person.findPerson(id2); - expectReturn(found2); - Person.findPerson(id1); - expectReturn(found1); - Person.countPeople(); - expectReturn(0); - playback(); - - Assert.assertEquals(found1, Person.findPerson(id1)); - Assert.assertEquals(found2, Person.findPerson(id2)); - Assert.assertEquals(found1, Person.findPerson(id1)); - Assert.assertEquals(0, Person.countPeople()); - } - - // Note delegation is used when tests are invalid and should fail, as otherwise - // the failure will occur on the verify() method in the aspect after - // this method returns, failing the test case - @Test - public void testArgMethodNoMatchExpectReturn() { - try { - new Delegate().testArgMethodNoMatchExpectReturn(); - Assert.fail(); - } catch (IllegalArgumentException expected) { - } - } - - @Test(expected=IllegalArgumentException.class) - public void testArgMethodNoMatchExpectThrow() { - new Delegate().testArgMethodNoMatchExpectThrow(); - } - - private void called(Person found, long id) { - Assert.assertEquals(found, Person.findPerson(id)); - } - - @Test - public void testReentrant() { - long id = 13; - Person found = new Person(); - Person.findPerson(id); - expectReturn(found); - playback(); - called(found, id); - } - - @Test(expected=IllegalStateException.class) - public void testRejectUnexpectedCall() { - new Delegate().rejectUnexpectedCall(); - } - - @Test(expected=IllegalStateException.class) - public void testFailTooFewCalls() { - new Delegate().failTooFewCalls(); - } - - @Test - public void testEmpty() { - // Test that verification check doesn't blow up if no replay() call happened - } - - @Test(expected=IllegalStateException.class) - public void testDoesntEverReplay() { - new Delegate().doesntEverReplay(); - } - - @Test(expected=IllegalStateException.class) - public void testDoesntEverSetReturn() { - new Delegate().doesntEverSetReturn(); - } -} - +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.staticmock; + +import javax.persistence.PersistenceException; + +import junit.framework.Assert; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import static org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl.*; + + +/** + * Test for static entity mocking framework. + * @author Rod Johnson + * @author Ramnivas Laddad + * + */ +@MockStaticEntityMethods +@RunWith(JUnit4.class) +public class AnnotationDrivenStaticEntityMockingControlTest { + + @Test + public void testNoArgIntReturn() { + int expectedCount = 13; + Person.countPeople(); + expectReturn(expectedCount); + playback(); + Assert.assertEquals(expectedCount, Person.countPeople()); + } + + @Test(expected=PersistenceException.class) + public void testNoArgThrows() { + Person.countPeople(); + expectThrow(new PersistenceException()); + playback(); + Person.countPeople(); + } + + @Test + public void testArgMethodMatches() { + long id = 13; + Person found = new Person(); + Person.findPerson(id); + expectReturn(found); + playback(); + Assert.assertEquals(found, Person.findPerson(id)); + } + + + @Test + public void testLongSeriesOfCalls() { + long id1 = 13; + long id2 = 24; + Person found1 = new Person(); + Person.findPerson(id1); + expectReturn(found1); + Person found2 = new Person(); + Person.findPerson(id2); + expectReturn(found2); + Person.findPerson(id1); + expectReturn(found1); + Person.countPeople(); + expectReturn(0); + playback(); + + Assert.assertEquals(found1, Person.findPerson(id1)); + Assert.assertEquals(found2, Person.findPerson(id2)); + Assert.assertEquals(found1, Person.findPerson(id1)); + Assert.assertEquals(0, Person.countPeople()); + } + + // Note delegation is used when tests are invalid and should fail, as otherwise + // the failure will occur on the verify() method in the aspect after + // this method returns, failing the test case + @Test + public void testArgMethodNoMatchExpectReturn() { + try { + new Delegate().testArgMethodNoMatchExpectReturn(); + Assert.fail(); + } catch (IllegalArgumentException expected) { + } + } + + @Test(expected=IllegalArgumentException.class) + public void testArgMethodNoMatchExpectThrow() { + new Delegate().testArgMethodNoMatchExpectThrow(); + } + + private void called(Person found, long id) { + Assert.assertEquals(found, Person.findPerson(id)); + } + + @Test + public void testReentrant() { + long id = 13; + Person found = new Person(); + Person.findPerson(id); + expectReturn(found); + playback(); + called(found, id); + } + + @Test(expected=IllegalStateException.class) + public void testRejectUnexpectedCall() { + new Delegate().rejectUnexpectedCall(); + } + + @Test(expected=IllegalStateException.class) + public void testFailTooFewCalls() { + new Delegate().failTooFewCalls(); + } + + @Test + public void testEmpty() { + // Test that verification check doesn't blow up if no replay() call happened + } + + @Test(expected=IllegalStateException.class) + public void testDoesntEverReplay() { + new Delegate().doesntEverReplay(); + } + + @Test(expected=IllegalStateException.class) + public void testDoesntEverSetReturn() { + new Delegate().doesntEverSetReturn(); + } +} + diff --git a/org.springframework.aspects/src/test/java/org/springframework/mock/staticmock/Delegate.java b/org.springframework.aspects/src/test/java/org/springframework/mock/staticmock/Delegate.java index 9c692c976b..c99dfe0c2e 100644 --- a/org.springframework.aspects/src/test/java/org/springframework/mock/staticmock/Delegate.java +++ b/org.springframework.aspects/src/test/java/org/springframework/mock/staticmock/Delegate.java @@ -1,92 +1,92 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.staticmock; - -import java.rmi.RemoteException; - -import javax.persistence.PersistenceException; - -import junit.framework.Assert; - -import org.junit.Ignore; -import org.junit.Test; -import org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl; -import org.springframework.mock.staticmock.MockStaticEntityMethods; - -//Used because verification failures occur after method returns, -//so we can't test for them in the test case itself -@MockStaticEntityMethods -@Ignore // This isn't meant for direct testing; rather it is driven from AnnotationDrivenStaticEntityMockingControl -public class Delegate { - - @Test - public void testArgMethodNoMatchExpectReturn() { - long id = 13; - Person found = new Person(); - Person.findPerson(id); - AnnotationDrivenStaticEntityMockingControl.expectReturn(found); - AnnotationDrivenStaticEntityMockingControl.playback(); - Assert.assertEquals(found, Person.findPerson(id + 1)); - } - - @Test - public void testArgMethodNoMatchExpectThrow() { - long id = 13; - Person found = new Person(); - Person.findPerson(id); - AnnotationDrivenStaticEntityMockingControl.expectThrow(new PersistenceException()); - AnnotationDrivenStaticEntityMockingControl.playback(); - Assert.assertEquals(found, Person.findPerson(id + 1)); - } - - @Test - public void failTooFewCalls() { - long id = 13; - Person found = new Person(); - Person.findPerson(id); - AnnotationDrivenStaticEntityMockingControl.expectReturn(found); - Person.countPeople(); - AnnotationDrivenStaticEntityMockingControl.expectReturn(25); - AnnotationDrivenStaticEntityMockingControl.playback(); - Assert.assertEquals(found, Person.findPerson(id)); - } - - @Test - public void doesntEverReplay() { - Person.countPeople(); - } - - @Test - public void doesntEverSetReturn() { - Person.countPeople(); - AnnotationDrivenStaticEntityMockingControl.playback(); - } - - @Test - public void rejectUnexpectedCall() { - AnnotationDrivenStaticEntityMockingControl.playback(); - Person.countPeople(); - } - - @Test(expected=RemoteException.class) - public void testVerificationFailsEvenWhenTestFailsInExpectedManner() throws RemoteException { - Person.countPeople(); - AnnotationDrivenStaticEntityMockingControl.playback(); - // No calls to allow verification failure - throw new RemoteException(); - } -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.staticmock; + +import java.rmi.RemoteException; + +import javax.persistence.PersistenceException; + +import junit.framework.Assert; + +import org.junit.Ignore; +import org.junit.Test; +import org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl; +import org.springframework.mock.staticmock.MockStaticEntityMethods; + +//Used because verification failures occur after method returns, +//so we can't test for them in the test case itself +@MockStaticEntityMethods +@Ignore // This isn't meant for direct testing; rather it is driven from AnnotationDrivenStaticEntityMockingControl +public class Delegate { + + @Test + public void testArgMethodNoMatchExpectReturn() { + long id = 13; + Person found = new Person(); + Person.findPerson(id); + AnnotationDrivenStaticEntityMockingControl.expectReturn(found); + AnnotationDrivenStaticEntityMockingControl.playback(); + Assert.assertEquals(found, Person.findPerson(id + 1)); + } + + @Test + public void testArgMethodNoMatchExpectThrow() { + long id = 13; + Person found = new Person(); + Person.findPerson(id); + AnnotationDrivenStaticEntityMockingControl.expectThrow(new PersistenceException()); + AnnotationDrivenStaticEntityMockingControl.playback(); + Assert.assertEquals(found, Person.findPerson(id + 1)); + } + + @Test + public void failTooFewCalls() { + long id = 13; + Person found = new Person(); + Person.findPerson(id); + AnnotationDrivenStaticEntityMockingControl.expectReturn(found); + Person.countPeople(); + AnnotationDrivenStaticEntityMockingControl.expectReturn(25); + AnnotationDrivenStaticEntityMockingControl.playback(); + Assert.assertEquals(found, Person.findPerson(id)); + } + + @Test + public void doesntEverReplay() { + Person.countPeople(); + } + + @Test + public void doesntEverSetReturn() { + Person.countPeople(); + AnnotationDrivenStaticEntityMockingControl.playback(); + } + + @Test + public void rejectUnexpectedCall() { + AnnotationDrivenStaticEntityMockingControl.playback(); + Person.countPeople(); + } + + @Test(expected=RemoteException.class) + public void testVerificationFailsEvenWhenTestFailsInExpectedManner() throws RemoteException { + Person.countPeople(); + AnnotationDrivenStaticEntityMockingControl.playback(); + // No calls to allow verification failure + throw new RemoteException(); + } +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/mock/staticmock/Person.java b/org.springframework.aspects/src/test/java/org/springframework/mock/staticmock/Person.java index 8fb74167b6..a3b15c59c6 100644 --- a/org.springframework.aspects/src/test/java/org/springframework/mock/staticmock/Person.java +++ b/org.springframework.aspects/src/test/java/org/springframework/mock/staticmock/Person.java @@ -1,24 +1,24 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.staticmock; - -import javax.persistence.Entity; - -@Entity -public class Person { -} - +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.staticmock; + +import javax.persistence.Entity; + +@Entity +public class Person { +} + diff --git a/org.springframework.aspects/src/test/java/org/springframework/mock/staticmock/Person_Roo_Entity.aj b/org.springframework.aspects/src/test/java/org/springframework/mock/staticmock/Person_Roo_Entity.aj index 799b2848bd..4d30f14376 100644 --- a/org.springframework.aspects/src/test/java/org/springframework/mock/staticmock/Person_Roo_Entity.aj +++ b/org.springframework.aspects/src/test/java/org/springframework/mock/staticmock/Person_Roo_Entity.aj @@ -1,100 +1,100 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.staticmock; - -privileged aspect Person_Roo_Entity { - - @javax.persistence.PersistenceContext - transient javax.persistence.EntityManager Person.entityManager; - - @javax.persistence.Id - @javax.persistence.GeneratedValue(strategy = javax.persistence.GenerationType.AUTO) - @javax.persistence.Column(name = "id") - private java.lang.Long Person.id; - - @javax.persistence.Version - @javax.persistence.Column(name = "version") - private java.lang.Integer Person.version; - - public java.lang.Long Person.getId() { - return this.id; - } - - public void Person.setId(java.lang.Long id) { - this.id = id; - } - - public java.lang.Integer Person.getVersion() { - return this.version; - } - - public void Person.setVersion(java.lang.Integer version) { - this.version = version; - } - - @org.springframework.transaction.annotation.Transactional - public void Person.persist() { - if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)"); - this.entityManager.persist(this); - } - - @org.springframework.transaction.annotation.Transactional - public void Person.remove() { - if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)"); - this.entityManager.remove(this); - } - - @org.springframework.transaction.annotation.Transactional - public void Person.flush() { - if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)"); - this.entityManager.flush(); - } - - @org.springframework.transaction.annotation.Transactional - public void Person.merge() { - if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)"); - Person merged = this.entityManager.merge(this); - this.entityManager.flush(); - this.id = merged.getId(); - } - - public static long Person.countPeople() { - javax.persistence.EntityManager em = new Person().entityManager; - if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)"); - return (Long) em.createQuery("select count(o) from Person o").getSingleResult(); - } - - public static java.util.List Person.findAllPeople() { - javax.persistence.EntityManager em = new Person().entityManager; - if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)"); - return em.createQuery("select o from Person o").getResultList(); - } - - public static Person Person.findPerson(java.lang.Long id) { - if (id == null) throw new IllegalArgumentException("An identifier is required to retrieve an instance of Person"); - javax.persistence.EntityManager em = new Person().entityManager; - if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)"); - return em.find(Person.class, id); - } - - public static java.util.List Person.findPersonEntries(int firstResult, int maxResults) { - javax.persistence.EntityManager em = new Person().entityManager; - if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)"); - return em.createQuery("select o from Person o").setFirstResult(firstResult).setMaxResults(maxResults).getResultList(); - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.staticmock; + +privileged aspect Person_Roo_Entity { + + @javax.persistence.PersistenceContext + transient javax.persistence.EntityManager Person.entityManager; + + @javax.persistence.Id + @javax.persistence.GeneratedValue(strategy = javax.persistence.GenerationType.AUTO) + @javax.persistence.Column(name = "id") + private java.lang.Long Person.id; + + @javax.persistence.Version + @javax.persistence.Column(name = "version") + private java.lang.Integer Person.version; + + public java.lang.Long Person.getId() { + return this.id; + } + + public void Person.setId(java.lang.Long id) { + this.id = id; + } + + public java.lang.Integer Person.getVersion() { + return this.version; + } + + public void Person.setVersion(java.lang.Integer version) { + this.version = version; + } + + @org.springframework.transaction.annotation.Transactional + public void Person.persist() { + if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)"); + this.entityManager.persist(this); + } + + @org.springframework.transaction.annotation.Transactional + public void Person.remove() { + if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)"); + this.entityManager.remove(this); + } + + @org.springframework.transaction.annotation.Transactional + public void Person.flush() { + if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)"); + this.entityManager.flush(); + } + + @org.springframework.transaction.annotation.Transactional + public void Person.merge() { + if (this.entityManager == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)"); + Person merged = this.entityManager.merge(this); + this.entityManager.flush(); + this.id = merged.getId(); + } + + public static long Person.countPeople() { + javax.persistence.EntityManager em = new Person().entityManager; + if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)"); + return (Long) em.createQuery("select count(o) from Person o").getSingleResult(); + } + + public static java.util.List Person.findAllPeople() { + javax.persistence.EntityManager em = new Person().entityManager; + if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)"); + return em.createQuery("select o from Person o").getResultList(); + } + + public static Person Person.findPerson(java.lang.Long id) { + if (id == null) throw new IllegalArgumentException("An identifier is required to retrieve an instance of Person"); + javax.persistence.EntityManager em = new Person().entityManager; + if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)"); + return em.find(Person.class, id); + } + + public static java.util.List Person.findPersonEntries(int firstResult, int maxResults) { + javax.persistence.EntityManager em = new Person().entityManager; + if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)"); + return em.createQuery("select o from Person o").setFirstResult(firstResult).setMaxResults(maxResults).getResultList(); + } + +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/scheduling/aspectj/AnnotationAsyncExecutionAspectTests.java b/org.springframework.aspects/src/test/java/org/springframework/scheduling/aspectj/AnnotationAsyncExecutionAspectTests.java index f8d55a43d2..e2194cfe5c 100644 --- a/org.springframework.aspects/src/test/java/org/springframework/scheduling/aspectj/AnnotationAsyncExecutionAspectTests.java +++ b/org.springframework.aspects/src/test/java/org/springframework/scheduling/aspectj/AnnotationAsyncExecutionAspectTests.java @@ -1,178 +1,178 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.scheduling.aspectj; - -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; - -import junit.framework.Assert; - -import static junit.framework.Assert.*; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.core.task.SimpleAsyncTaskExecutor; -import org.springframework.scheduling.annotation.Async; -import org.springframework.scheduling.annotation.AsyncResult; - -/** - * @author Ramnivas Laddad - */ -public class AnnotationAsyncExecutionAspectTests { - - private static final long WAIT_TIME = 1000; //milli seconds - - private CountingExecutor executor; - - @Before - public void setUp() { - executor = new CountingExecutor(); - AnnotationAsyncExecutionAspect.aspectOf().setExecutor(executor); - } - - @Test - public void asyncMethodGetsRoutedAsynchronously() { - ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation(); - obj.incrementAsync(); - executor.waitForCompletion(); - assertEquals(1, obj.counter); - assertEquals(1, executor.submitStartCounter); - assertEquals(1, executor.submitCompleteCounter); - } - - @Test - public void asyncMethodReturningFutureGetsRoutedAsynchronouslyAndReturnsAFuture() throws InterruptedException, ExecutionException { - ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation(); - Future future = obj.incrementReturningAFuture(); - // No need to executor.waitForCompletion() as future.get() will have the same effect - assertEquals(5, future.get().intValue()); - assertEquals(1, obj.counter); - assertEquals(1, executor.submitStartCounter); - assertEquals(1, executor.submitCompleteCounter); - } - - @Test - public void syncMethodGetsRoutedSynchronously() { - ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation(); - obj.increment(); - assertEquals(1, obj.counter); - assertEquals(0, executor.submitStartCounter); - assertEquals(0, executor.submitCompleteCounter); - } - - @Test - public void voidMethodInAsyncClassGetsRoutedAsynchronously() { - ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation(); - obj.increment(); - executor.waitForCompletion(); - assertEquals(1, obj.counter); - assertEquals(1, executor.submitStartCounter); - assertEquals(1, executor.submitCompleteCounter); - } - - @Test - public void methodReturningFutureInAsyncClassGetsRoutedAsynchronouslyAndReturnsAFuture() throws InterruptedException, ExecutionException { - ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation(); - Future future = obj.incrementReturningAFuture(); - assertEquals(5, future.get().intValue()); - assertEquals(1, obj.counter); - assertEquals(1, executor.submitStartCounter); - assertEquals(1, executor.submitCompleteCounter); - } - - @Test - public void methodReturningNonVoidNonFutureInAsyncClassGetsRoutedSynchronously() { - ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation(); - int returnValue = obj.return5(); - assertEquals(5, returnValue); - assertEquals(0, executor.submitStartCounter); - assertEquals(0, executor.submitCompleteCounter); - } - - @SuppressWarnings("serial") - private static class CountingExecutor extends SimpleAsyncTaskExecutor { - int submitStartCounter; - int submitCompleteCounter; - - @Override - public Future submit(Callable task) { - submitStartCounter++; - Future future = super.submit(task); - submitCompleteCounter++; - synchronized (this) { - notifyAll(); - } - return future; - } - - public synchronized void waitForCompletion() { - try { - wait(WAIT_TIME); - } catch (InterruptedException e) { - Assert.fail("Didn't finish the async job in " + WAIT_TIME + " milliseconds"); - } - } - } - - static class ClassWithoutAsyncAnnotation { - int counter; - - @Async public void incrementAsync() { - counter++; - } - - public void increment() { - counter++; - } - - @Async public Future incrementReturningAFuture() { - counter++; - return new AsyncResult(5); - } - - // It should be an error to attach @Async to a method that returns a non-void - // or non-Future. - // We need to keep this commented out, otherwise there will be a compile-time error. - // Please uncomment and re-comment this periodically to check that the compiler - // produces an error message due to the 'declare error' statement - // in AnnotationAsyncExecutionAspect -// @Async public int getInt() { -// return 0; -// } - } - - @Async - static class ClassWithAsyncAnnotation { - int counter; - - public void increment() { - counter++; - } - - // Manually check that there is a warning from the 'declare warning' statement in AnnotationAsynchExecutionAspect - public int return5() { - return 5; - } - - public Future incrementReturningAFuture() { - counter++; - return new AsyncResult(5); - } - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling.aspectj; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +import junit.framework.Assert; + +import static junit.framework.Assert.*; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.AsyncResult; + +/** + * @author Ramnivas Laddad + */ +public class AnnotationAsyncExecutionAspectTests { + + private static final long WAIT_TIME = 1000; //milli seconds + + private CountingExecutor executor; + + @Before + public void setUp() { + executor = new CountingExecutor(); + AnnotationAsyncExecutionAspect.aspectOf().setExecutor(executor); + } + + @Test + public void asyncMethodGetsRoutedAsynchronously() { + ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation(); + obj.incrementAsync(); + executor.waitForCompletion(); + assertEquals(1, obj.counter); + assertEquals(1, executor.submitStartCounter); + assertEquals(1, executor.submitCompleteCounter); + } + + @Test + public void asyncMethodReturningFutureGetsRoutedAsynchronouslyAndReturnsAFuture() throws InterruptedException, ExecutionException { + ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation(); + Future future = obj.incrementReturningAFuture(); + // No need to executor.waitForCompletion() as future.get() will have the same effect + assertEquals(5, future.get().intValue()); + assertEquals(1, obj.counter); + assertEquals(1, executor.submitStartCounter); + assertEquals(1, executor.submitCompleteCounter); + } + + @Test + public void syncMethodGetsRoutedSynchronously() { + ClassWithoutAsyncAnnotation obj = new ClassWithoutAsyncAnnotation(); + obj.increment(); + assertEquals(1, obj.counter); + assertEquals(0, executor.submitStartCounter); + assertEquals(0, executor.submitCompleteCounter); + } + + @Test + public void voidMethodInAsyncClassGetsRoutedAsynchronously() { + ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation(); + obj.increment(); + executor.waitForCompletion(); + assertEquals(1, obj.counter); + assertEquals(1, executor.submitStartCounter); + assertEquals(1, executor.submitCompleteCounter); + } + + @Test + public void methodReturningFutureInAsyncClassGetsRoutedAsynchronouslyAndReturnsAFuture() throws InterruptedException, ExecutionException { + ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation(); + Future future = obj.incrementReturningAFuture(); + assertEquals(5, future.get().intValue()); + assertEquals(1, obj.counter); + assertEquals(1, executor.submitStartCounter); + assertEquals(1, executor.submitCompleteCounter); + } + + @Test + public void methodReturningNonVoidNonFutureInAsyncClassGetsRoutedSynchronously() { + ClassWithAsyncAnnotation obj = new ClassWithAsyncAnnotation(); + int returnValue = obj.return5(); + assertEquals(5, returnValue); + assertEquals(0, executor.submitStartCounter); + assertEquals(0, executor.submitCompleteCounter); + } + + @SuppressWarnings("serial") + private static class CountingExecutor extends SimpleAsyncTaskExecutor { + int submitStartCounter; + int submitCompleteCounter; + + @Override + public Future submit(Callable task) { + submitStartCounter++; + Future future = super.submit(task); + submitCompleteCounter++; + synchronized (this) { + notifyAll(); + } + return future; + } + + public synchronized void waitForCompletion() { + try { + wait(WAIT_TIME); + } catch (InterruptedException e) { + Assert.fail("Didn't finish the async job in " + WAIT_TIME + " milliseconds"); + } + } + } + + static class ClassWithoutAsyncAnnotation { + int counter; + + @Async public void incrementAsync() { + counter++; + } + + public void increment() { + counter++; + } + + @Async public Future incrementReturningAFuture() { + counter++; + return new AsyncResult(5); + } + + // It should be an error to attach @Async to a method that returns a non-void + // or non-Future. + // We need to keep this commented out, otherwise there will be a compile-time error. + // Please uncomment and re-comment this periodically to check that the compiler + // produces an error message due to the 'declare error' statement + // in AnnotationAsyncExecutionAspect +// @Async public int getInt() { +// return 0; +// } + } + + @Async + static class ClassWithAsyncAnnotation { + int counter; + + public void increment() { + counter++; + } + + // Manually check that there is a warning from the 'declare warning' statement in AnnotationAsynchExecutionAspect + public int return5() { + return 5; + } + + public Future incrementReturningAFuture() { + counter++; + return new AsyncResult(5); + } + } + +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ClassWithPrivateAnnotatedMember.java b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ClassWithPrivateAnnotatedMember.java index 899e0feb67..6351d55d0d 100644 --- a/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ClassWithPrivateAnnotatedMember.java +++ b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ClassWithPrivateAnnotatedMember.java @@ -1,34 +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. - * - * Created on 11 Sep 2006 by Adrian Colyer - */ -package org.springframework.transaction.aspectj; - -import org.springframework.transaction.annotation.Transactional; - -/** - * @author Adrian Colyer - * @since 2.0 - */ -public class ClassWithPrivateAnnotatedMember { - - public void doSomething() { - doInTransaction(); - } - - @Transactional - private void doInTransaction() {} -} +/* + * 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 11 Sep 2006 by Adrian Colyer + */ +package org.springframework.transaction.aspectj; + +import org.springframework.transaction.annotation.Transactional; + +/** + * @author Adrian Colyer + * @since 2.0 + */ +public class ClassWithPrivateAnnotatedMember { + + public void doSomething() { + doInTransaction(); + } + + @Transactional + private void doInTransaction() {} +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ClassWithProtectedAnnotatedMember.java b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ClassWithProtectedAnnotatedMember.java index a4cb30c50f..f681c81e84 100644 --- a/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ClassWithProtectedAnnotatedMember.java +++ b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ClassWithProtectedAnnotatedMember.java @@ -1,34 +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. - * - * Created on 11 Sep 2006 by Adrian Colyer - */ -package org.springframework.transaction.aspectj; - -import org.springframework.transaction.annotation.Transactional; - -/** - * @author Adrian Colyer - * @since 2.0 - */ -public class ClassWithProtectedAnnotatedMember { - - public void doSomething() { - doInTransaction(); - } - - @Transactional - protected void doInTransaction() {} -} +/* + * 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 11 Sep 2006 by Adrian Colyer + */ +package org.springframework.transaction.aspectj; + +import org.springframework.transaction.annotation.Transactional; + +/** + * @author Adrian Colyer + * @since 2.0 + */ +public class ClassWithProtectedAnnotatedMember { + + public void doSomething() { + doInTransaction(); + } + + @Transactional + protected void doInTransaction() {} +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ITransactional.java b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ITransactional.java index 48670fbf6a..19a115ea21 100644 --- a/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ITransactional.java +++ b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/ITransactional.java @@ -1,10 +1,10 @@ -package org.springframework.transaction.aspectj; - -import org.springframework.transaction.annotation.Transactional; - -@Transactional -public interface ITransactional { - - Object echo(Throwable t) throws Throwable; - -} +package org.springframework.transaction.aspectj; + +import org.springframework.transaction.annotation.Transactional; + +@Transactional +public interface ITransactional { + + Object echo(Throwable t) throws Throwable; + +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/MethodAnnotationOnClassWithNoInterface.java b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/MethodAnnotationOnClassWithNoInterface.java index 29b9b311b7..22cc31ebc6 100644 --- a/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/MethodAnnotationOnClassWithNoInterface.java +++ b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/MethodAnnotationOnClassWithNoInterface.java @@ -1,19 +1,19 @@ -package org.springframework.transaction.aspectj; - -import org.springframework.transaction.annotation.Transactional; - -public class MethodAnnotationOnClassWithNoInterface { - - @Transactional(rollbackFor=InterruptedException.class) - public Object echo(Throwable t) throws Throwable { - if (t != null) { - throw t; - } - return t; - } - - public void noTransactionAttribute() { - - } - -} +package org.springframework.transaction.aspectj; + +import org.springframework.transaction.annotation.Transactional; + +public class MethodAnnotationOnClassWithNoInterface { + + @Transactional(rollbackFor=InterruptedException.class) + public Object echo(Throwable t) throws Throwable { + if (t != null) { + throw t; + } + return t; + } + + public void noTransactionAttribute() { + + } + +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests.java b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests.java index 39fedc70b3..9449b2bcf7 100644 --- a/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests.java +++ b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests.java @@ -1,261 +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.transaction.aspectj; - -import java.lang.reflect.Method; - -import junit.framework.AssertionFailedError; - -import org.springframework.test.AbstractDependencyInjectionSpringContextTests; -import org.springframework.transaction.CallCountingTransactionManager; -import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource; -import org.springframework.transaction.interceptor.TransactionAspectSupport; -import org.springframework.transaction.interceptor.TransactionAttribute; - -/** - * @author Rod Johnson - * @author Ramnivas Laddad - */ -public class TransactionAspectTests extends AbstractDependencyInjectionSpringContextTests { - - private TransactionAspectSupport transactionAspect; - - private CallCountingTransactionManager txManager; - - private TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface; - - private ClassWithProtectedAnnotatedMember beanWithAnnotatedProtectedMethod; - - private ClassWithPrivateAnnotatedMember beanWithAnnotatedPrivateMethod; - - private MethodAnnotationOnClassWithNoInterface methodAnnotationOnly = new MethodAnnotationOnClassWithNoInterface(); - - - public void setAnnotationOnlyOnClassWithNoInterface( - TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface) { - this.annotationOnlyOnClassWithNoInterface = annotationOnlyOnClassWithNoInterface; - } - - public void setClassWithAnnotatedProtectedMethod(ClassWithProtectedAnnotatedMember aBean) { - this.beanWithAnnotatedProtectedMethod = aBean; - } - - public void setClassWithAnnotatedPrivateMethod(ClassWithPrivateAnnotatedMember aBean) { - this.beanWithAnnotatedPrivateMethod = aBean; - } - - public void setTransactionAspect(TransactionAspectSupport transactionAspect) { - this.transactionAspect = transactionAspect; - this.txManager = (CallCountingTransactionManager) transactionAspect.getTransactionManager(); - } - - public TransactionAspectSupport getTransactionAspect() { - return this.transactionAspect; - } - - @Override - protected String getConfigPath() { - return "TransactionAspectTests-context.xml"; - } - - - public void testCommitOnAnnotatedClass() throws Throwable { - txManager.clear(); - assertEquals(0, txManager.begun); - annotationOnlyOnClassWithNoInterface.echo(null); - assertEquals(1, txManager.commits); - } - - public void testCommitOnAnnotatedProtectedMethod() throws Throwable { - txManager.clear(); - assertEquals(0, txManager.begun); - beanWithAnnotatedProtectedMethod.doInTransaction(); - assertEquals(1, txManager.commits); - } - - public void testCommitOnAnnotatedPrivateMethod() throws Throwable { - txManager.clear(); - assertEquals(0, txManager.begun); - beanWithAnnotatedPrivateMethod.doSomething(); - assertEquals(1, txManager.commits); - } - - public void testNoCommitOnNonAnnotatedNonPublicMethodInTransactionalType() throws Throwable { - txManager.clear(); - assertEquals(0,txManager.begun); - annotationOnlyOnClassWithNoInterface.nonTransactionalMethod(); - assertEquals(0,txManager.begun); - } - - public void testCommitOnAnnotatedMethod() throws Throwable { - txManager.clear(); - assertEquals(0, txManager.begun); - methodAnnotationOnly.echo(null); - assertEquals(1, txManager.commits); - } - - - public static class NotTransactional { - public void noop() { - } - } - - public void testNotTransactional() throws Throwable { - txManager.clear(); - assertEquals(0, txManager.begun); - new NotTransactional().noop(); - assertEquals(0, txManager.begun); - } - - - public void testDefaultCommitOnAnnotatedClass() throws Throwable { - testRollback(new TransactionOperationCallback() { - public Object performTransactionalOperation() throws Throwable { - return annotationOnlyOnClassWithNoInterface.echo(new Exception()); - } - }, false); - } - - public void testDefaultRollbackOnAnnotatedClass() throws Throwable { - testRollback(new TransactionOperationCallback() { - public Object performTransactionalOperation() throws Throwable { - return annotationOnlyOnClassWithNoInterface.echo(new RuntimeException()); - } - }, true); - } - - - public static class SubclassOfClassWithTransactionalAnnotation extends TransactionalAnnotationOnlyOnClassWithNoInterface { - } - - public void testDefaultCommitOnSubclassOfAnnotatedClass() throws Throwable { - testRollback(new TransactionOperationCallback() { - public Object performTransactionalOperation() throws Throwable { - return new SubclassOfClassWithTransactionalAnnotation().echo(new Exception()); - } - }, false); - } - - public static class SubclassOfClassWithTransactionalMethodAnnotation extends MethodAnnotationOnClassWithNoInterface { - } - - public void testDefaultCommitOnSubclassOfClassWithTransactionalMethodAnnotated() throws Throwable { - testRollback(new TransactionOperationCallback() { - public Object performTransactionalOperation() throws Throwable { - return new SubclassOfClassWithTransactionalMethodAnnotation().echo(new Exception()); - } - }, false); - } - - public static class ImplementsAnnotatedInterface implements ITransactional { - public Object echo(Throwable t) throws Throwable { - if (t != null) { - throw t; - } - return t; - } - } - - public void testDefaultCommitOnImplementationOfAnnotatedInterface() throws Throwable { -// testRollback(new TransactionOperationCallback() { -// public Object performTransactionalOperation() throws Throwable { -// return new ImplementsAnnotatedInterface().echo(new Exception()); -// } -// }, false); - - final Exception ex = new Exception(); - testNotTransactional(new TransactionOperationCallback() { - public Object performTransactionalOperation() throws Throwable { - return new ImplementsAnnotatedInterface().echo(ex); - } - }, ex); - } - - /** - * Note: resolution does not occur. Thus we can't make a class transactional if - * it implements a transactionally annotated interface. This behaviour could only - * be changed in AbstractFallbackTransactionAttributeSource in Spring proper. - * @throws SecurityException - * @throws NoSuchMethodException - */ - public void testDoesNotResolveTxAnnotationOnMethodFromClassImplementingAnnotatedInterface() throws SecurityException, NoSuchMethodException { - AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - Method m = ImplementsAnnotatedInterface.class.getMethod("echo", Throwable.class); - TransactionAttribute ta = atas.getTransactionAttribute(m, ImplementsAnnotatedInterface.class); - assertNull(ta); - } - - - public void testDefaultRollbackOnImplementationOfAnnotatedInterface() throws Throwable { -// testRollback(new TransactionOperationCallback() { -// public Object performTransactionalOperation() throws Throwable { -// return new ImplementsAnnotatedInterface().echo(new RuntimeException()); -// } -// }, true); - - final Exception rollbackProvokingException = new RuntimeException(); - testNotTransactional(new TransactionOperationCallback() { - public Object performTransactionalOperation() throws Throwable { - return new ImplementsAnnotatedInterface().echo(rollbackProvokingException); - } - }, rollbackProvokingException); - } - - - protected void testRollback(TransactionOperationCallback toc, boolean rollback) throws Throwable { - txManager.clear(); - assertEquals(0, txManager.begun); - try { - toc.performTransactionalOperation(); - assertEquals(1, txManager.commits); - } - catch (Throwable caught) { - if (caught instanceof AssertionFailedError) { - return; - } - } - - if (rollback) { - assertEquals(1, txManager.rollbacks); - } - assertEquals(1, txManager.begun); - } - - protected void testNotTransactional(TransactionOperationCallback toc, Throwable expected) throws Throwable { - txManager.clear(); - assertEquals(0, txManager.begun); - try { - toc.performTransactionalOperation(); - } - catch (Throwable t) { - if (expected == null) { - fail("Expected " + expected); - } - assertSame(expected, t); - } - finally { - assertEquals(0, txManager.begun); - } - } - - - private interface TransactionOperationCallback { - - Object performTransactionalOperation() throws Throwable; - } - -} +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.aspectj; + +import java.lang.reflect.Method; + +import junit.framework.AssertionFailedError; + +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; +import org.springframework.transaction.CallCountingTransactionManager; +import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource; +import org.springframework.transaction.interceptor.TransactionAspectSupport; +import org.springframework.transaction.interceptor.TransactionAttribute; + +/** + * @author Rod Johnson + * @author Ramnivas Laddad + */ +public class TransactionAspectTests extends AbstractDependencyInjectionSpringContextTests { + + private TransactionAspectSupport transactionAspect; + + private CallCountingTransactionManager txManager; + + private TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface; + + private ClassWithProtectedAnnotatedMember beanWithAnnotatedProtectedMethod; + + private ClassWithPrivateAnnotatedMember beanWithAnnotatedPrivateMethod; + + private MethodAnnotationOnClassWithNoInterface methodAnnotationOnly = new MethodAnnotationOnClassWithNoInterface(); + + + public void setAnnotationOnlyOnClassWithNoInterface( + TransactionalAnnotationOnlyOnClassWithNoInterface annotationOnlyOnClassWithNoInterface) { + this.annotationOnlyOnClassWithNoInterface = annotationOnlyOnClassWithNoInterface; + } + + public void setClassWithAnnotatedProtectedMethod(ClassWithProtectedAnnotatedMember aBean) { + this.beanWithAnnotatedProtectedMethod = aBean; + } + + public void setClassWithAnnotatedPrivateMethod(ClassWithPrivateAnnotatedMember aBean) { + this.beanWithAnnotatedPrivateMethod = aBean; + } + + public void setTransactionAspect(TransactionAspectSupport transactionAspect) { + this.transactionAspect = transactionAspect; + this.txManager = (CallCountingTransactionManager) transactionAspect.getTransactionManager(); + } + + public TransactionAspectSupport getTransactionAspect() { + return this.transactionAspect; + } + + @Override + protected String getConfigPath() { + return "TransactionAspectTests-context.xml"; + } + + + public void testCommitOnAnnotatedClass() throws Throwable { + txManager.clear(); + assertEquals(0, txManager.begun); + annotationOnlyOnClassWithNoInterface.echo(null); + assertEquals(1, txManager.commits); + } + + public void testCommitOnAnnotatedProtectedMethod() throws Throwable { + txManager.clear(); + assertEquals(0, txManager.begun); + beanWithAnnotatedProtectedMethod.doInTransaction(); + assertEquals(1, txManager.commits); + } + + public void testCommitOnAnnotatedPrivateMethod() throws Throwable { + txManager.clear(); + assertEquals(0, txManager.begun); + beanWithAnnotatedPrivateMethod.doSomething(); + assertEquals(1, txManager.commits); + } + + public void testNoCommitOnNonAnnotatedNonPublicMethodInTransactionalType() throws Throwable { + txManager.clear(); + assertEquals(0,txManager.begun); + annotationOnlyOnClassWithNoInterface.nonTransactionalMethod(); + assertEquals(0,txManager.begun); + } + + public void testCommitOnAnnotatedMethod() throws Throwable { + txManager.clear(); + assertEquals(0, txManager.begun); + methodAnnotationOnly.echo(null); + assertEquals(1, txManager.commits); + } + + + public static class NotTransactional { + public void noop() { + } + } + + public void testNotTransactional() throws Throwable { + txManager.clear(); + assertEquals(0, txManager.begun); + new NotTransactional().noop(); + assertEquals(0, txManager.begun); + } + + + public void testDefaultCommitOnAnnotatedClass() throws Throwable { + testRollback(new TransactionOperationCallback() { + public Object performTransactionalOperation() throws Throwable { + return annotationOnlyOnClassWithNoInterface.echo(new Exception()); + } + }, false); + } + + public void testDefaultRollbackOnAnnotatedClass() throws Throwable { + testRollback(new TransactionOperationCallback() { + public Object performTransactionalOperation() throws Throwable { + return annotationOnlyOnClassWithNoInterface.echo(new RuntimeException()); + } + }, true); + } + + + public static class SubclassOfClassWithTransactionalAnnotation extends TransactionalAnnotationOnlyOnClassWithNoInterface { + } + + public void testDefaultCommitOnSubclassOfAnnotatedClass() throws Throwable { + testRollback(new TransactionOperationCallback() { + public Object performTransactionalOperation() throws Throwable { + return new SubclassOfClassWithTransactionalAnnotation().echo(new Exception()); + } + }, false); + } + + public static class SubclassOfClassWithTransactionalMethodAnnotation extends MethodAnnotationOnClassWithNoInterface { + } + + public void testDefaultCommitOnSubclassOfClassWithTransactionalMethodAnnotated() throws Throwable { + testRollback(new TransactionOperationCallback() { + public Object performTransactionalOperation() throws Throwable { + return new SubclassOfClassWithTransactionalMethodAnnotation().echo(new Exception()); + } + }, false); + } + + public static class ImplementsAnnotatedInterface implements ITransactional { + public Object echo(Throwable t) throws Throwable { + if (t != null) { + throw t; + } + return t; + } + } + + public void testDefaultCommitOnImplementationOfAnnotatedInterface() throws Throwable { +// testRollback(new TransactionOperationCallback() { +// public Object performTransactionalOperation() throws Throwable { +// return new ImplementsAnnotatedInterface().echo(new Exception()); +// } +// }, false); + + final Exception ex = new Exception(); + testNotTransactional(new TransactionOperationCallback() { + public Object performTransactionalOperation() throws Throwable { + return new ImplementsAnnotatedInterface().echo(ex); + } + }, ex); + } + + /** + * Note: resolution does not occur. Thus we can't make a class transactional if + * it implements a transactionally annotated interface. This behaviour could only + * be changed in AbstractFallbackTransactionAttributeSource in Spring proper. + * @throws SecurityException + * @throws NoSuchMethodException + */ + public void testDoesNotResolveTxAnnotationOnMethodFromClassImplementingAnnotatedInterface() throws SecurityException, NoSuchMethodException { + AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); + Method m = ImplementsAnnotatedInterface.class.getMethod("echo", Throwable.class); + TransactionAttribute ta = atas.getTransactionAttribute(m, ImplementsAnnotatedInterface.class); + assertNull(ta); + } + + + public void testDefaultRollbackOnImplementationOfAnnotatedInterface() throws Throwable { +// testRollback(new TransactionOperationCallback() { +// public Object performTransactionalOperation() throws Throwable { +// return new ImplementsAnnotatedInterface().echo(new RuntimeException()); +// } +// }, true); + + final Exception rollbackProvokingException = new RuntimeException(); + testNotTransactional(new TransactionOperationCallback() { + public Object performTransactionalOperation() throws Throwable { + return new ImplementsAnnotatedInterface().echo(rollbackProvokingException); + } + }, rollbackProvokingException); + } + + + protected void testRollback(TransactionOperationCallback toc, boolean rollback) throws Throwable { + txManager.clear(); + assertEquals(0, txManager.begun); + try { + toc.performTransactionalOperation(); + assertEquals(1, txManager.commits); + } + catch (Throwable caught) { + if (caught instanceof AssertionFailedError) { + return; + } + } + + if (rollback) { + assertEquals(1, txManager.rollbacks); + } + assertEquals(1, txManager.begun); + } + + protected void testNotTransactional(TransactionOperationCallback toc, Throwable expected) throws Throwable { + txManager.clear(); + assertEquals(0, txManager.begun); + try { + toc.performTransactionalOperation(); + } + catch (Throwable t) { + if (expected == null) { + fail("Expected " + expected); + } + assertSame(expected, t); + } + finally { + assertEquals(0, txManager.begun); + } + } + + + private interface TransactionOperationCallback { + + Object performTransactionalOperation() throws Throwable; + } + +} diff --git a/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/TransactionalAnnotationOnlyOnClassWithNoInterface.java b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/TransactionalAnnotationOnlyOnClassWithNoInterface.java index a111f57241..691506baa0 100644 --- a/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/TransactionalAnnotationOnlyOnClassWithNoInterface.java +++ b/org.springframework.aspects/src/test/java/org/springframework/transaction/aspectj/TransactionalAnnotationOnlyOnClassWithNoInterface.java @@ -1,20 +1,20 @@ -package org.springframework.transaction.aspectj; - -import org.springframework.transaction.annotation.Transactional; - -@Transactional -public class TransactionalAnnotationOnlyOnClassWithNoInterface { - - public Object echo(Throwable t) throws Throwable { - if (t != null) { - throw t; - } - return t; - } - - void nonTransactionalMethod() { - // no-op - } - -} - +package org.springframework.transaction.aspectj; + +import org.springframework.transaction.annotation.Transactional; + +@Transactional +public class TransactionalAnnotationOnlyOnClassWithNoInterface { + + public Object echo(Throwable t) throws Throwable { + if (t != null) { + throw t; + } + return t; + } + + void nonTransactionalMethod() { + // no-op + } + +} + diff --git a/org.springframework.aspects/template.mf b/org.springframework.aspects/template.mf index a1cd0a1e91..27543caee4 100644 --- a/org.springframework.aspects/template.mf +++ b/org.springframework.aspects/template.mf @@ -1,20 +1,20 @@ -Bundle-SymbolicName: org.springframework.aspects -Bundle-Name: Spring Aspects -Bundle-Vendor: SpringSource -Bundle-ManifestVersion: 2 -Import-Template: - javax.persistence;version="[1.0.0,3.0.0)";resolution:=optional, - org.apache.commons.logging.*;version="[1.1.1, 2.0.0)", - org.aspectj.*;version=${aj.osgi.range};resolution:=optional, - org.springframework.context.*;version=${spring.osgi.range}, - org.springframework.beans.*;version=${spring.osgi.range}, - org.springframework.cache.*;version=${spring.osgi.range};resolution:=optional, - org.springframework.core.*;version=${spring.osgi.range}, - org.springframework.dao.*;version=${spring.osgi.range};resolution:=optional, - org.springframework.orm.*;version=${spring.osgi.range};resolution:=optional, - org.springframework.scheduling.*;version=${spring.osgi.range};resolution:=optional, - org.springframework.transaction.*;version=${spring.osgi.range};resolution:=optional -Ignored-Existing-Headers: - Bnd-LastModified, - Import-Package, - Tool +Bundle-SymbolicName: org.springframework.aspects +Bundle-Name: Spring Aspects +Bundle-Vendor: SpringSource +Bundle-ManifestVersion: 2 +Import-Template: + javax.persistence;version="[1.0.0,3.0.0)";resolution:=optional, + org.apache.commons.logging.*;version="[1.1.1, 2.0.0)", + org.aspectj.*;version=${aj.osgi.range};resolution:=optional, + org.springframework.context.*;version=${spring.osgi.range}, + org.springframework.beans.*;version=${spring.osgi.range}, + org.springframework.cache.*;version=${spring.osgi.range};resolution:=optional, + org.springframework.core.*;version=${spring.osgi.range}, + org.springframework.dao.*;version=${spring.osgi.range};resolution:=optional, + org.springframework.orm.*;version=${spring.osgi.range};resolution:=optional, + org.springframework.scheduling.*;version=${spring.osgi.range};resolution:=optional, + org.springframework.transaction.*;version=${spring.osgi.range};resolution:=optional +Ignored-Existing-Headers: + Bnd-LastModified, + Import-Package, + Tool diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/Value.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/Value.java index b4e8d0399a..2136666cfb 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/Value.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/annotation/Value.java @@ -1,61 +1,61 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation at the field or method/constructor parameter level - * that indicates a default value expression for the affected argument. - * - *

Typically used for expression-driven dependency injection. Also supported - * for dynamic resolution of handler method parameters, e.g. in Spring MVC. - * - *

A common use case is to assign default field values using - * "#{systemProperties.myProp}" style expressions. - * - *

Note that actual processing of the {@code @Value} annotation is performed - * by a {@link org.springframework.beans.factory.config.BeanPostProcessor - * BeanPostProcessor} which in turn means that you cannot use - * {@code @Value} within - * {@link org.springframework.beans.factory.config.BeanPostProcessor - * BeanPostProcessor} or {@link BeanFactoryPostProcessor} types. Please - * consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor} - * class (which, by default, checks for the presence of this annotation). - * - * @author Juergen Hoeller - * @since 3.0 - * @see AutowiredAnnotationBeanPostProcessor - * @see Autowired - * @see org.springframework.beans.factory.config.BeanExpressionResolver - * @see org.springframework.beans.factory.support.AutowireCandidateResolver#getSuggestedValue - */ -@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface Value { - - /** - * The actual value expression: e.g. "#{systemProperties.myProp}". - */ - String value(); - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation at the field or method/constructor parameter level + * that indicates a default value expression for the affected argument. + * + *

Typically used for expression-driven dependency injection. Also supported + * for dynamic resolution of handler method parameters, e.g. in Spring MVC. + * + *

A common use case is to assign default field values using + * "#{systemProperties.myProp}" style expressions. + * + *

Note that actual processing of the {@code @Value} annotation is performed + * by a {@link org.springframework.beans.factory.config.BeanPostProcessor + * BeanPostProcessor} which in turn means that you cannot use + * {@code @Value} within + * {@link org.springframework.beans.factory.config.BeanPostProcessor + * BeanPostProcessor} or {@link BeanFactoryPostProcessor} types. Please + * consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor} + * class (which, by default, checks for the presence of this annotation). + * + * @author Juergen Hoeller + * @since 3.0 + * @see AutowiredAnnotationBeanPostProcessor + * @see Autowired + * @see org.springframework.beans.factory.config.BeanExpressionResolver + * @see org.springframework.beans.factory.support.AutowireCandidateResolver#getSuggestedValue + */ +@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Value { + + /** + * The actual value expression: e.g. "#{systemProperties.myProp}". + */ + String value(); + +} diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/BeanExpressionContext.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/BeanExpressionContext.java index f74a6ad986..1da52f0e20 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/BeanExpressionContext.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/BeanExpressionContext.java @@ -1,84 +1,84 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.beans.factory.config; - -import org.springframework.util.Assert; - -/** - * Context object for evaluating an expression within a bean definition. - * - * @author Juergen Hoeller - * @since 3.0 - */ -public class BeanExpressionContext { - - private final ConfigurableBeanFactory beanFactory; - - private final Scope scope; - - - public BeanExpressionContext(ConfigurableBeanFactory beanFactory, Scope scope) { - Assert.notNull(beanFactory, "BeanFactory must not be null"); - this.beanFactory = beanFactory; - this.scope = scope; - } - - public final ConfigurableBeanFactory getBeanFactory() { - return this.beanFactory; - } - - public final Scope getScope() { - return this.scope; - } - - - public boolean containsObject(String key) { - return (this.beanFactory.containsBean(key) || - (this.scope != null && this.scope.resolveContextualObject(key) != null)); - } - - public Object getObject(String key) { - if (this.beanFactory.containsBean(key)) { - return this.beanFactory.getBean(key); - } - else if (this.scope != null){ - return this.scope.resolveContextualObject(key); - } - else { - return null; - } - } - - - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - if (!(other instanceof BeanExpressionContext)) { - return false; - } - BeanExpressionContext otherContext = (BeanExpressionContext) other; - return (this.beanFactory == otherContext.beanFactory && this.scope == otherContext.scope); - } - - @Override - public int hashCode() { - return this.beanFactory.hashCode(); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.config; + +import org.springframework.util.Assert; + +/** + * Context object for evaluating an expression within a bean definition. + * + * @author Juergen Hoeller + * @since 3.0 + */ +public class BeanExpressionContext { + + private final ConfigurableBeanFactory beanFactory; + + private final Scope scope; + + + public BeanExpressionContext(ConfigurableBeanFactory beanFactory, Scope scope) { + Assert.notNull(beanFactory, "BeanFactory must not be null"); + this.beanFactory = beanFactory; + this.scope = scope; + } + + public final ConfigurableBeanFactory getBeanFactory() { + return this.beanFactory; + } + + public final Scope getScope() { + return this.scope; + } + + + public boolean containsObject(String key) { + return (this.beanFactory.containsBean(key) || + (this.scope != null && this.scope.resolveContextualObject(key) != null)); + } + + public Object getObject(String key) { + if (this.beanFactory.containsBean(key)) { + return this.beanFactory.getBean(key); + } + else if (this.scope != null){ + return this.scope.resolveContextualObject(key); + } + else { + return null; + } + } + + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof BeanExpressionContext)) { + return false; + } + BeanExpressionContext otherContext = (BeanExpressionContext) other; + return (this.beanFactory == otherContext.beanFactory && this.scope == otherContext.scope); + } + + @Override + public int hashCode() { + return this.beanFactory.hashCode(); + } + +} diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/BeanExpressionResolver.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/BeanExpressionResolver.java index 589417d1a0..3b2604f15a 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/BeanExpressionResolver.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/BeanExpressionResolver.java @@ -1,45 +1,45 @@ -/* - * 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 org.springframework.beans.BeansException; - -/** - * Strategy interface for resolving a value through evaluating it - * as an expression, if applicable. - * - *

A raw {@link org.springframework.beans.factory.BeanFactory} does not - * contain a default implementation of this strategy. However, - * {@link org.springframework.context.ApplicationContext} implementations - * will provide expression support out of the box. - * - * @author Juergen Hoeller - * @since 3.0 - */ -public interface BeanExpressionResolver { - - /** - * Evaluate the given value as an expression, if applicable; - * return the value as-is otherwise. - * @param value the value to check - * @param evalContext the evaluation context - * @return the resolved value (potentially the given value as-is) - * @throws BeansException if evaluation failed - */ - Object evaluate(String value, BeanExpressionContext evalContext) throws BeansException; - -} +/* + * 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 org.springframework.beans.BeansException; + +/** + * Strategy interface for resolving a value through evaluating it + * as an expression, if applicable. + * + *

A raw {@link org.springframework.beans.factory.BeanFactory} does not + * contain a default implementation of this strategy. However, + * {@link org.springframework.context.ApplicationContext} implementations + * will provide expression support out of the box. + * + * @author Juergen Hoeller + * @since 3.0 + */ +public interface BeanExpressionResolver { + + /** + * Evaluate the given value as an expression, if applicable; + * return the value as-is otherwise. + * @param value the value to check + * @param evalContext the evaluation context + * @return the resolved value (potentially the given value as-is) + * @throws BeansException if evaluation failed + */ + Object evaluate(String value, BeanExpressionContext evalContext) throws BeansException; + +} diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ProviderCreatingFactoryBean.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ProviderCreatingFactoryBean.java index 657d4e7bb2..141ca3b17b 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ProviderCreatingFactoryBean.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ProviderCreatingFactoryBean.java @@ -1,95 +1,95 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.beans.factory.config; - -import java.io.Serializable; -import javax.inject.Provider; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.util.Assert; - -/** - * A {@link org.springframework.beans.factory.FactoryBean} implementation that - * returns a value which is a JSR-330 {@link javax.inject.Provider} that in turn - * returns a bean sourced from a {@link org.springframework.beans.factory.BeanFactory}. - * - *

This is basically a JSR-330 compliant variant of Spring's good old - * {@link ObjectFactoryCreatingFactoryBean}. It can be used for traditional - * external dependency injection configuration that targets a property or - * constructor argument of type javax.inject.Provider, as an - * alternative to JSR-330's @Inject annotation-driven approach. - * - * @author Juergen Hoeller - * @since 3.0.2 - * @see javax.inject.Provider - * @see ObjectFactoryCreatingFactoryBean - */ -public class ProviderCreatingFactoryBean extends AbstractFactoryBean { - - private String targetBeanName; - - - /** - * Set the name of the target bean. - *

The target does not have to be a non-singleton bean, but realisticially - * always will be (because if the target bean were a singleton, then said singleton - * bean could simply be injected straight into the dependent object, thus obviating - * the need for the extra level of indirection afforded by this factory approach). - */ - public void setTargetBeanName(String targetBeanName) { - this.targetBeanName = targetBeanName; - } - - @Override - public void afterPropertiesSet() throws Exception { - Assert.hasText(this.targetBeanName, "Property 'targetBeanName' is required"); - super.afterPropertiesSet(); - } - - - @Override - public Class getObjectType() { - return Provider.class; - } - - @Override - protected Provider createInstance() { - return new TargetBeanProvider(getBeanFactory(), this.targetBeanName); - } - - - /** - * Independent inner class - for serialization purposes. - */ - private static class TargetBeanProvider implements Provider, Serializable { - - private final BeanFactory beanFactory; - - private final String targetBeanName; - - public TargetBeanProvider(BeanFactory beanFactory, String targetBeanName) { - this.beanFactory = beanFactory; - this.targetBeanName = targetBeanName; - } - - public Object get() throws BeansException { - return this.beanFactory.getBean(this.targetBeanName); - } - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.config; + +import java.io.Serializable; +import javax.inject.Provider; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.util.Assert; + +/** + * A {@link org.springframework.beans.factory.FactoryBean} implementation that + * returns a value which is a JSR-330 {@link javax.inject.Provider} that in turn + * returns a bean sourced from a {@link org.springframework.beans.factory.BeanFactory}. + * + *

This is basically a JSR-330 compliant variant of Spring's good old + * {@link ObjectFactoryCreatingFactoryBean}. It can be used for traditional + * external dependency injection configuration that targets a property or + * constructor argument of type javax.inject.Provider, as an + * alternative to JSR-330's @Inject annotation-driven approach. + * + * @author Juergen Hoeller + * @since 3.0.2 + * @see javax.inject.Provider + * @see ObjectFactoryCreatingFactoryBean + */ +public class ProviderCreatingFactoryBean extends AbstractFactoryBean { + + private String targetBeanName; + + + /** + * Set the name of the target bean. + *

The target does not have to be a non-singleton bean, but realisticially + * always will be (because if the target bean were a singleton, then said singleton + * bean could simply be injected straight into the dependent object, thus obviating + * the need for the extra level of indirection afforded by this factory approach). + */ + public void setTargetBeanName(String targetBeanName) { + this.targetBeanName = targetBeanName; + } + + @Override + public void afterPropertiesSet() throws Exception { + Assert.hasText(this.targetBeanName, "Property 'targetBeanName' is required"); + super.afterPropertiesSet(); + } + + + @Override + public Class getObjectType() { + return Provider.class; + } + + @Override + protected Provider createInstance() { + return new TargetBeanProvider(getBeanFactory(), this.targetBeanName); + } + + + /** + * Independent inner class - for serialization purposes. + */ + private static class TargetBeanProvider implements Provider, Serializable { + + private final BeanFactory beanFactory; + + private final String targetBeanName; + + public TargetBeanProvider(BeanFactory beanFactory, String targetBeanName) { + this.beanFactory = beanFactory; + this.targetBeanName = targetBeanName; + } + + public Object get() throws BeansException { + return this.beanFactory.getBean(this.targetBeanName); + } + } + +} diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/ManagedArray.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/ManagedArray.java index 63492ea7f3..2be0e4152d 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/ManagedArray.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/ManagedArray.java @@ -1,45 +1,45 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.beans.factory.support; - -import org.springframework.util.Assert; - -/** - * Tag collection class used to hold managed array elements, which may - * include runtime bean references (to be resolved into bean objects). - * - * @author Juergen Hoeller - * @since 3.0 - */ -public class ManagedArray extends ManagedList { - - /** Resolved element type for runtime creation of the target array */ - volatile Class resolvedElementType; - - - /** - * Create a new managed array placeholder. - * @param elementTypeName the target element type as a class name - * @param size the size of the array - */ - public ManagedArray(String elementTypeName, int size) { - super(size); - Assert.notNull(elementTypeName, "elementTypeName must not be null"); - setElementTypeName(elementTypeName); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.support; + +import org.springframework.util.Assert; + +/** + * Tag collection class used to hold managed array elements, which may + * include runtime bean references (to be resolved into bean objects). + * + * @author Juergen Hoeller + * @since 3.0 + */ +public class ManagedArray extends ManagedList { + + /** Resolved element type for runtime creation of the target array */ + volatile Class resolvedElementType; + + + /** + * Create a new managed array placeholder. + * @param elementTypeName the target element type as a class name + * @param size the size of the array + */ + public ManagedArray(String elementTypeName, int size) { + super(size); + Assert.notNull(elementTypeName, "elementTypeName must not be null"); + setElementTypeName(elementTypeName); + } + +} diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/SecurityContextProvider.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/SecurityContextProvider.java index ba09748b53..0403b8900f 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/SecurityContextProvider.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/SecurityContextProvider.java @@ -1,35 +1,35 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.beans.factory.support; - -import java.security.AccessControlContext; - -/** - * Provider of the security context of the code running inside the bean factory. - * - * @author Costin Leau - * @since 3.0 - */ -public interface SecurityContextProvider { - - /** - * Provides a security access control context relevant to a bean factory. - * @return bean factory security control context - */ - AccessControlContext getAccessControlContext(); - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.support; + +import java.security.AccessControlContext; + +/** + * Provider of the security context of the code running inside the bean factory. + * + * @author Costin Leau + * @since 3.0 + */ +public interface SecurityContextProvider { + + /** + * Provides a security access control context relevant to a bean factory. + * @return bean factory security control context + */ + AccessControlContext getAccessControlContext(); + +} diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/SimpleSecurityContextProvider.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/SimpleSecurityContextProvider.java index 14b9d883fe..78b62938da 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/SimpleSecurityContextProvider.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/support/SimpleSecurityContextProvider.java @@ -1,58 +1,58 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.beans.factory.support; - -import java.security.AccessControlContext; -import java.security.AccessController; - -/** - * Simple {@link SecurityContextProvider} implementation. - * - * @author Costin Leau - * @since 3.0 - */ -public class SimpleSecurityContextProvider implements SecurityContextProvider { - - private final AccessControlContext acc; - - - /** - * Construct a new SimpleSecurityContextProvider instance. - *

The security context will be retrieved on each call from the current - * thread. - */ - public SimpleSecurityContextProvider() { - this(null); - } - - /** - * Construct a new SimpleSecurityContextProvider instance. - *

If the given control context is null, the security context will be - * retrieved on each call from the current thread. - * @param acc access control context (can be null) - * @see AccessController#getContext() - */ - public SimpleSecurityContextProvider(AccessControlContext acc) { - this.acc = acc; - } - - - public AccessControlContext getAccessControlContext() { - return (this.acc != null ? acc : AccessController.getContext()); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.support; + +import java.security.AccessControlContext; +import java.security.AccessController; + +/** + * Simple {@link SecurityContextProvider} implementation. + * + * @author Costin Leau + * @since 3.0 + */ +public class SimpleSecurityContextProvider implements SecurityContextProvider { + + private final AccessControlContext acc; + + + /** + * Construct a new SimpleSecurityContextProvider instance. + *

The security context will be retrieved on each call from the current + * thread. + */ + public SimpleSecurityContextProvider() { + this(null); + } + + /** + * Construct a new SimpleSecurityContextProvider instance. + *

If the given control context is null, the security context will be + * retrieved on each call from the current thread. + * @param acc access control context (can be null) + * @see AccessController#getContext() + */ + public SimpleSecurityContextProvider(AccessControlContext acc) { + this.acc = acc; + } + + + public AccessControlContext getAccessControlContext() { + return (this.acc != null ? acc : AccessController.getContext()); + } + +} diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/SimpleConstructorNamespaceHandler.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/SimpleConstructorNamespaceHandler.java index 81d8632bf5..a3656ec8bb 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/SimpleConstructorNamespaceHandler.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/xml/SimpleConstructorNamespaceHandler.java @@ -1,151 +1,151 @@ -/* - * Copyright 2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.beans.factory.xml; - -import java.util.Collection; - -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.BeanDefinitionHolder; -import org.springframework.beans.factory.config.ConstructorArgumentValues; -import org.springframework.beans.factory.config.RuntimeBeanReference; -import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder; -import org.springframework.core.Conventions; -import org.springframework.util.StringUtils; -import org.w3c.dom.Attr; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -/** - * Simple NamespaceHandler implementation that maps custom - * attributes directly through to bean properties. An important point to note is - * that this NamespaceHandler does not have a corresponding schema - * since there is no way to know in advance all possible attribute names. - * - *

- * An example of the usage of this NamespaceHandler is shown below: - * - *

- * <bean id="author" class="..TestBean" c:name="Enescu" c:work-ref="compositions"/>
- * 
- * - * Here the 'c:name' corresponds directly to the 'name - * ' argument declared on the constructor of class 'TestBean'. The - * 'c:work-ref' attributes corresponds to the 'work' - * argument and, rather than being the concrete value, it contains the name of - * the bean that will be considered as a parameter. - * - * Note: This implementation supports only named parameters - there is no - * support for indexes or types. Further more, the names are used as hints by - * the container which, by default, does type introspection. - * - * @see SimplePropertyNamespaceHandler - * @author Costin Leau - */ -public class SimpleConstructorNamespaceHandler implements NamespaceHandler { - - private static final String REF_SUFFIX = "-ref"; - private static final String DELIMITER_PREFIX = "_"; - - public void init() { - } - - public BeanDefinition parse(Element element, ParserContext parserContext) { - parserContext.getReaderContext().error( - "Class [" + getClass().getName() + "] does not support custom elements.", element); - return null; - } - - public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) { - if (node instanceof Attr) { - Attr attr = (Attr) node; - String argName = StringUtils.trimWhitespace(parserContext.getDelegate().getLocalName(attr)); - String argValue = StringUtils.trimWhitespace(attr.getValue()); - - ConstructorArgumentValues cvs = definition.getBeanDefinition().getConstructorArgumentValues(); - boolean ref = false; - - // handle -ref arguments - if (argName.endsWith(REF_SUFFIX)) { - ref = true; - argName = argName.substring(0, argName.length() - REF_SUFFIX.length()); - } - - ValueHolder valueHolder = new ValueHolder(ref ? new RuntimeBeanReference(argValue) : argValue); - valueHolder.setSource(parserContext.getReaderContext().extractSource(attr)); - - // handle "escaped"/"_" arguments - if (argName.startsWith(DELIMITER_PREFIX)) { - String arg = argName.substring(1).trim(); - - // fast default check - if (!StringUtils.hasText(arg)) { - cvs.addGenericArgumentValue(valueHolder); - } - // assume an index otherwise - else { - int index = -1; - try { - index = Integer.parseInt(arg); - } catch (NumberFormatException ex) { - parserContext.getReaderContext().error( - "Constructor argument '" + argName + "' specifies an invalid integer", attr); - } - if (index < 0) { - parserContext.getReaderContext().error( - "Constructor argument '" + argName + "' specifies a negative index", attr); - } - - if (cvs.hasIndexedArgumentValue(index)){ - parserContext.getReaderContext().error( - "Constructor argument '" + argName + "' with index "+ index+" already defined using ." + - " Only one approach may be used per argument.", attr); - } - - cvs.addIndexedArgumentValue(index, valueHolder); - } - } - // no escaping -> ctr name - else { - String name = Conventions.attributeNameToPropertyName(argName); - if (containsArgWithName(name, cvs)){ - parserContext.getReaderContext().error( - "Constructor argument '" + argName + "' already defined using ." + - " Only one approach may be used per argument.", attr); - } - valueHolder.setName(Conventions.attributeNameToPropertyName(argName)); - cvs.addGenericArgumentValue(valueHolder); - } - } - return definition; - } - - private boolean containsArgWithName(String name, ConstructorArgumentValues cvs) { - if (!checkName(name, cvs.getGenericArgumentValues())) { - return checkName(name, cvs.getIndexedArgumentValues().values()); - } - - return true; - } - - private boolean checkName(String name, Collection values) { - for (ValueHolder holder : values) { - if (name.equals(holder.getName())) { - return true; - } - } - return false; - } +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.beans.factory.xml; + +import java.util.Collection; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.config.ConstructorArgumentValues; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder; +import org.springframework.core.Conventions; +import org.springframework.util.StringUtils; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * Simple NamespaceHandler implementation that maps custom + * attributes directly through to bean properties. An important point to note is + * that this NamespaceHandler does not have a corresponding schema + * since there is no way to know in advance all possible attribute names. + * + *

+ * An example of the usage of this NamespaceHandler is shown below: + * + *

+ * <bean id="author" class="..TestBean" c:name="Enescu" c:work-ref="compositions"/>
+ * 
+ * + * Here the 'c:name' corresponds directly to the 'name + * ' argument declared on the constructor of class 'TestBean'. The + * 'c:work-ref' attributes corresponds to the 'work' + * argument and, rather than being the concrete value, it contains the name of + * the bean that will be considered as a parameter. + * + * Note: This implementation supports only named parameters - there is no + * support for indexes or types. Further more, the names are used as hints by + * the container which, by default, does type introspection. + * + * @see SimplePropertyNamespaceHandler + * @author Costin Leau + */ +public class SimpleConstructorNamespaceHandler implements NamespaceHandler { + + private static final String REF_SUFFIX = "-ref"; + private static final String DELIMITER_PREFIX = "_"; + + public void init() { + } + + public BeanDefinition parse(Element element, ParserContext parserContext) { + parserContext.getReaderContext().error( + "Class [" + getClass().getName() + "] does not support custom elements.", element); + return null; + } + + public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) { + if (node instanceof Attr) { + Attr attr = (Attr) node; + String argName = StringUtils.trimWhitespace(parserContext.getDelegate().getLocalName(attr)); + String argValue = StringUtils.trimWhitespace(attr.getValue()); + + ConstructorArgumentValues cvs = definition.getBeanDefinition().getConstructorArgumentValues(); + boolean ref = false; + + // handle -ref arguments + if (argName.endsWith(REF_SUFFIX)) { + ref = true; + argName = argName.substring(0, argName.length() - REF_SUFFIX.length()); + } + + ValueHolder valueHolder = new ValueHolder(ref ? new RuntimeBeanReference(argValue) : argValue); + valueHolder.setSource(parserContext.getReaderContext().extractSource(attr)); + + // handle "escaped"/"_" arguments + if (argName.startsWith(DELIMITER_PREFIX)) { + String arg = argName.substring(1).trim(); + + // fast default check + if (!StringUtils.hasText(arg)) { + cvs.addGenericArgumentValue(valueHolder); + } + // assume an index otherwise + else { + int index = -1; + try { + index = Integer.parseInt(arg); + } catch (NumberFormatException ex) { + parserContext.getReaderContext().error( + "Constructor argument '" + argName + "' specifies an invalid integer", attr); + } + if (index < 0) { + parserContext.getReaderContext().error( + "Constructor argument '" + argName + "' specifies a negative index", attr); + } + + if (cvs.hasIndexedArgumentValue(index)){ + parserContext.getReaderContext().error( + "Constructor argument '" + argName + "' with index "+ index+" already defined using ." + + " Only one approach may be used per argument.", attr); + } + + cvs.addIndexedArgumentValue(index, valueHolder); + } + } + // no escaping -> ctr name + else { + String name = Conventions.attributeNameToPropertyName(argName); + if (containsArgWithName(name, cvs)){ + parserContext.getReaderContext().error( + "Constructor argument '" + argName + "' already defined using ." + + " Only one approach may be used per argument.", attr); + } + valueHolder.setName(Conventions.attributeNameToPropertyName(argName)); + cvs.addGenericArgumentValue(valueHolder); + } + } + return definition; + } + + private boolean containsArgWithName(String name, ConstructorArgumentValues cvs) { + if (!checkName(name, cvs.getGenericArgumentValues())) { + return checkName(name, cvs.getIndexedArgumentValues().values()); + } + + return true; + } + + private boolean checkName(String name, Collection values) { + for (ValueHolder holder : values) { + if (name.equals(holder.getName())) { + return true; + } + } + return false; + } } \ No newline at end of file diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/propertyeditors/CurrencyEditor.java b/org.springframework.beans/src/main/java/org/springframework/beans/propertyeditors/CurrencyEditor.java index 004d8ed283..910016ac86 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/propertyeditors/CurrencyEditor.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/propertyeditors/CurrencyEditor.java @@ -1,43 +1,43 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.propertyeditors; - -import java.beans.PropertyEditorSupport; -import java.util.Currency; - -/** - * Editor for java.util.Currency, translating currency codes into Currency - * objects. Exposes the currency code as text representation of a Currency object. - * - * @author Juergen Hoeller - * @since 3.0 - * @see java.util.Currency - */ -public class CurrencyEditor extends PropertyEditorSupport { - - @Override - public void setAsText(String text) throws IllegalArgumentException { - setValue(Currency.getInstance(text)); - } - - @Override - public String getAsText() { - Currency value = (Currency) getValue(); - return (value != null ? value.getCurrencyCode() : ""); - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.propertyeditors; + +import java.beans.PropertyEditorSupport; +import java.util.Currency; + +/** + * Editor for java.util.Currency, translating currency codes into Currency + * objects. Exposes the currency code as text representation of a Currency object. + * + * @author Juergen Hoeller + * @since 3.0 + * @see java.util.Currency + */ +public class CurrencyEditor extends PropertyEditorSupport { + + @Override + public void setAsText(String text) throws IllegalArgumentException { + setValue(Currency.getInstance(text)); + } + + @Override + public String getAsText() { + Currency value = (Currency) getValue(); + return (value != null ? value.getCurrencyCode() : ""); + } + +} diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/propertyeditors/TimeZoneEditor.java b/org.springframework.beans/src/main/java/org/springframework/beans/propertyeditors/TimeZoneEditor.java index 323f4ca4c9..832488ffaf 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/propertyeditors/TimeZoneEditor.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/propertyeditors/TimeZoneEditor.java @@ -1,46 +1,46 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.beans.propertyeditors; - -import java.beans.PropertyEditorSupport; -import java.util.TimeZone; - -/** - * Editor for java.util.TimeZone, translating timezone IDs into - * TimeZone objects. Does not expose a text representation for TimeZone objects. - * - * @author Juergen Hoeller - * @since 3.0 - * @see java.util.TimeZone - */ -public class TimeZoneEditor extends PropertyEditorSupport { - - @Override - public void setAsText(String text) throws IllegalArgumentException { - setValue(TimeZone.getTimeZone(text)); - } - - /** - * This implementation returns null to indicate that - * there is no appropriate text representation. - */ - @Override - public String getAsText() { - return null; - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.propertyeditors; + +import java.beans.PropertyEditorSupport; +import java.util.TimeZone; + +/** + * Editor for java.util.TimeZone, translating timezone IDs into + * TimeZone objects. Does not expose a text representation for TimeZone objects. + * + * @author Juergen Hoeller + * @since 3.0 + * @see java.util.TimeZone + */ +public class TimeZoneEditor extends PropertyEditorSupport { + + @Override + public void setAsText(String text) throws IllegalArgumentException { + setValue(TimeZone.getTimeZone(text)); + } + + /** + * This implementation returns null to indicate that + * there is no appropriate text representation. + */ + @Override + public String getAsText() { + return null; + } + +} diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/propertyeditors/UUIDEditor.java b/org.springframework.beans/src/main/java/org/springframework/beans/propertyeditors/UUIDEditor.java index 885676962b..98c9ea54f5 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/propertyeditors/UUIDEditor.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/propertyeditors/UUIDEditor.java @@ -1,50 +1,50 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.beans.propertyeditors; - -import java.beans.PropertyEditorSupport; -import java.util.UUID; - -import org.springframework.util.StringUtils; - -/** - * Editor for java.util.UUID, translating UUID - * String representations into UUID objects and back. - * - * @author Juergen Hoeller - * @since 3.0.1 - * @see java.util.UUID - */ -public class UUIDEditor extends PropertyEditorSupport { - - @Override - public void setAsText(String text) throws IllegalArgumentException { - if (StringUtils.hasText(text)) { - setValue(UUID.fromString(text)); - } - else { - setValue(null); - } - } - - @Override - public String getAsText() { - UUID value = (UUID) getValue(); - return (value != null ? value.toString() : ""); - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.propertyeditors; + +import java.beans.PropertyEditorSupport; +import java.util.UUID; + +import org.springframework.util.StringUtils; + +/** + * Editor for java.util.UUID, translating UUID + * String representations into UUID objects and back. + * + * @author Juergen Hoeller + * @since 3.0.1 + * @see java.util.UUID + */ +public class UUIDEditor extends PropertyEditorSupport { + + @Override + public void setAsText(String text) throws IllegalArgumentException { + if (StringUtils.hasText(text)) { + setValue(UUID.fromString(text)); + } + else { + setValue(null); + } + } + + @Override + public String getAsText() { + UUID value = (UUID) getValue(); + return (value != null ? value.toString() : ""); + } + +} diff --git a/org.springframework.beans/src/test/java/com/foo/Component.java b/org.springframework.beans/src/test/java/com/foo/Component.java index 20d7d7e3c7..5c5d61ec81 100644 --- a/org.springframework.beans/src/test/java/com/foo/Component.java +++ b/org.springframework.beans/src/test/java/com/foo/Component.java @@ -1,26 +1,26 @@ -package com.foo; - -import java.util.ArrayList; -import java.util.List; - -public class Component { - private String name; - private List components = new ArrayList(); - - // mmm, there is no setter method for the 'components' - public void addComponent(Component component) { - this.components.add(component); - } - - public List getComponents() { - return components; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} +package com.foo; + +import java.util.ArrayList; +import java.util.List; + +public class Component { + private String name; + private List components = new ArrayList(); + + // mmm, there is no setter method for the 'components' + public void addComponent(Component component) { + this.components.add(component); + } + + public List getComponents() { + return components; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/org.springframework.beans/src/test/java/com/foo/ComponentBeanDefinitionParser.java b/org.springframework.beans/src/test/java/com/foo/ComponentBeanDefinitionParser.java index 519d2a6bc5..3483077e85 100644 --- a/org.springframework.beans/src/test/java/com/foo/ComponentBeanDefinitionParser.java +++ b/org.springframework.beans/src/test/java/com/foo/ComponentBeanDefinitionParser.java @@ -1,52 +1,52 @@ -package com.foo; - -import java.util.List; - -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.support.AbstractBeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.ManagedList; -import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.util.xml.DomUtils; -import org.w3c.dom.Element; - -public class ComponentBeanDefinitionParser extends AbstractBeanDefinitionParser { - - protected AbstractBeanDefinition parseInternal(Element element, - ParserContext parserContext) { - return parseComponentElement(element); - } - - private static AbstractBeanDefinition parseComponentElement(Element element) { - BeanDefinitionBuilder factory = BeanDefinitionBuilder - .rootBeanDefinition(ComponentFactoryBean.class); - - factory.addPropertyValue("parent", parseComponent(element)); - - List childElements = DomUtils.getChildElementsByTagName( - element, "component"); - if (childElements != null && childElements.size() > 0) { - parseChildComponents(childElements, factory); - } - - return factory.getBeanDefinition(); - } - - private static BeanDefinition parseComponent(Element element) { - BeanDefinitionBuilder component = BeanDefinitionBuilder - .rootBeanDefinition(Component.class); - component.addPropertyValue("name", element.getAttribute("name")); - return component.getBeanDefinition(); - } - - private static void parseChildComponents(List childElements, - BeanDefinitionBuilder factory) { - ManagedList children = new ManagedList( - childElements.size()); - for (Element element : childElements) { - children.add(parseComponentElement(element)); - } - factory.addPropertyValue("children", children); - } -} +package com.foo; + +import java.util.List; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Element; + +public class ComponentBeanDefinitionParser extends AbstractBeanDefinitionParser { + + protected AbstractBeanDefinition parseInternal(Element element, + ParserContext parserContext) { + return parseComponentElement(element); + } + + private static AbstractBeanDefinition parseComponentElement(Element element) { + BeanDefinitionBuilder factory = BeanDefinitionBuilder + .rootBeanDefinition(ComponentFactoryBean.class); + + factory.addPropertyValue("parent", parseComponent(element)); + + List childElements = DomUtils.getChildElementsByTagName( + element, "component"); + if (childElements != null && childElements.size() > 0) { + parseChildComponents(childElements, factory); + } + + return factory.getBeanDefinition(); + } + + private static BeanDefinition parseComponent(Element element) { + BeanDefinitionBuilder component = BeanDefinitionBuilder + .rootBeanDefinition(Component.class); + component.addPropertyValue("name", element.getAttribute("name")); + return component.getBeanDefinition(); + } + + private static void parseChildComponents(List childElements, + BeanDefinitionBuilder factory) { + ManagedList children = new ManagedList( + childElements.size()); + for (Element element : childElements) { + children.add(parseComponentElement(element)); + } + factory.addPropertyValue("children", children); + } +} diff --git a/org.springframework.beans/src/test/java/com/foo/ComponentBeanDefinitionParserTest.java b/org.springframework.beans/src/test/java/com/foo/ComponentBeanDefinitionParserTest.java index 9b0cf6f5cb..aec54454ec 100644 --- a/org.springframework.beans/src/test/java/com/foo/ComponentBeanDefinitionParserTest.java +++ b/org.springframework.beans/src/test/java/com/foo/ComponentBeanDefinitionParserTest.java @@ -1,74 +1,74 @@ -/* - * Copyright 2006-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.foo; - -import java.util.List; - -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.springframework.beans.factory.xml.XmlBeanFactory; -import org.springframework.core.io.ClassPathResource; - -import static org.junit.Assert.*; -import static org.hamcrest.CoreMatchers.*; - -/** - * @author Costin Leau - */ -public class ComponentBeanDefinitionParserTest { - - private static XmlBeanFactory bf; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - bf = new XmlBeanFactory(new ClassPathResource( - "com/foo/component-config.xml")); - } - - @AfterClass - public static void tearDownAfterClass() throws Exception { - bf.destroySingletons(); - } - - private Component getBionicFamily() { - return bf.getBean("bionic-family", Component.class); - } - - @Test - public void testBionicBasic() throws Exception { - Component cp = getBionicFamily(); - assertThat("Bionic-1", equalTo(cp.getName())); - } - - @Test - public void testBionicFirstLevelChildren() throws Exception { - Component cp = getBionicFamily(); - List components = cp.getComponents(); - assertThat(2, equalTo(components.size())); - assertThat("Mother-1", equalTo(components.get(0).getName())); - assertThat("Rock-1", equalTo(components.get(1).getName())); - } - - @Test - public void testBionicSecondLevenChildren() throws Exception { - Component cp = getBionicFamily(); - List components = cp.getComponents().get(0).getComponents(); - assertThat(2, equalTo(components.size())); - assertThat("Karate-1", equalTo(components.get(0).getName())); - assertThat("Sport-1", equalTo(components.get(1).getName())); - } +/* + * Copyright 2006-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.foo; + +import java.util.List; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.core.io.ClassPathResource; + +import static org.junit.Assert.*; +import static org.hamcrest.CoreMatchers.*; + +/** + * @author Costin Leau + */ +public class ComponentBeanDefinitionParserTest { + + private static XmlBeanFactory bf; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + bf = new XmlBeanFactory(new ClassPathResource( + "com/foo/component-config.xml")); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + bf.destroySingletons(); + } + + private Component getBionicFamily() { + return bf.getBean("bionic-family", Component.class); + } + + @Test + public void testBionicBasic() throws Exception { + Component cp = getBionicFamily(); + assertThat("Bionic-1", equalTo(cp.getName())); + } + + @Test + public void testBionicFirstLevelChildren() throws Exception { + Component cp = getBionicFamily(); + List components = cp.getComponents(); + assertThat(2, equalTo(components.size())); + assertThat("Mother-1", equalTo(components.get(0).getName())); + assertThat("Rock-1", equalTo(components.get(1).getName())); + } + + @Test + public void testBionicSecondLevenChildren() throws Exception { + Component cp = getBionicFamily(); + List components = cp.getComponents().get(0).getComponents(); + assertThat(2, equalTo(components.size())); + assertThat("Karate-1", equalTo(components.get(0).getName())); + assertThat("Sport-1", equalTo(components.get(1).getName())); + } } \ No newline at end of file diff --git a/org.springframework.beans/src/test/java/com/foo/ComponentFactoryBean.java b/org.springframework.beans/src/test/java/com/foo/ComponentFactoryBean.java index dbc7a03472..e62eab786e 100644 --- a/org.springframework.beans/src/test/java/com/foo/ComponentFactoryBean.java +++ b/org.springframework.beans/src/test/java/com/foo/ComponentFactoryBean.java @@ -1,35 +1,35 @@ -package com.foo; - -import java.util.List; - -import org.springframework.beans.factory.FactoryBean; - -public class ComponentFactoryBean implements FactoryBean { - private Component parent; - private List children; - - public void setParent(Component parent) { - this.parent = parent; - } - - public void setChildren(List children) { - this.children = children; - } - - public Component getObject() throws Exception { - if (this.children != null && this.children.size() > 0) { - for (Component child : children) { - this.parent.addComponent(child); - } - } - return this.parent; - } - - public Class getObjectType() { - return Component.class; - } - - public boolean isSingleton() { - return true; - } -} +package com.foo; + +import java.util.List; + +import org.springframework.beans.factory.FactoryBean; + +public class ComponentFactoryBean implements FactoryBean { + private Component parent; + private List children; + + public void setParent(Component parent) { + this.parent = parent; + } + + public void setChildren(List children) { + this.children = children; + } + + public Component getObject() throws Exception { + if (this.children != null && this.children.size() > 0) { + for (Component child : children) { + this.parent.addComponent(child); + } + } + return this.parent; + } + + public Class getObjectType() { + return Component.class; + } + + public boolean isSingleton() { + return true; + } +} diff --git a/org.springframework.beans/src/test/java/com/foo/ComponentNamespaceHandler.java b/org.springframework.beans/src/test/java/com/foo/ComponentNamespaceHandler.java index aff5ab6a8d..3ccc7f167b 100644 --- a/org.springframework.beans/src/test/java/com/foo/ComponentNamespaceHandler.java +++ b/org.springframework.beans/src/test/java/com/foo/ComponentNamespaceHandler.java @@ -1,10 +1,10 @@ -package com.foo; - -import org.springframework.beans.factory.xml.NamespaceHandlerSupport; - -public class ComponentNamespaceHandler extends NamespaceHandlerSupport { - public void init() { - registerBeanDefinitionParser("component", - new ComponentBeanDefinitionParser()); - } -} +package com.foo; + +import org.springframework.beans.factory.xml.NamespaceHandlerSupport; + +public class ComponentNamespaceHandler extends NamespaceHandlerSupport { + public void init() { + registerBeanDefinitionParser("component", + new ComponentBeanDefinitionParser()); + } +} diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/CallbacksSecurityTests.java b/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/CallbacksSecurityTests.java index e48bcc5bec..d0bec20491 100644 --- a/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/CallbacksSecurityTests.java +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/CallbacksSecurityTests.java @@ -1,525 +1,525 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.beans.factory.support.security; - -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertNull; -import static junit.framework.Assert.assertTrue; -import static junit.framework.Assert.fail; - -import java.lang.reflect.Method; -import java.net.URL; -import java.security.AccessControlContext; -import java.security.AccessController; -import java.security.Permissions; -import java.security.Policy; -import java.security.Principal; -import java.security.PrivilegedAction; -import java.security.PrivilegedExceptionAction; -import java.security.ProtectionDomain; -import java.util.PropertyPermission; -import java.util.Set; - -import javax.security.auth.AuthPermission; -import javax.security.auth.Subject; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.beans.factory.BeanCreationException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.BeanNameAware; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.SmartFactoryBean; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.beans.factory.support.SecurityContextProvider; -import org.springframework.beans.factory.support.security.support.ConstructorBean; -import org.springframework.beans.factory.support.security.support.CustomCallbackBean; -import org.springframework.beans.factory.xml.XmlBeanFactory; -import org.springframework.core.io.DefaultResourceLoader; -import org.springframework.core.io.Resource; - -/** - * Security test case. Checks whether the container uses its privileges for its - * internal work but does not leak them when touching/calling user code. - * - *t The first half of the test case checks that permissions are downgraded when - * calling user code while the second half that the caller code permission get - * through and Spring doesn't override the permission stack. - * - * @author Costin Leau - */ -public class CallbacksSecurityTests { - - private XmlBeanFactory beanFactory; - private SecurityContextProvider provider; - - private static class NonPrivilegedBean { - - private String expectedName; - public static boolean destroyed = false; - - public NonPrivilegedBean(String expected) { - this.expectedName = expected; - checkCurrentContext(); - } - - public void init() { - checkCurrentContext(); - } - - public void destroy() { - checkCurrentContext(); - destroyed = true; - } - - public void setProperty(Object value) { - checkCurrentContext(); - } - - public Object getProperty() { - checkCurrentContext(); - return null; - } - - public void setListProperty(Object value) { - checkCurrentContext(); - } - - public Object getListProperty() { - checkCurrentContext(); - return null; - } - - private void checkCurrentContext() { - assertEquals(expectedName, getCurrentSubjectName()); - } - } - - private static class NonPrivilegedSpringCallbacksBean implements - InitializingBean, DisposableBean, BeanClassLoaderAware, - BeanFactoryAware, BeanNameAware { - - private String expectedName; - public static boolean destroyed = false; - - public NonPrivilegedSpringCallbacksBean(String expected) { - this.expectedName = expected; - checkCurrentContext(); - } - - public void afterPropertiesSet() { - checkCurrentContext(); - } - - public void destroy() { - checkCurrentContext(); - destroyed = true; - } - - public void setBeanName(String name) { - checkCurrentContext(); - } - - public void setBeanClassLoader(ClassLoader classLoader) { - checkCurrentContext(); - } - - public void setBeanFactory(BeanFactory beanFactory) - throws BeansException { - checkCurrentContext(); - } - - private void checkCurrentContext() { - assertEquals(expectedName, getCurrentSubjectName()); - } - } - - private static class NonPrivilegedFactoryBean implements SmartFactoryBean { - private String expectedName; - - public NonPrivilegedFactoryBean(String expected) { - this.expectedName = expected; - checkCurrentContext(); - } - - public boolean isEagerInit() { - checkCurrentContext(); - return false; - } - - public boolean isPrototype() { - checkCurrentContext(); - return true; - } - - public Object getObject() throws Exception { - checkCurrentContext(); - return new Object(); - } - - public Class getObjectType() { - checkCurrentContext(); - return Object.class; - } - - public boolean isSingleton() { - checkCurrentContext(); - return false; - } - - private void checkCurrentContext() { - assertEquals(expectedName, getCurrentSubjectName()); - } - } - - private static class NonPrivilegedFactory { - - private final String expectedName; - - public NonPrivilegedFactory(String expected) { - this.expectedName = expected; - assertEquals(expectedName, getCurrentSubjectName()); - } - - public static Object makeStaticInstance(String expectedName) { - assertEquals(expectedName, getCurrentSubjectName()); - return new Object(); - } - - public Object makeInstance() { - assertEquals(expectedName, getCurrentSubjectName()); - return new Object(); - } - } - - private static String getCurrentSubjectName() { - final AccessControlContext acc = AccessController.getContext(); - - return AccessController.doPrivileged(new PrivilegedAction() { - - public String run() { - Subject subject = Subject.getSubject(acc); - if (subject == null) { - return null; - } - - Set principals = subject.getPrincipals(); - - if (principals == null) { - return null; - } - for (Principal p : principals) { - return p.getName(); - } - return null; - } - }); - } - - private static class TestPrincipal implements Principal { - - private String name; - - public TestPrincipal(String name) { - this.name = name; - } - - public String getName() { - return this.name; - } - - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - if (!(obj instanceof TestPrincipal)) { - return false; - } - TestPrincipal p = (TestPrincipal) obj; - return this.name.equals(p.name); - } - - public int hashCode() { - return this.name.hashCode(); - } - } - - public CallbacksSecurityTests() { - // setup security - if (System.getSecurityManager() == null) { - Policy policy = Policy.getPolicy(); - URL policyURL = getClass() - .getResource( - "/org/springframework/beans/factory/support/security/policy.all"); - System.setProperty("java.security.policy", policyURL.toString()); - System.setProperty("policy.allowSystemProperty", "true"); - policy.refresh(); - - System.setSecurityManager(new SecurityManager()); - } - } - - @Before - public void setUp() throws Exception { - - final ProtectionDomain empty = new ProtectionDomain(null, - new Permissions()); - - provider = new SecurityContextProvider() { - private final AccessControlContext acc = new AccessControlContext( - new ProtectionDomain[] { empty }); - - public AccessControlContext getAccessControlContext() { - return acc; - } - }; - - DefaultResourceLoader drl = new DefaultResourceLoader(); - Resource config = drl - .getResource("/org/springframework/beans/factory/support/security/callbacks.xml"); - beanFactory = new XmlBeanFactory(config); - beanFactory.setSecurityContextProvider(provider); - } - - @Test - public void testSecuritySanity() throws Exception { - AccessControlContext acc = provider.getAccessControlContext(); - try { - acc.checkPermission(new PropertyPermission("*", "read")); - fail("Acc should not have any permissions"); - } catch (SecurityException se) { - // expected - } - - final CustomCallbackBean bean = new CustomCallbackBean(); - final Method method = bean.getClass().getMethod("destroy", null); - method.setAccessible(true); - - try { - AccessController.doPrivileged(new PrivilegedExceptionAction() { - - public Object run() throws Exception { - method.invoke(bean, null); - return null; - } - }, acc); - fail("expected security exception"); - } catch (Exception ex) { - } - - final Class cl = ConstructorBean.class; - try { - AccessController.doPrivileged( - new PrivilegedExceptionAction() { - - public Object run() throws Exception { - return cl.newInstance(); - } - }, acc); - fail("expected security exception"); - } catch (Exception ex) { - } - } - - @Test - public void testSpringInitBean() throws Exception { - try { - beanFactory.getBean("spring-init"); - fail("expected security exception"); - } catch (BeanCreationException ex) { - assertTrue(ex.getCause() instanceof SecurityException); - } - } - - @Test - public void testCustomInitBean() throws Exception { - try { - beanFactory.getBean("custom-init"); - fail("expected security exception"); - } catch (BeanCreationException ex) { - assertTrue(ex.getCause() instanceof SecurityException); - } - } - - @Test - public void testSpringDestroyBean() throws Exception { - beanFactory.getBean("spring-destroy"); - beanFactory.destroySingletons(); - assertNull(System.getProperty("security.destroy")); - } - - @Test - public void testCustomDestroyBean() throws Exception { - beanFactory.getBean("custom-destroy"); - beanFactory.destroySingletons(); - assertNull(System.getProperty("security.destroy")); - } - - @Test - public void testCustomFactoryObject() throws Exception { - try { - beanFactory.getBean("spring-factory"); - fail("expected security exception"); - } catch (BeanCreationException ex) { - assertTrue(ex.getCause() instanceof SecurityException); - } - - } - - @Test - public void testCustomFactoryType() throws Exception { - assertNull(beanFactory.getType("spring-factory")); - assertNull(System.getProperty("factory.object.type")); - } - - @Test - public void testCustomStaticFactoryMethod() throws Exception { - try { - beanFactory.getBean("custom-static-factory-method"); - fail("expected security exception"); - } catch (BeanCreationException ex) { - assertTrue(ex.getMostSpecificCause() instanceof SecurityException); - } - } - - @Test - public void testCustomInstanceFactoryMethod() throws Exception { - try { - beanFactory.getBean("custom-factory-method"); - fail("expected security exception"); - } catch (BeanCreationException ex) { - assertTrue(ex.getMostSpecificCause() instanceof SecurityException); - } - } - - @Test - public void testTrustedFactoryMethod() throws Exception { - try { - beanFactory.getBean("privileged-static-factory-method"); - fail("expected security exception"); - } catch (BeanCreationException ex) { - assertTrue(ex.getMostSpecificCause() instanceof SecurityException); - } - } - - @Test - public void testConstructor() throws Exception { - try { - beanFactory.getBean("constructor"); - fail("expected security exception"); - } catch (BeanCreationException ex) { - // expected - assertTrue(ex.getMostSpecificCause() instanceof SecurityException); - } - } - - @Test - public void testContainerPriviledges() throws Exception { - AccessControlContext acc = provider.getAccessControlContext(); - - AccessController.doPrivileged(new PrivilegedExceptionAction() { - - public Object run() throws Exception { - beanFactory.getBean("working-factory-method"); - beanFactory.getBean("container-execution"); - return null; - } - }, acc); - } - - @Test - public void testPropertyInjection() throws Exception { - try { - beanFactory.getBean("property-injection"); - fail("expected security exception"); - } catch (BeanCreationException ex) { - assertTrue(ex.getMessage().contains("security")); - } - - beanFactory.getBean("working-property-injection"); - } - - @Test - public void testInitSecurityAwarePrototypeBean() { - final DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); - BeanDefinitionBuilder bdb = BeanDefinitionBuilder - .genericBeanDefinition(NonPrivilegedBean.class).setScope( - ConfigurableBeanFactory.SCOPE_PROTOTYPE) - .setInitMethodName("init").setDestroyMethodName("destroy") - .addConstructorArgValue("user1"); - lbf.registerBeanDefinition("test", bdb.getBeanDefinition()); - final Subject subject = new Subject(); - subject.getPrincipals().add(new TestPrincipal("user1")); - - NonPrivilegedBean bean = Subject.doAsPrivileged( - subject, new PrivilegedAction() { - public NonPrivilegedBean run() { - return lbf.getBean("test", NonPrivilegedBean.class); - } - }, null); - assertNotNull(bean); - } - - @Test - public void testTrustedExecution() throws Exception { - beanFactory.setSecurityContextProvider(null); - - Permissions perms = new Permissions(); - perms.add(new AuthPermission("getSubject")); - ProtectionDomain pd = new ProtectionDomain(null, perms); - - AccessControlContext acc = new AccessControlContext( - new ProtectionDomain[] { pd }); - - final Subject subject = new Subject(); - subject.getPrincipals().add(new TestPrincipal("user1")); - - // request the beans from non-privileged code - Subject.doAsPrivileged(subject, new PrivilegedAction() { - - public Object run() { - // sanity check - assertEquals("user1", getCurrentSubjectName()); - assertEquals(false, NonPrivilegedBean.destroyed); - - beanFactory.getBean("trusted-spring-callbacks"); - beanFactory.getBean("trusted-custom-init-destroy"); - // the factory is a prototype - ask for multiple instances - beanFactory.getBean("trusted-spring-factory"); - beanFactory.getBean("trusted-spring-factory"); - beanFactory.getBean("trusted-spring-factory"); - - beanFactory.getBean("trusted-factory-bean"); - beanFactory.getBean("trusted-static-factory-method"); - beanFactory.getBean("trusted-factory-method"); - beanFactory.getBean("trusted-property-injection"); - beanFactory.getBean("trusted-working-property-injection"); - - beanFactory.destroySingletons(); - assertEquals(true, NonPrivilegedBean.destroyed); - return null; - } - }, provider.getAccessControlContext()); - } +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.support.security; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertNull; +import static junit.framework.Assert.assertTrue; +import static junit.framework.Assert.fail; + +import java.lang.reflect.Method; +import java.net.URL; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.Permissions; +import java.security.Policy; +import java.security.Principal; +import java.security.PrivilegedAction; +import java.security.PrivilegedExceptionAction; +import java.security.ProtectionDomain; +import java.util.PropertyPermission; +import java.util.Set; + +import javax.security.auth.AuthPermission; +import javax.security.auth.Subject; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.SmartFactoryBean; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.SecurityContextProvider; +import org.springframework.beans.factory.support.security.support.ConstructorBean; +import org.springframework.beans.factory.support.security.support.CustomCallbackBean; +import org.springframework.beans.factory.xml.XmlBeanFactory; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.Resource; + +/** + * Security test case. Checks whether the container uses its privileges for its + * internal work but does not leak them when touching/calling user code. + * + *t The first half of the test case checks that permissions are downgraded when + * calling user code while the second half that the caller code permission get + * through and Spring doesn't override the permission stack. + * + * @author Costin Leau + */ +public class CallbacksSecurityTests { + + private XmlBeanFactory beanFactory; + private SecurityContextProvider provider; + + private static class NonPrivilegedBean { + + private String expectedName; + public static boolean destroyed = false; + + public NonPrivilegedBean(String expected) { + this.expectedName = expected; + checkCurrentContext(); + } + + public void init() { + checkCurrentContext(); + } + + public void destroy() { + checkCurrentContext(); + destroyed = true; + } + + public void setProperty(Object value) { + checkCurrentContext(); + } + + public Object getProperty() { + checkCurrentContext(); + return null; + } + + public void setListProperty(Object value) { + checkCurrentContext(); + } + + public Object getListProperty() { + checkCurrentContext(); + return null; + } + + private void checkCurrentContext() { + assertEquals(expectedName, getCurrentSubjectName()); + } + } + + private static class NonPrivilegedSpringCallbacksBean implements + InitializingBean, DisposableBean, BeanClassLoaderAware, + BeanFactoryAware, BeanNameAware { + + private String expectedName; + public static boolean destroyed = false; + + public NonPrivilegedSpringCallbacksBean(String expected) { + this.expectedName = expected; + checkCurrentContext(); + } + + public void afterPropertiesSet() { + checkCurrentContext(); + } + + public void destroy() { + checkCurrentContext(); + destroyed = true; + } + + public void setBeanName(String name) { + checkCurrentContext(); + } + + public void setBeanClassLoader(ClassLoader classLoader) { + checkCurrentContext(); + } + + public void setBeanFactory(BeanFactory beanFactory) + throws BeansException { + checkCurrentContext(); + } + + private void checkCurrentContext() { + assertEquals(expectedName, getCurrentSubjectName()); + } + } + + private static class NonPrivilegedFactoryBean implements SmartFactoryBean { + private String expectedName; + + public NonPrivilegedFactoryBean(String expected) { + this.expectedName = expected; + checkCurrentContext(); + } + + public boolean isEagerInit() { + checkCurrentContext(); + return false; + } + + public boolean isPrototype() { + checkCurrentContext(); + return true; + } + + public Object getObject() throws Exception { + checkCurrentContext(); + return new Object(); + } + + public Class getObjectType() { + checkCurrentContext(); + return Object.class; + } + + public boolean isSingleton() { + checkCurrentContext(); + return false; + } + + private void checkCurrentContext() { + assertEquals(expectedName, getCurrentSubjectName()); + } + } + + private static class NonPrivilegedFactory { + + private final String expectedName; + + public NonPrivilegedFactory(String expected) { + this.expectedName = expected; + assertEquals(expectedName, getCurrentSubjectName()); + } + + public static Object makeStaticInstance(String expectedName) { + assertEquals(expectedName, getCurrentSubjectName()); + return new Object(); + } + + public Object makeInstance() { + assertEquals(expectedName, getCurrentSubjectName()); + return new Object(); + } + } + + private static String getCurrentSubjectName() { + final AccessControlContext acc = AccessController.getContext(); + + return AccessController.doPrivileged(new PrivilegedAction() { + + public String run() { + Subject subject = Subject.getSubject(acc); + if (subject == null) { + return null; + } + + Set principals = subject.getPrincipals(); + + if (principals == null) { + return null; + } + for (Principal p : principals) { + return p.getName(); + } + return null; + } + }); + } + + private static class TestPrincipal implements Principal { + + private String name; + + public TestPrincipal(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof TestPrincipal)) { + return false; + } + TestPrincipal p = (TestPrincipal) obj; + return this.name.equals(p.name); + } + + public int hashCode() { + return this.name.hashCode(); + } + } + + public CallbacksSecurityTests() { + // setup security + if (System.getSecurityManager() == null) { + Policy policy = Policy.getPolicy(); + URL policyURL = getClass() + .getResource( + "/org/springframework/beans/factory/support/security/policy.all"); + System.setProperty("java.security.policy", policyURL.toString()); + System.setProperty("policy.allowSystemProperty", "true"); + policy.refresh(); + + System.setSecurityManager(new SecurityManager()); + } + } + + @Before + public void setUp() throws Exception { + + final ProtectionDomain empty = new ProtectionDomain(null, + new Permissions()); + + provider = new SecurityContextProvider() { + private final AccessControlContext acc = new AccessControlContext( + new ProtectionDomain[] { empty }); + + public AccessControlContext getAccessControlContext() { + return acc; + } + }; + + DefaultResourceLoader drl = new DefaultResourceLoader(); + Resource config = drl + .getResource("/org/springframework/beans/factory/support/security/callbacks.xml"); + beanFactory = new XmlBeanFactory(config); + beanFactory.setSecurityContextProvider(provider); + } + + @Test + public void testSecuritySanity() throws Exception { + AccessControlContext acc = provider.getAccessControlContext(); + try { + acc.checkPermission(new PropertyPermission("*", "read")); + fail("Acc should not have any permissions"); + } catch (SecurityException se) { + // expected + } + + final CustomCallbackBean bean = new CustomCallbackBean(); + final Method method = bean.getClass().getMethod("destroy", null); + method.setAccessible(true); + + try { + AccessController.doPrivileged(new PrivilegedExceptionAction() { + + public Object run() throws Exception { + method.invoke(bean, null); + return null; + } + }, acc); + fail("expected security exception"); + } catch (Exception ex) { + } + + final Class cl = ConstructorBean.class; + try { + AccessController.doPrivileged( + new PrivilegedExceptionAction() { + + public Object run() throws Exception { + return cl.newInstance(); + } + }, acc); + fail("expected security exception"); + } catch (Exception ex) { + } + } + + @Test + public void testSpringInitBean() throws Exception { + try { + beanFactory.getBean("spring-init"); + fail("expected security exception"); + } catch (BeanCreationException ex) { + assertTrue(ex.getCause() instanceof SecurityException); + } + } + + @Test + public void testCustomInitBean() throws Exception { + try { + beanFactory.getBean("custom-init"); + fail("expected security exception"); + } catch (BeanCreationException ex) { + assertTrue(ex.getCause() instanceof SecurityException); + } + } + + @Test + public void testSpringDestroyBean() throws Exception { + beanFactory.getBean("spring-destroy"); + beanFactory.destroySingletons(); + assertNull(System.getProperty("security.destroy")); + } + + @Test + public void testCustomDestroyBean() throws Exception { + beanFactory.getBean("custom-destroy"); + beanFactory.destroySingletons(); + assertNull(System.getProperty("security.destroy")); + } + + @Test + public void testCustomFactoryObject() throws Exception { + try { + beanFactory.getBean("spring-factory"); + fail("expected security exception"); + } catch (BeanCreationException ex) { + assertTrue(ex.getCause() instanceof SecurityException); + } + + } + + @Test + public void testCustomFactoryType() throws Exception { + assertNull(beanFactory.getType("spring-factory")); + assertNull(System.getProperty("factory.object.type")); + } + + @Test + public void testCustomStaticFactoryMethod() throws Exception { + try { + beanFactory.getBean("custom-static-factory-method"); + fail("expected security exception"); + } catch (BeanCreationException ex) { + assertTrue(ex.getMostSpecificCause() instanceof SecurityException); + } + } + + @Test + public void testCustomInstanceFactoryMethod() throws Exception { + try { + beanFactory.getBean("custom-factory-method"); + fail("expected security exception"); + } catch (BeanCreationException ex) { + assertTrue(ex.getMostSpecificCause() instanceof SecurityException); + } + } + + @Test + public void testTrustedFactoryMethod() throws Exception { + try { + beanFactory.getBean("privileged-static-factory-method"); + fail("expected security exception"); + } catch (BeanCreationException ex) { + assertTrue(ex.getMostSpecificCause() instanceof SecurityException); + } + } + + @Test + public void testConstructor() throws Exception { + try { + beanFactory.getBean("constructor"); + fail("expected security exception"); + } catch (BeanCreationException ex) { + // expected + assertTrue(ex.getMostSpecificCause() instanceof SecurityException); + } + } + + @Test + public void testContainerPriviledges() throws Exception { + AccessControlContext acc = provider.getAccessControlContext(); + + AccessController.doPrivileged(new PrivilegedExceptionAction() { + + public Object run() throws Exception { + beanFactory.getBean("working-factory-method"); + beanFactory.getBean("container-execution"); + return null; + } + }, acc); + } + + @Test + public void testPropertyInjection() throws Exception { + try { + beanFactory.getBean("property-injection"); + fail("expected security exception"); + } catch (BeanCreationException ex) { + assertTrue(ex.getMessage().contains("security")); + } + + beanFactory.getBean("working-property-injection"); + } + + @Test + public void testInitSecurityAwarePrototypeBean() { + final DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + BeanDefinitionBuilder bdb = BeanDefinitionBuilder + .genericBeanDefinition(NonPrivilegedBean.class).setScope( + ConfigurableBeanFactory.SCOPE_PROTOTYPE) + .setInitMethodName("init").setDestroyMethodName("destroy") + .addConstructorArgValue("user1"); + lbf.registerBeanDefinition("test", bdb.getBeanDefinition()); + final Subject subject = new Subject(); + subject.getPrincipals().add(new TestPrincipal("user1")); + + NonPrivilegedBean bean = Subject.doAsPrivileged( + subject, new PrivilegedAction() { + public NonPrivilegedBean run() { + return lbf.getBean("test", NonPrivilegedBean.class); + } + }, null); + assertNotNull(bean); + } + + @Test + public void testTrustedExecution() throws Exception { + beanFactory.setSecurityContextProvider(null); + + Permissions perms = new Permissions(); + perms.add(new AuthPermission("getSubject")); + ProtectionDomain pd = new ProtectionDomain(null, perms); + + AccessControlContext acc = new AccessControlContext( + new ProtectionDomain[] { pd }); + + final Subject subject = new Subject(); + subject.getPrincipals().add(new TestPrincipal("user1")); + + // request the beans from non-privileged code + Subject.doAsPrivileged(subject, new PrivilegedAction() { + + public Object run() { + // sanity check + assertEquals("user1", getCurrentSubjectName()); + assertEquals(false, NonPrivilegedBean.destroyed); + + beanFactory.getBean("trusted-spring-callbacks"); + beanFactory.getBean("trusted-custom-init-destroy"); + // the factory is a prototype - ask for multiple instances + beanFactory.getBean("trusted-spring-factory"); + beanFactory.getBean("trusted-spring-factory"); + beanFactory.getBean("trusted-spring-factory"); + + beanFactory.getBean("trusted-factory-bean"); + beanFactory.getBean("trusted-static-factory-method"); + beanFactory.getBean("trusted-factory-method"); + beanFactory.getBean("trusted-property-injection"); + beanFactory.getBean("trusted-working-property-injection"); + + beanFactory.destroySingletons(); + assertEquals(true, NonPrivilegedBean.destroyed); + return null; + } + }, provider.getAccessControlContext()); + } } \ No newline at end of file diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/policy.all b/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/policy.all index a59033804b..de8e185c94 100644 --- a/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/policy.all +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/policy.all @@ -1,3 +1,3 @@ -grant { - permission java.security.AllPermission; +grant { + permission java.security.AllPermission; }; \ No newline at end of file diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/ConstructorBean.java b/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/ConstructorBean.java index 1934157b94..95cf5df4da 100644 --- a/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/ConstructorBean.java +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/ConstructorBean.java @@ -1,30 +1,30 @@ -/* - * Copyright 2006-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.beans.factory.support.security.support; - -/** - * @author Costin Leau - */ -public class ConstructorBean { - - public ConstructorBean() { - System.getProperties(); - } - - public ConstructorBean(Object obj) { - System.out.println("Received object " + obj); - } -} +/* + * Copyright 2006-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.beans.factory.support.security.support; + +/** + * @author Costin Leau + */ +public class ConstructorBean { + + public ConstructorBean() { + System.getProperties(); + } + + public ConstructorBean(Object obj) { + System.out.println("Received object " + obj); + } +} diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/CustomCallbackBean.java b/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/CustomCallbackBean.java index c64000093b..80c09aff2b 100644 --- a/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/CustomCallbackBean.java +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/CustomCallbackBean.java @@ -1,30 +1,30 @@ -/* - * Copyright 2006-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.beans.factory.support.security.support; - -/** - * @author Costin Leau - */ -public class CustomCallbackBean { - - public void init() { - System.getProperties(); - } - - public void destroy() { - System.setProperty("security.destroy", "true"); - } -} +/* + * Copyright 2006-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.beans.factory.support.security.support; + +/** + * @author Costin Leau + */ +public class CustomCallbackBean { + + public void init() { + System.getProperties(); + } + + public void destroy() { + System.setProperty("security.destroy", "true"); + } +} diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/CustomFactoryBean.java b/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/CustomFactoryBean.java index 231c5d1d08..93a8c344ba 100644 --- a/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/CustomFactoryBean.java +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/CustomFactoryBean.java @@ -1,39 +1,39 @@ -/* - * Copyright 2006-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.beans.factory.support.security.support; - -import java.util.Properties; - -import org.springframework.beans.factory.FactoryBean; - -/** - * @author Costin Leau - */ -public class CustomFactoryBean implements FactoryBean { - - public Object getObject() throws Exception { - return System.getProperties(); - } - - public Class getObjectType() { - System.setProperty("factory.object.type", "true"); - return Properties.class; - } - - public boolean isSingleton() { - return true; - } -} +/* + * Copyright 2006-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.beans.factory.support.security.support; + +import java.util.Properties; + +import org.springframework.beans.factory.FactoryBean; + +/** + * @author Costin Leau + */ +public class CustomFactoryBean implements FactoryBean { + + public Object getObject() throws Exception { + return System.getProperties(); + } + + public Class getObjectType() { + System.setProperty("factory.object.type", "true"); + return Properties.class; + } + + public boolean isSingleton() { + return true; + } +} diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/DestroyBean.java b/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/DestroyBean.java index da25e799b7..d24ff22474 100644 --- a/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/DestroyBean.java +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/DestroyBean.java @@ -1,28 +1,28 @@ -/* - * Copyright 2006-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.beans.factory.support.security.support; - -import org.springframework.beans.factory.DisposableBean; - -/** - * @author Costin Leau - */ -public class DestroyBean implements DisposableBean { - - public void destroy() throws Exception { - System.setProperty("security.destroy", "true"); - } -} +/* + * Copyright 2006-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.beans.factory.support.security.support; + +import org.springframework.beans.factory.DisposableBean; + +/** + * @author Costin Leau + */ +public class DestroyBean implements DisposableBean { + + public void destroy() throws Exception { + System.setProperty("security.destroy", "true"); + } +} diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/FactoryBean.java b/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/FactoryBean.java index 80871674f5..43efd6fd8b 100644 --- a/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/FactoryBean.java +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/FactoryBean.java @@ -1,36 +1,36 @@ -/* - * Copyright 2006-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.beans.factory.support.security.support; - -/** - * @author Costin Leau - */ -public class FactoryBean { - - public static Object makeStaticInstance() { - System.getProperties(); - return new Object(); - } - - protected static Object protectedStaticInstance() { - return "protectedStaticInstance"; - } - - public Object makeInstance() { - System.getProperties(); - return new Object(); - } -} +/* + * Copyright 2006-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.beans.factory.support.security.support; + +/** + * @author Costin Leau + */ +public class FactoryBean { + + public static Object makeStaticInstance() { + System.getProperties(); + return new Object(); + } + + protected static Object protectedStaticInstance() { + return "protectedStaticInstance"; + } + + public Object makeInstance() { + System.getProperties(); + return new Object(); + } +} diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/InitBean.java b/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/InitBean.java index 0c3f71e63e..acd4343d21 100644 --- a/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/InitBean.java +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/InitBean.java @@ -1,28 +1,28 @@ -/* - * Copyright 2006-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.beans.factory.support.security.support; - -import org.springframework.beans.factory.InitializingBean; - -/** - * @author Costin Leau - */ -public class InitBean implements InitializingBean { - - public void afterPropertiesSet() throws Exception { - System.getProperties(); - } -} +/* + * Copyright 2006-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.beans.factory.support.security.support; + +import org.springframework.beans.factory.InitializingBean; + +/** + * @author Costin Leau + */ +public class InitBean implements InitializingBean { + + public void afterPropertiesSet() throws Exception { + System.getProperties(); + } +} diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/PropertyBean.java b/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/PropertyBean.java index 494187c20f..ced0d45b93 100644 --- a/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/PropertyBean.java +++ b/org.springframework.beans/src/test/java/org/springframework/beans/factory/support/security/support/PropertyBean.java @@ -1,30 +1,30 @@ -/* - * Copyright 2006-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.beans.factory.support.security.support; - -/** - * @author Costin Leau - */ -public class PropertyBean { - - public void setSecurityProperty(Object property) { - System.getProperties(); - } - - public void setProperty(Object property) { - - } -} +/* + * Copyright 2006-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.beans.factory.support.security.support; + +/** + * @author Costin Leau + */ +public class PropertyBean { + + public void setSecurityProperty(Object property) { + System.getProperties(); + } + + public void setProperty(Object property) { + + } +} diff --git a/org.springframework.beans/src/test/java/test/beans/DummyBean.java b/org.springframework.beans/src/test/java/test/beans/DummyBean.java index 0fda3dc3e7..54ae5e65d6 100644 --- a/org.springframework.beans/src/test/java/test/beans/DummyBean.java +++ b/org.springframework.beans/src/test/java/test/beans/DummyBean.java @@ -1,68 +1,68 @@ -/* - * Copyright 2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package test.beans; - -/** - * @author Costin Leau - */ -public class DummyBean { - - private Object value; - private String name; - private int age; - private TestBean spouse; - - public DummyBean(Object value) { - this.value = value; - } - - public DummyBean(String name, int age) { - this.name = name; - this.age = age; - } - - public DummyBean(int ageRef, String nameRef) { - this.name = nameRef; - this.age = ageRef; - } - - public DummyBean(String name, TestBean spouse) { - this.name = name; - this.spouse = spouse; - } - - public DummyBean(String name, Object value, int age) { - this.name = name; - this.value = value; - this.age = age; - } - - public Object getValue() { - return value; - } - - public String getName() { - return name; - } - - public int getAge() { - return age; - } - - public TestBean getSpouse() { - return spouse; - } -} +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package test.beans; + +/** + * @author Costin Leau + */ +public class DummyBean { + + private Object value; + private String name; + private int age; + private TestBean spouse; + + public DummyBean(Object value) { + this.value = value; + } + + public DummyBean(String name, int age) { + this.name = name; + this.age = age; + } + + public DummyBean(int ageRef, String nameRef) { + this.name = nameRef; + this.age = ageRef; + } + + public DummyBean(String name, TestBean spouse) { + this.name = name; + this.spouse = spouse; + } + + public DummyBean(String name, Object value, int age) { + this.name = name; + this.value = value; + this.age = age; + } + + public Object getValue() { + return value; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } + + public TestBean getSpouse() { + return spouse; + } +} diff --git a/org.springframework.context.support/.settings/org.eclipse.jdt.ui.prefs b/org.springframework.context.support/.settings/org.eclipse.jdt.ui.prefs index 09becb34db..5ffc725a5a 100644 --- a/org.springframework.context.support/.settings/org.eclipse.jdt.ui.prefs +++ b/org.springframework.context.support/.settings/org.eclipse.jdt.ui.prefs @@ -1,4 +1,4 @@ -#Wed Mar 31 18:40:01 EEST 2010 -eclipse.preferences.version=1 -formatter_profile=_Spring -formatter_settings_version=11 +#Wed Mar 31 18:40:01 EEST 2010 +eclipse.preferences.version=1 +formatter_profile=_Spring +formatter_settings_version=11 diff --git a/org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/TimerManagerAccessor.java b/org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/TimerManagerAccessor.java index f53108cec2..46db6ee2c0 100644 --- a/org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/TimerManagerAccessor.java +++ b/org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/TimerManagerAccessor.java @@ -1,163 +1,163 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.scheduling.commonj; - -import javax.naming.NamingException; - -import commonj.timers.TimerManager; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.Lifecycle; -import org.springframework.jndi.JndiLocatorSupport; - -/** - * Base class for classes that are accessing a CommonJ {@link commonj.timers.TimerManager} - * Defines common configuration settings and common lifecycle handling. - * - * @author Juergen Hoeller - * @since 3.0 - * @see commonj.timers.TimerManager - */ -public abstract class TimerManagerAccessor extends JndiLocatorSupport - implements InitializingBean, DisposableBean, Lifecycle { - - private TimerManager timerManager; - - private String timerManagerName; - - private boolean shared = false; - - - /** - * Specify the CommonJ TimerManager to delegate to. - *

Note that the given TimerManager's lifecycle will be managed - * by this FactoryBean. - *

Alternatively (and typically), you can specify the JNDI name - * of the target TimerManager. - * @see #setTimerManagerName - */ - public void setTimerManager(TimerManager timerManager) { - this.timerManager = timerManager; - } - - /** - * Set the JNDI name of the CommonJ TimerManager. - *

This can either be a fully qualified JNDI name, or the JNDI name relative - * to the current environment naming context if "resourceRef" is set to "true". - * @see #setTimerManager - * @see #setResourceRef - */ - public void setTimerManagerName(String timerManagerName) { - this.timerManagerName = timerManagerName; - } - - /** - * Specify whether the TimerManager obtained by this FactoryBean - * is a shared instance ("true") or an independent instance ("false"). - * The lifecycle of the former is supposed to be managed by the application - * server, while the lifecycle of the latter is up to the application. - *

Default is "false", i.e. managing an independent TimerManager instance. - * This is what the CommonJ specification suggests that application servers - * are supposed to offer via JNDI lookups, typically declared as a - * resource-ref of type commonj.timers.TimerManager - * in web.xml, with res-sharing-scope set to 'Unshareable'. - *

Switch this flag to "true" if you are obtaining a shared TimerManager, - * typically through specifying the JNDI location of a TimerManager that - * has been explicitly declared as 'Shareable'. Note that WebLogic's - * cluster-aware Job Scheduler is a shared TimerManager too. - *

The sole difference between this FactoryBean being in shared or - * non-shared mode is that it will only attempt to suspend / resume / stop - * the underlying TimerManager in case of an independent (non-shared) instance. - * This only affects the {@link org.springframework.context.Lifecycle} support - * as well as application context shutdown. - * @see #stop() - * @see #start() - * @see #destroy() - * @see commonj.timers.TimerManager - */ - public void setShared(boolean shared) { - this.shared = shared; - } - - - public void afterPropertiesSet() throws NamingException { - if (this.timerManager == null) { - if (this.timerManagerName == null) { - throw new IllegalArgumentException("Either 'timerManager' or 'timerManagerName' must be specified"); - } - this.timerManager = lookup(this.timerManagerName, TimerManager.class); - } - } - - protected final TimerManager getTimerManager() { - return this.timerManager; - } - - - //--------------------------------------------------------------------- - // Implementation of Lifecycle interface - //--------------------------------------------------------------------- - - /** - * Resumes the underlying TimerManager (if not shared). - * @see commonj.timers.TimerManager#resume() - */ - public void start() { - if (!this.shared) { - this.timerManager.resume(); - } - } - - /** - * Suspends the underlying TimerManager (if not shared). - * @see commonj.timers.TimerManager#suspend() - */ - public void stop() { - if (!this.shared) { - this.timerManager.suspend(); - } - } - - /** - * Considers the underlying TimerManager as running if it is - * neither suspending nor stopping. - * @see commonj.timers.TimerManager#isSuspending() - * @see commonj.timers.TimerManager#isStopping() - */ - public boolean isRunning() { - return (!this.timerManager.isSuspending() && !this.timerManager.isStopping()); - } - - - //--------------------------------------------------------------------- - // Implementation of DisposableBean interface - //--------------------------------------------------------------------- - - /** - * Stops the underlying TimerManager (if not shared). - * @see commonj.timers.TimerManager#stop() - */ - public void destroy() { - // Stop the entire TimerManager, if necessary. - if (!this.shared) { - // May return early, but at least we already cancelled all known Timers. - this.timerManager.stop(); - } - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling.commonj; + +import javax.naming.NamingException; + +import commonj.timers.TimerManager; + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.Lifecycle; +import org.springframework.jndi.JndiLocatorSupport; + +/** + * Base class for classes that are accessing a CommonJ {@link commonj.timers.TimerManager} + * Defines common configuration settings and common lifecycle handling. + * + * @author Juergen Hoeller + * @since 3.0 + * @see commonj.timers.TimerManager + */ +public abstract class TimerManagerAccessor extends JndiLocatorSupport + implements InitializingBean, DisposableBean, Lifecycle { + + private TimerManager timerManager; + + private String timerManagerName; + + private boolean shared = false; + + + /** + * Specify the CommonJ TimerManager to delegate to. + *

Note that the given TimerManager's lifecycle will be managed + * by this FactoryBean. + *

Alternatively (and typically), you can specify the JNDI name + * of the target TimerManager. + * @see #setTimerManagerName + */ + public void setTimerManager(TimerManager timerManager) { + this.timerManager = timerManager; + } + + /** + * Set the JNDI name of the CommonJ TimerManager. + *

This can either be a fully qualified JNDI name, or the JNDI name relative + * to the current environment naming context if "resourceRef" is set to "true". + * @see #setTimerManager + * @see #setResourceRef + */ + public void setTimerManagerName(String timerManagerName) { + this.timerManagerName = timerManagerName; + } + + /** + * Specify whether the TimerManager obtained by this FactoryBean + * is a shared instance ("true") or an independent instance ("false"). + * The lifecycle of the former is supposed to be managed by the application + * server, while the lifecycle of the latter is up to the application. + *

Default is "false", i.e. managing an independent TimerManager instance. + * This is what the CommonJ specification suggests that application servers + * are supposed to offer via JNDI lookups, typically declared as a + * resource-ref of type commonj.timers.TimerManager + * in web.xml, with res-sharing-scope set to 'Unshareable'. + *

Switch this flag to "true" if you are obtaining a shared TimerManager, + * typically through specifying the JNDI location of a TimerManager that + * has been explicitly declared as 'Shareable'. Note that WebLogic's + * cluster-aware Job Scheduler is a shared TimerManager too. + *

The sole difference between this FactoryBean being in shared or + * non-shared mode is that it will only attempt to suspend / resume / stop + * the underlying TimerManager in case of an independent (non-shared) instance. + * This only affects the {@link org.springframework.context.Lifecycle} support + * as well as application context shutdown. + * @see #stop() + * @see #start() + * @see #destroy() + * @see commonj.timers.TimerManager + */ + public void setShared(boolean shared) { + this.shared = shared; + } + + + public void afterPropertiesSet() throws NamingException { + if (this.timerManager == null) { + if (this.timerManagerName == null) { + throw new IllegalArgumentException("Either 'timerManager' or 'timerManagerName' must be specified"); + } + this.timerManager = lookup(this.timerManagerName, TimerManager.class); + } + } + + protected final TimerManager getTimerManager() { + return this.timerManager; + } + + + //--------------------------------------------------------------------- + // Implementation of Lifecycle interface + //--------------------------------------------------------------------- + + /** + * Resumes the underlying TimerManager (if not shared). + * @see commonj.timers.TimerManager#resume() + */ + public void start() { + if (!this.shared) { + this.timerManager.resume(); + } + } + + /** + * Suspends the underlying TimerManager (if not shared). + * @see commonj.timers.TimerManager#suspend() + */ + public void stop() { + if (!this.shared) { + this.timerManager.suspend(); + } + } + + /** + * Considers the underlying TimerManager as running if it is + * neither suspending nor stopping. + * @see commonj.timers.TimerManager#isSuspending() + * @see commonj.timers.TimerManager#isStopping() + */ + public boolean isRunning() { + return (!this.timerManager.isSuspending() && !this.timerManager.isStopping()); + } + + + //--------------------------------------------------------------------- + // Implementation of DisposableBean interface + //--------------------------------------------------------------------- + + /** + * Stops the underlying TimerManager (if not shared). + * @see commonj.timers.TimerManager#stop() + */ + public void destroy() { + // Stop the entire TimerManager, if necessary. + if (!this.shared) { + // May return early, but at least we already cancelled all known Timers. + this.timerManager.stop(); + } + } + +} diff --git a/org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/TimerManagerTaskScheduler.java b/org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/TimerManagerTaskScheduler.java index d9cba9e5b8..8d0f0795bc 100644 --- a/org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/TimerManagerTaskScheduler.java +++ b/org.springframework.context.support/src/main/java/org/springframework/scheduling/commonj/TimerManagerTaskScheduler.java @@ -1,174 +1,174 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.scheduling.commonj; - -import java.util.Date; -import java.util.concurrent.Delayed; -import java.util.concurrent.FutureTask; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - -import commonj.timers.Timer; -import commonj.timers.TimerListener; - -import org.springframework.scheduling.TaskScheduler; -import org.springframework.scheduling.Trigger; -import org.springframework.scheduling.support.SimpleTriggerContext; -import org.springframework.scheduling.support.TaskUtils; -import org.springframework.util.ErrorHandler; - -/** - * Implementation of Spring's {@link TaskScheduler} interface, wrapping - * a CommonJ {@link commonj.timers.TimerManager}. - * - * @author Juergen Hoeller - * @author Mark Fisher - * @since 3.0 - */ -public class TimerManagerTaskScheduler extends TimerManagerAccessor implements TaskScheduler { - - private volatile ErrorHandler errorHandler; - - public void setErrorHandler(ErrorHandler errorHandler) { - this.errorHandler = errorHandler; - } - - public ScheduledFuture schedule(Runnable task, Trigger trigger) { - return new ReschedulingTimerListener(errorHandlingTask(task, true), trigger).schedule(); - } - - public ScheduledFuture schedule(Runnable task, Date startTime) { - TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, false)); - Timer timer = getTimerManager().schedule(futureTask, startTime); - futureTask.setTimer(timer); - return futureTask; - } - - public ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period) { - TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true)); - Timer timer = getTimerManager().scheduleAtFixedRate(futureTask, startTime, period); - futureTask.setTimer(timer); - return futureTask; - } - - public ScheduledFuture scheduleAtFixedRate(Runnable task, long period) { - TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true)); - Timer timer = getTimerManager().scheduleAtFixedRate(futureTask, 0, period); - futureTask.setTimer(timer); - return futureTask; - } - - public ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay) { - TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true)); - Timer timer = getTimerManager().schedule(futureTask, startTime, delay); - futureTask.setTimer(timer); - return futureTask; - } - - public ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay) { - TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true)); - Timer timer = getTimerManager().schedule(futureTask, 0, delay); - futureTask.setTimer(timer); - return futureTask; - } - - private Runnable errorHandlingTask(Runnable delegate, boolean isRepeatingTask) { - return TaskUtils.decorateTaskWithErrorHandler(delegate, this.errorHandler, isRepeatingTask); - } - - - /** - * ScheduledFuture adapter that wraps a CommonJ Timer. - */ - private static class TimerScheduledFuture extends FutureTask implements TimerListener, ScheduledFuture { - - protected transient Timer timer; - - protected transient boolean cancelled = false; - - public TimerScheduledFuture(Runnable runnable) { - super(runnable, null); - } - - public void setTimer(Timer timer) { - this.timer = timer; - } - - public void timerExpired(Timer timer) { - runAndReset(); - } - - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - boolean result = super.cancel(mayInterruptIfRunning); - this.timer.cancel(); - this.cancelled = true; - return result; - } - - public long getDelay(TimeUnit unit) { - return unit.convert(System.currentTimeMillis() - this.timer.getScheduledExecutionTime(), TimeUnit.MILLISECONDS); - } - - public int compareTo(Delayed other) { - if (this == other) { - return 0; - } - long diff = getDelay(TimeUnit.MILLISECONDS) - other.getDelay(TimeUnit.MILLISECONDS); - return (diff == 0 ? 0 : ((diff < 0)? -1 : 1)); - } - } - - - /** - * ScheduledFuture adapter for trigger-based rescheduling. - */ - private class ReschedulingTimerListener extends TimerScheduledFuture { - - private final Trigger trigger; - - private final SimpleTriggerContext triggerContext = new SimpleTriggerContext(); - - private volatile Date scheduledExecutionTime; - - public ReschedulingTimerListener(Runnable runnable, Trigger trigger) { - super(runnable); - this.trigger = trigger; - } - - public ScheduledFuture schedule() { - this.scheduledExecutionTime = this.trigger.nextExecutionTime(this.triggerContext); - if (this.scheduledExecutionTime == null) { - return null; - } - setTimer(getTimerManager().schedule(this, this.scheduledExecutionTime)); - return this; - } - - @Override - public void timerExpired(Timer timer) { - Date actualExecutionTime = new Date(); - super.timerExpired(timer); - Date completionTime = new Date(); - this.triggerContext.update(this.scheduledExecutionTime, actualExecutionTime, completionTime); - if (!this.cancelled) { - schedule(); - } - } - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling.commonj; + +import java.util.Date; +import java.util.concurrent.Delayed; +import java.util.concurrent.FutureTask; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import commonj.timers.Timer; +import commonj.timers.TimerListener; + +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.Trigger; +import org.springframework.scheduling.support.SimpleTriggerContext; +import org.springframework.scheduling.support.TaskUtils; +import org.springframework.util.ErrorHandler; + +/** + * Implementation of Spring's {@link TaskScheduler} interface, wrapping + * a CommonJ {@link commonj.timers.TimerManager}. + * + * @author Juergen Hoeller + * @author Mark Fisher + * @since 3.0 + */ +public class TimerManagerTaskScheduler extends TimerManagerAccessor implements TaskScheduler { + + private volatile ErrorHandler errorHandler; + + public void setErrorHandler(ErrorHandler errorHandler) { + this.errorHandler = errorHandler; + } + + public ScheduledFuture schedule(Runnable task, Trigger trigger) { + return new ReschedulingTimerListener(errorHandlingTask(task, true), trigger).schedule(); + } + + public ScheduledFuture schedule(Runnable task, Date startTime) { + TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, false)); + Timer timer = getTimerManager().schedule(futureTask, startTime); + futureTask.setTimer(timer); + return futureTask; + } + + public ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period) { + TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true)); + Timer timer = getTimerManager().scheduleAtFixedRate(futureTask, startTime, period); + futureTask.setTimer(timer); + return futureTask; + } + + public ScheduledFuture scheduleAtFixedRate(Runnable task, long period) { + TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true)); + Timer timer = getTimerManager().scheduleAtFixedRate(futureTask, 0, period); + futureTask.setTimer(timer); + return futureTask; + } + + public ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay) { + TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true)); + Timer timer = getTimerManager().schedule(futureTask, startTime, delay); + futureTask.setTimer(timer); + return futureTask; + } + + public ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay) { + TimerScheduledFuture futureTask = new TimerScheduledFuture(errorHandlingTask(task, true)); + Timer timer = getTimerManager().schedule(futureTask, 0, delay); + futureTask.setTimer(timer); + return futureTask; + } + + private Runnable errorHandlingTask(Runnable delegate, boolean isRepeatingTask) { + return TaskUtils.decorateTaskWithErrorHandler(delegate, this.errorHandler, isRepeatingTask); + } + + + /** + * ScheduledFuture adapter that wraps a CommonJ Timer. + */ + private static class TimerScheduledFuture extends FutureTask implements TimerListener, ScheduledFuture { + + protected transient Timer timer; + + protected transient boolean cancelled = false; + + public TimerScheduledFuture(Runnable runnable) { + super(runnable, null); + } + + public void setTimer(Timer timer) { + this.timer = timer; + } + + public void timerExpired(Timer timer) { + runAndReset(); + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + boolean result = super.cancel(mayInterruptIfRunning); + this.timer.cancel(); + this.cancelled = true; + return result; + } + + public long getDelay(TimeUnit unit) { + return unit.convert(System.currentTimeMillis() - this.timer.getScheduledExecutionTime(), TimeUnit.MILLISECONDS); + } + + public int compareTo(Delayed other) { + if (this == other) { + return 0; + } + long diff = getDelay(TimeUnit.MILLISECONDS) - other.getDelay(TimeUnit.MILLISECONDS); + return (diff == 0 ? 0 : ((diff < 0)? -1 : 1)); + } + } + + + /** + * ScheduledFuture adapter for trigger-based rescheduling. + */ + private class ReschedulingTimerListener extends TimerScheduledFuture { + + private final Trigger trigger; + + private final SimpleTriggerContext triggerContext = new SimpleTriggerContext(); + + private volatile Date scheduledExecutionTime; + + public ReschedulingTimerListener(Runnable runnable, Trigger trigger) { + super(runnable); + this.trigger = trigger; + } + + public ScheduledFuture schedule() { + this.scheduledExecutionTime = this.trigger.nextExecutionTime(this.triggerContext); + if (this.scheduledExecutionTime == null) { + return null; + } + setTimer(getTimerManager().schedule(this, this.scheduledExecutionTime)); + return this; + } + + @Override + public void timerExpired(Timer timer) { + Date actualExecutionTime = new Date(); + super.timerExpired(timer); + Date completionTime = new Date(); + this.triggerContext.update(this.scheduledExecutionTime, actualExecutionTime, completionTime); + if (!this.cancelled) { + schedule(); + } + } + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/EmbeddedValueResolverAware.java b/org.springframework.context/src/main/java/org/springframework/context/EmbeddedValueResolverAware.java index a3f3a0ce2f..98d25eaaff 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/EmbeddedValueResolverAware.java +++ b/org.springframework.context/src/main/java/org/springframework/context/EmbeddedValueResolverAware.java @@ -1,41 +1,41 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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; - -import org.springframework.beans.factory.Aware; -import org.springframework.util.StringValueResolver; - -/** - * Interface to be implemented by any object that wishes to be notified of a - * StringValueResolver for the resolution of embedded definition values. - * - *

This is an alternative to a full ConfigurableBeanFactory dependency via the - * ApplicationContextAware/BeanFactoryAware interfaces. - * - * @author Juergen Hoeller - * @author Chris Beams - * @since 3.0.3 - * @see org.springframework.beans.factory.config.ConfigurableBeanFactory#resolveEmbeddedValue - */ -public interface EmbeddedValueResolverAware extends Aware { - - /** - * Set the StringValueResolver to use for resolving embedded definition values. - */ - void setEmbeddedValueResolver(StringValueResolver resolver); - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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; + +import org.springframework.beans.factory.Aware; +import org.springframework.util.StringValueResolver; + +/** + * Interface to be implemented by any object that wishes to be notified of a + * StringValueResolver for the resolution of embedded definition values. + * + *

This is an alternative to a full ConfigurableBeanFactory dependency via the + * ApplicationContextAware/BeanFactoryAware interfaces. + * + * @author Juergen Hoeller + * @author Chris Beams + * @since 3.0.3 + * @see org.springframework.beans.factory.config.ConfigurableBeanFactory#resolveEmbeddedValue + */ +public interface EmbeddedValueResolverAware extends Aware { + + /** + * Set the StringValueResolver to use for resolving embedded definition values. + */ + void setEmbeddedValueResolver(StringValueResolver resolver); + +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java index 3986803b15..2d3ee5ab8e 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java @@ -1,177 +1,177 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.Annotation; - -import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition; -import org.springframework.beans.factory.config.BeanDefinitionHolder; -import org.springframework.beans.factory.support.AutowireCandidateQualifier; -import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.BeanNameGenerator; -import org.springframework.core.env.Environment; -import org.springframework.core.env.EnvironmentCapable; -import org.springframework.core.env.StandardEnvironment; -import org.springframework.core.type.AnnotationMetadata; -import org.springframework.util.Assert; - -/** - * Convenient adapter for programmatic registration of annotated bean classes. - * This is an alternative to {@link ClassPathBeanDefinitionScanner}, applying - * the same resolution of annotations but for explicitly registered classes only. - * - * @author Juergen Hoeller - * @author Chris Beams - * @author Sam Brannen - * @since 3.0 - * @see AnnotationConfigApplicationContext#register - */ -public class AnnotatedBeanDefinitionReader { - - private final BeanDefinitionRegistry registry; - - private Environment environment; - - private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator(); - - private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver(); - - /** - * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry. - * If the registry is {@link EnvironmentCapable}, e.g. is an {@code ApplicationContext}, - * the {@link Environment} will be inherited, otherwise a new - * {@link StandardEnvironment} will be created and used. - * @param registry the {@code BeanFactory} to load bean definitions into, - * in the form of a {@code BeanDefinitionRegistry} - * @see #AnnotatedBeanDefinitionReader(BeanDefinitionRegistry, Environment) - * @see #setEnvironment(Environment) - */ - public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) { - this(registry, getOrCreateEnvironment(registry)); - } - - /** - * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry and using - * the given {@link Environment}. - * @param registry the {@code BeanFactory} to load bean definitions into, - * in the form of a {@code BeanDefinitionRegistry} - * @param environment the {@code Environment} to use when evaluating bean definition - * profiles. - * @since 3.1 - */ - public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) { - Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); - Assert.notNull(environment, "Environment must not be null"); - - this.registry = registry; - this.environment = environment; - - AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); - } - - /** - * Return the BeanDefinitionRegistry that this scanner operates on. - */ - public final BeanDefinitionRegistry getRegistry() { - return this.registry; - } - - /** - * Set the Environment to use when evaluating whether - * {@link Profile @Profile}-annotated component classes should be registered. - *

The default is a {@link StandardEnvironment}. - * @see #registerBean(Class, String, Class...) - */ - public void setEnvironment(Environment environment) { - this.environment = environment; - } - - /** - * Set the BeanNameGenerator to use for detected bean classes. - *

The default is a {@link AnnotationBeanNameGenerator}. - */ - public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) { - this.beanNameGenerator = (beanNameGenerator != null ? beanNameGenerator : new AnnotationBeanNameGenerator()); - } - - /** - * Set the ScopeMetadataResolver to use for detected bean classes. - *

The default is an {@link AnnotationScopeMetadataResolver}. - */ - public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) { - this.scopeMetadataResolver = (scopeMetadataResolver != null ? scopeMetadataResolver - : new AnnotationScopeMetadataResolver()); - } - - public void register(Class... annotatedClasses) { - for (Class annotatedClass : annotatedClasses) { - registerBean(annotatedClass); - } - } - - public void registerBean(Class annotatedClass) { - registerBean(annotatedClass, null, (Class[]) null); - } - - public void registerBean(Class annotatedClass, Class... qualifiers) { - registerBean(annotatedClass, null, qualifiers); - } - - public void registerBean(Class annotatedClass, String name, Class... qualifiers) { - AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass); - AnnotationMetadata metadata = abd.getMetadata(); - - if (ProfileHelper.isProfileAnnotationPresent(metadata)) { - if (!this.environment.acceptsProfiles(ProfileHelper.getCandidateProfiles(metadata))) { - return; - } - } - ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); - abd.setScope(scopeMetadata.getScopeName()); - String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); - AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); - if (qualifiers != null) { - for (Class qualifier : qualifiers) { - if (Primary.class.equals(qualifier)) { - abd.setPrimary(true); - } else if (Lazy.class.equals(qualifier)) { - abd.setLazyInit(true); - } else { - abd.addQualifier(new AutowireCandidateQualifier(qualifier)); - } - } - } - BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); - definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); - BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); - } - - - /** - * Get the Environment from the given registry if possible, otherwise return a new - * StandardEnvironment. - */ - private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) { - Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); - if (registry instanceof EnvironmentCapable) { - return ((EnvironmentCapable) registry).getEnvironment(); - } - return new StandardEnvironment(); - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.Annotation; + +import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.support.AutowireCandidateQualifier; +import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanNameGenerator; +import org.springframework.core.env.Environment; +import org.springframework.core.env.EnvironmentCapable; +import org.springframework.core.env.StandardEnvironment; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.util.Assert; + +/** + * Convenient adapter for programmatic registration of annotated bean classes. + * This is an alternative to {@link ClassPathBeanDefinitionScanner}, applying + * the same resolution of annotations but for explicitly registered classes only. + * + * @author Juergen Hoeller + * @author Chris Beams + * @author Sam Brannen + * @since 3.0 + * @see AnnotationConfigApplicationContext#register + */ +public class AnnotatedBeanDefinitionReader { + + private final BeanDefinitionRegistry registry; + + private Environment environment; + + private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator(); + + private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver(); + + /** + * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry. + * If the registry is {@link EnvironmentCapable}, e.g. is an {@code ApplicationContext}, + * the {@link Environment} will be inherited, otherwise a new + * {@link StandardEnvironment} will be created and used. + * @param registry the {@code BeanFactory} to load bean definitions into, + * in the form of a {@code BeanDefinitionRegistry} + * @see #AnnotatedBeanDefinitionReader(BeanDefinitionRegistry, Environment) + * @see #setEnvironment(Environment) + */ + public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) { + this(registry, getOrCreateEnvironment(registry)); + } + + /** + * Create a new {@code AnnotatedBeanDefinitionReader} for the given registry and using + * the given {@link Environment}. + * @param registry the {@code BeanFactory} to load bean definitions into, + * in the form of a {@code BeanDefinitionRegistry} + * @param environment the {@code Environment} to use when evaluating bean definition + * profiles. + * @since 3.1 + */ + public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) { + Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); + Assert.notNull(environment, "Environment must not be null"); + + this.registry = registry; + this.environment = environment; + + AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); + } + + /** + * Return the BeanDefinitionRegistry that this scanner operates on. + */ + public final BeanDefinitionRegistry getRegistry() { + return this.registry; + } + + /** + * Set the Environment to use when evaluating whether + * {@link Profile @Profile}-annotated component classes should be registered. + *

The default is a {@link StandardEnvironment}. + * @see #registerBean(Class, String, Class...) + */ + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + /** + * Set the BeanNameGenerator to use for detected bean classes. + *

The default is a {@link AnnotationBeanNameGenerator}. + */ + public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) { + this.beanNameGenerator = (beanNameGenerator != null ? beanNameGenerator : new AnnotationBeanNameGenerator()); + } + + /** + * Set the ScopeMetadataResolver to use for detected bean classes. + *

The default is an {@link AnnotationScopeMetadataResolver}. + */ + public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) { + this.scopeMetadataResolver = (scopeMetadataResolver != null ? scopeMetadataResolver + : new AnnotationScopeMetadataResolver()); + } + + public void register(Class... annotatedClasses) { + for (Class annotatedClass : annotatedClasses) { + registerBean(annotatedClass); + } + } + + public void registerBean(Class annotatedClass) { + registerBean(annotatedClass, null, (Class[]) null); + } + + public void registerBean(Class annotatedClass, Class... qualifiers) { + registerBean(annotatedClass, null, qualifiers); + } + + public void registerBean(Class annotatedClass, String name, Class... qualifiers) { + AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass); + AnnotationMetadata metadata = abd.getMetadata(); + + if (ProfileHelper.isProfileAnnotationPresent(metadata)) { + if (!this.environment.acceptsProfiles(ProfileHelper.getCandidateProfiles(metadata))) { + return; + } + } + ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); + abd.setScope(scopeMetadata.getScopeName()); + String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); + AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); + if (qualifiers != null) { + for (Class qualifier : qualifiers) { + if (Primary.class.equals(qualifier)) { + abd.setPrimary(true); + } else if (Lazy.class.equals(qualifier)) { + abd.setLazyInit(true); + } else { + abd.addQualifier(new AutowireCandidateQualifier(qualifier)); + } + } + } + BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); + definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); + BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); + } + + + /** + * Get the Environment from the given registry if possible, otherwise return a new + * StandardEnvironment. + */ + private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) { + Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); + if (registry instanceof EnvironmentCapable) { + return ((EnvironmentCapable) registry).getEnvironment(); + } + return new StandardEnvironment(); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/DependsOn.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/DependsOn.java index 1fee1a0f9f..59bd215857 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/DependsOn.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/DependsOn.java @@ -1,54 +1,54 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.annotation; - -import java.lang.annotation.Target; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Inherited; -import java.lang.annotation.Documented; - -/** - * Beans on which the current bean depends. Any beans specified are guaranteed to be - * created by the container before this bean. Used infrequently in cases where a bean - * does not explicitly depend on another through properties or constructor arguments, - * but rather depends on the side effects of another bean's initialization. - *

Note: This attribute will not be inherited by child bean definitions, - * hence it needs to be specified per concrete bean definition. - * - *

May be used on any class directly or indirectly annotated with - * {@link org.springframework.stereotype.Component} or on methods annotated - * with {@link Bean}. - * - *

Using {@link DependsOn} at the class level has no effect unless component-scanning - * is being used. If a {@link DependsOn}-annotated class is declared via XML, - * {@link DependsOn} annotation metadata is ignored, and - * {@code } is respected instead. - * - * @author Juergen Hoeller - * @since 3.0 - */ -@Target({ElementType.TYPE, ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -@Inherited -@Documented -public @interface DependsOn { - - String[] value() default {}; - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Inherited; +import java.lang.annotation.Documented; + +/** + * Beans on which the current bean depends. Any beans specified are guaranteed to be + * created by the container before this bean. Used infrequently in cases where a bean + * does not explicitly depend on another through properties or constructor arguments, + * but rather depends on the side effects of another bean's initialization. + *

Note: This attribute will not be inherited by child bean definitions, + * hence it needs to be specified per concrete bean definition. + * + *

May be used on any class directly or indirectly annotated with + * {@link org.springframework.stereotype.Component} or on methods annotated + * with {@link Bean}. + * + *

Using {@link DependsOn} at the class level has no effect unless component-scanning + * is being used. If a {@link DependsOn}-annotated class is declared via XML, + * {@link DependsOn} annotation metadata is ignored, and + * {@code } is respected instead. + * + * @author Juergen Hoeller + * @since 3.0 + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface DependsOn { + + String[] value() default {}; + +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/Jsr330ScopeMetadataResolver.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/Jsr330ScopeMetadataResolver.java index 61e79114b9..8549d97f8e 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/Jsr330ScopeMetadataResolver.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/Jsr330ScopeMetadataResolver.java @@ -1,111 +1,111 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.annotation; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; -import org.springframework.beans.factory.config.BeanDefinition; - -/** - * Simple {@link ScopeMetadataResolver} implementation that follows JSR-330 scoping rules: - * defaulting to prototype scope unless {@link javax.inject.Singleton} is present. - * - *

This scope resolver can be used with {@link ClassPathBeanDefinitionScanner} and - * {@link AnnotatedBeanDefinitionReader} for standard JSR-330 compliance. However, - * in practice, you will typically use Spring's rich default scoping instead - or extend - * this resolver with custom scoping annotations that point to extended Spring scopes. - * - * @author Juergen Hoeller - * @since 3.0 - * @see #registerScope - * @see #resolveScopeName - * @see ClassPathBeanDefinitionScanner#setScopeMetadataResolver - * @see AnnotatedBeanDefinitionReader#setScopeMetadataResolver - */ -public class Jsr330ScopeMetadataResolver implements ScopeMetadataResolver { - - private final Map scopeMap = new HashMap(); - - - public Jsr330ScopeMetadataResolver() { - registerScope("javax.inject.Singleton", BeanDefinition.SCOPE_SINGLETON); - } - - - /** - * Register an extended JSR-330 scope annotation, mapping it onto a - * specific Spring scope by name. - * @param annotationType the JSR-330 annotation type as a Class - * @param scopeName the Spring scope name - */ - public final void registerScope(Class annotationType, String scopeName) { - this.scopeMap.put(annotationType.getName(), scopeName); - } - - /** - * Register an extended JSR-330 scope annotation, mapping it onto a - * specific Spring scope by name. - * @param annotationType the JSR-330 annotation type by name - * @param scopeName the Spring scope name - */ - public final void registerScope(String annotationType, String scopeName) { - this.scopeMap.put(annotationType, scopeName); - } - - /** - * Resolve the given annotation type into a named Spring scope. - *

The default implementation simply checks against registered scopes. - * Can be overridden for custom mapping rules, e.g. naming conventions. - * @param annotationType the JSR-330 annotation type - * @return the Spring scope name - */ - protected String resolveScopeName(String annotationType) { - return this.scopeMap.get(annotationType); - } - - - public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) { - ScopeMetadata metadata = new ScopeMetadata(); - metadata.setScopeName(BeanDefinition.SCOPE_PROTOTYPE); - if (definition instanceof AnnotatedBeanDefinition) { - AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition; - Set annTypes = annDef.getMetadata().getAnnotationTypes(); - String found = null; - for (String annType : annTypes) { - Set metaAnns = annDef.getMetadata().getMetaAnnotationTypes(annType); - if (metaAnns.contains("javax.inject.Scope")) { - if (found != null) { - throw new IllegalStateException("Found ambiguous scope annotations on bean class [" + - definition.getBeanClassName() + "]: " + found + ", " + annType); - } - found = annType; - String scopeName = resolveScopeName(annType); - if (scopeName == null) { - throw new IllegalStateException( - "Unsupported scope annotation - not mapped onto Spring scope name: " + annType); - } - metadata.setScopeName(scopeName); - } - } - } - return metadata; - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; +import org.springframework.beans.factory.config.BeanDefinition; + +/** + * Simple {@link ScopeMetadataResolver} implementation that follows JSR-330 scoping rules: + * defaulting to prototype scope unless {@link javax.inject.Singleton} is present. + * + *

This scope resolver can be used with {@link ClassPathBeanDefinitionScanner} and + * {@link AnnotatedBeanDefinitionReader} for standard JSR-330 compliance. However, + * in practice, you will typically use Spring's rich default scoping instead - or extend + * this resolver with custom scoping annotations that point to extended Spring scopes. + * + * @author Juergen Hoeller + * @since 3.0 + * @see #registerScope + * @see #resolveScopeName + * @see ClassPathBeanDefinitionScanner#setScopeMetadataResolver + * @see AnnotatedBeanDefinitionReader#setScopeMetadataResolver + */ +public class Jsr330ScopeMetadataResolver implements ScopeMetadataResolver { + + private final Map scopeMap = new HashMap(); + + + public Jsr330ScopeMetadataResolver() { + registerScope("javax.inject.Singleton", BeanDefinition.SCOPE_SINGLETON); + } + + + /** + * Register an extended JSR-330 scope annotation, mapping it onto a + * specific Spring scope by name. + * @param annotationType the JSR-330 annotation type as a Class + * @param scopeName the Spring scope name + */ + public final void registerScope(Class annotationType, String scopeName) { + this.scopeMap.put(annotationType.getName(), scopeName); + } + + /** + * Register an extended JSR-330 scope annotation, mapping it onto a + * specific Spring scope by name. + * @param annotationType the JSR-330 annotation type by name + * @param scopeName the Spring scope name + */ + public final void registerScope(String annotationType, String scopeName) { + this.scopeMap.put(annotationType, scopeName); + } + + /** + * Resolve the given annotation type into a named Spring scope. + *

The default implementation simply checks against registered scopes. + * Can be overridden for custom mapping rules, e.g. naming conventions. + * @param annotationType the JSR-330 annotation type + * @return the Spring scope name + */ + protected String resolveScopeName(String annotationType) { + return this.scopeMap.get(annotationType); + } + + + public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) { + ScopeMetadata metadata = new ScopeMetadata(); + metadata.setScopeName(BeanDefinition.SCOPE_PROTOTYPE); + if (definition instanceof AnnotatedBeanDefinition) { + AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition; + Set annTypes = annDef.getMetadata().getAnnotationTypes(); + String found = null; + for (String annType : annTypes) { + Set metaAnns = annDef.getMetadata().getMetaAnnotationTypes(annType); + if (metaAnns.contains("javax.inject.Scope")) { + if (found != null) { + throw new IllegalStateException("Found ambiguous scope annotations on bean class [" + + definition.getBeanClassName() + "]: " + found + ", " + annType); + } + found = annType; + String scopeName = resolveScopeName(annType); + if (scopeName == null) { + throw new IllegalStateException( + "Unsupported scope annotation - not mapped onto Spring scope name: " + annType); + } + metadata.setScopeName(scopeName); + } + } + } + return metadata; + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ScopedProxyCreator.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ScopedProxyCreator.java index 5ede63ea35..371c8b6674 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ScopedProxyCreator.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ScopedProxyCreator.java @@ -1,43 +1,43 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.annotation; - -import org.springframework.aop.scope.ScopedProxyUtils; -import org.springframework.beans.factory.config.BeanDefinitionHolder; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; - -/** - * Delegate factory class used to just introduce an AOP framework dependency - * when actually creating a scoped proxy. - * - * @author Juergen Hoeller - * @since 3.0 - * @see org.springframework.aop.scope.ScopedProxyUtils#createScopedProxy - */ -class ScopedProxyCreator { - - public static BeanDefinitionHolder createScopedProxy( - BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry, boolean proxyTargetClass) { - - return ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass); - } - - public static String getTargetBeanName(String originalBeanName) { - return ScopedProxyUtils.getTargetBeanName(originalBeanName); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import org.springframework.aop.scope.ScopedProxyUtils; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; + +/** + * Delegate factory class used to just introduce an AOP framework dependency + * when actually creating a scoped proxy. + * + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.aop.scope.ScopedProxyUtils#createScopedProxy + */ +class ScopedProxyCreator { + + public static BeanDefinitionHolder createScopedProxy( + BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry, boolean proxyTargetClass) { + + return ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass); + } + + public static String getTargetBeanName(String originalBeanName) { + return ScopedProxyUtils.getTargetBeanName(originalBeanName); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/event/GenericApplicationListenerAdapter.java b/org.springframework.context/src/main/java/org/springframework/context/event/GenericApplicationListenerAdapter.java index 087dcf46fa..5866212e87 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/event/GenericApplicationListenerAdapter.java +++ b/org.springframework.context/src/main/java/org/springframework/context/event/GenericApplicationListenerAdapter.java @@ -1,73 +1,73 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.event; - -import org.springframework.aop.support.AopUtils; -import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.core.GenericTypeResolver; -import org.springframework.core.Ordered; -import org.springframework.util.Assert; - -/** - * {@link SmartApplicationListener} adapter that determines supported event types - * through introspecting the generically declared type of the target listener. - * - * @author Juergen Hoeller - * @since 3.0 - * @see org.springframework.context.ApplicationListener#onApplicationEvent - */ -public class GenericApplicationListenerAdapter implements SmartApplicationListener { - - private final ApplicationListener delegate; - - - /** - * Create a new GenericApplicationListener for the given delegate. - * @param delegate the delegate listener to be invoked - */ - public GenericApplicationListenerAdapter(ApplicationListener delegate) { - Assert.notNull(delegate, "Delegate listener must not be null"); - this.delegate = delegate; - } - - - @SuppressWarnings("unchecked") - public void onApplicationEvent(ApplicationEvent event) { - this.delegate.onApplicationEvent(event); - } - - public boolean supportsEventType(Class eventType) { - Class typeArg = GenericTypeResolver.resolveTypeArgument(this.delegate.getClass(), ApplicationListener.class); - if (typeArg == null || typeArg.equals(ApplicationEvent.class)) { - Class targetClass = AopUtils.getTargetClass(this.delegate); - if (targetClass != this.delegate.getClass()) { - typeArg = GenericTypeResolver.resolveTypeArgument(targetClass, ApplicationListener.class); - } - } - return (typeArg == null || typeArg.isAssignableFrom(eventType)); - } - - public boolean supportsSourceType(Class sourceType) { - return true; - } - - public int getOrder() { - return (this.delegate instanceof Ordered ? ((Ordered) this.delegate).getOrder() : Ordered.LOWEST_PRECEDENCE); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.event; + +import org.springframework.aop.support.AopUtils; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.core.GenericTypeResolver; +import org.springframework.core.Ordered; +import org.springframework.util.Assert; + +/** + * {@link SmartApplicationListener} adapter that determines supported event types + * through introspecting the generically declared type of the target listener. + * + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.context.ApplicationListener#onApplicationEvent + */ +public class GenericApplicationListenerAdapter implements SmartApplicationListener { + + private final ApplicationListener delegate; + + + /** + * Create a new GenericApplicationListener for the given delegate. + * @param delegate the delegate listener to be invoked + */ + public GenericApplicationListenerAdapter(ApplicationListener delegate) { + Assert.notNull(delegate, "Delegate listener must not be null"); + this.delegate = delegate; + } + + + @SuppressWarnings("unchecked") + public void onApplicationEvent(ApplicationEvent event) { + this.delegate.onApplicationEvent(event); + } + + public boolean supportsEventType(Class eventType) { + Class typeArg = GenericTypeResolver.resolveTypeArgument(this.delegate.getClass(), ApplicationListener.class); + if (typeArg == null || typeArg.equals(ApplicationEvent.class)) { + Class targetClass = AopUtils.getTargetClass(this.delegate); + if (targetClass != this.delegate.getClass()) { + typeArg = GenericTypeResolver.resolveTypeArgument(targetClass, ApplicationListener.class); + } + } + return (typeArg == null || typeArg.isAssignableFrom(eventType)); + } + + public boolean supportsSourceType(Class sourceType) { + return true; + } + + public int getOrder() { + return (this.delegate instanceof Ordered ? ((Ordered) this.delegate).getOrder() : Ordered.LOWEST_PRECEDENCE); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/event/SmartApplicationListener.java b/org.springframework.context/src/main/java/org/springframework/context/event/SmartApplicationListener.java index 1dcd739e90..9fe22adaf1 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/event/SmartApplicationListener.java +++ b/org.springframework.context/src/main/java/org/springframework/context/event/SmartApplicationListener.java @@ -1,42 +1,42 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.event; - -import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.core.Ordered; - -/** - * Extended variant of the standard {@link ApplicationListener} interface, - * exposing further metadata such as the supported event type. - * - * @author Juergen Hoeller - * @since 3.0 - */ -public interface SmartApplicationListener extends ApplicationListener, Ordered { - - /** - * Determine whether this listener actually supports the given event type. - */ - boolean supportsEventType(Class eventType); - - /** - * Determine whether this listener actually supports the given source type. - */ - boolean supportsSourceType(Class sourceType); - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.event; + +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.core.Ordered; + +/** + * Extended variant of the standard {@link ApplicationListener} interface, + * exposing further metadata such as the supported event type. + * + * @author Juergen Hoeller + * @since 3.0 + */ +public interface SmartApplicationListener extends ApplicationListener, Ordered { + + /** + * Determine whether this listener actually supports the given event type. + */ + boolean supportsEventType(Class eventType); + + /** + * Determine whether this listener actually supports the given source type. + */ + boolean supportsSourceType(Class sourceType); + +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/expression/BeanExpressionContextAccessor.java b/org.springframework.context/src/main/java/org/springframework/context/expression/BeanExpressionContextAccessor.java index 89bc6b6a43..e81c929e81 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/expression/BeanExpressionContextAccessor.java +++ b/org.springframework.context/src/main/java/org/springframework/context/expression/BeanExpressionContextAccessor.java @@ -1,55 +1,55 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.expression; - -import org.springframework.beans.factory.config.BeanExpressionContext; -import org.springframework.expression.AccessException; -import org.springframework.expression.EvaluationContext; -import org.springframework.expression.PropertyAccessor; -import org.springframework.expression.TypedValue; - -/** - * EL property accessor that knows how to traverse the beans and contextual objects - * of a Spring {@link org.springframework.beans.factory.config.BeanExpressionContext}. - * - * @author Juergen Hoeller - * @author Andy Clement - * @since 3.0 - */ -public class BeanExpressionContextAccessor implements PropertyAccessor { - - public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { - return ((BeanExpressionContext) target).containsObject(name); - } - - public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { - return new TypedValue(((BeanExpressionContext) target).getObject(name)); - } - - public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { - return false; - } - - public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { - throw new AccessException("Beans in a BeanFactory are read-only"); - } - - public Class[] getSpecificTargetClasses() { - return new Class[] {BeanExpressionContext.class}; - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.expression; + +import org.springframework.beans.factory.config.BeanExpressionContext; +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.TypedValue; + +/** + * EL property accessor that knows how to traverse the beans and contextual objects + * of a Spring {@link org.springframework.beans.factory.config.BeanExpressionContext}. + * + * @author Juergen Hoeller + * @author Andy Clement + * @since 3.0 + */ +public class BeanExpressionContextAccessor implements PropertyAccessor { + + public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { + return ((BeanExpressionContext) target).containsObject(name); + } + + public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { + return new TypedValue(((BeanExpressionContext) target).getObject(name)); + } + + public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { + return false; + } + + public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { + throw new AccessException("Beans in a BeanFactory are read-only"); + } + + public Class[] getSpecificTargetClasses() { + return new Class[] {BeanExpressionContext.class}; + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/expression/BeanFactoryAccessor.java b/org.springframework.context/src/main/java/org/springframework/context/expression/BeanFactoryAccessor.java index 66157a604b..486ded925f 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/expression/BeanFactoryAccessor.java +++ b/org.springframework.context/src/main/java/org/springframework/context/expression/BeanFactoryAccessor.java @@ -1,55 +1,55 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.expression; - -import org.springframework.beans.factory.BeanFactory; -import org.springframework.expression.AccessException; -import org.springframework.expression.EvaluationContext; -import org.springframework.expression.PropertyAccessor; -import org.springframework.expression.TypedValue; - -/** - * EL property accessor that knows how to traverse the beans of a - * Spring {@link org.springframework.beans.factory.BeanFactory}. - * - * @author Juergen Hoeller - * @author Andy Clement - * @since 3.0 - */ -public class BeanFactoryAccessor implements PropertyAccessor { - - public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { - return (((BeanFactory) target).containsBean(name)); - } - - public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { - return new TypedValue(((BeanFactory) target).getBean(name)); - } - - public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { - return false; - } - - public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { - throw new AccessException("Beans in a BeanFactory are read-only"); - } - - public Class[] getSpecificTargetClasses() { - return new Class[] {BeanFactory.class}; - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.expression; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.TypedValue; + +/** + * EL property accessor that knows how to traverse the beans of a + * Spring {@link org.springframework.beans.factory.BeanFactory}. + * + * @author Juergen Hoeller + * @author Andy Clement + * @since 3.0 + */ +public class BeanFactoryAccessor implements PropertyAccessor { + + public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { + return (((BeanFactory) target).containsBean(name)); + } + + public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { + return new TypedValue(((BeanFactory) target).getBean(name)); + } + + public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { + return false; + } + + public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { + throw new AccessException("Beans in a BeanFactory are read-only"); + } + + public Class[] getSpecificTargetClasses() { + return new Class[] {BeanFactory.class}; + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/expression/BeanFactoryResolver.java b/org.springframework.context/src/main/java/org/springframework/context/expression/BeanFactoryResolver.java index 894a196f51..ff4aaaa78d 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/expression/BeanFactoryResolver.java +++ b/org.springframework.context/src/main/java/org/springframework/context/expression/BeanFactoryResolver.java @@ -1,51 +1,51 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.expression; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.expression.AccessException; -import org.springframework.expression.BeanResolver; -import org.springframework.expression.EvaluationContext; -import org.springframework.util.Assert; - -/** - * EL bean resolver that operates against a Spring - * {@link org.springframework.beans.factory.BeanFactory}. - * - * @author Juergen Hoeller - * @since 3.0.4 - */ -public class BeanFactoryResolver implements BeanResolver { - - private final BeanFactory beanFactory; - - public BeanFactoryResolver(BeanFactory beanFactory) { - Assert.notNull(beanFactory, "BeanFactory must not be null"); - this.beanFactory = beanFactory; - } - - public Object resolve(EvaluationContext context, String beanName) throws AccessException { - try { - return this.beanFactory.getBean(beanName); - } - catch (BeansException ex) { - throw new AccessException("Could not resolve bean reference against BeanFactory", ex); - } - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.expression; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.expression.AccessException; +import org.springframework.expression.BeanResolver; +import org.springframework.expression.EvaluationContext; +import org.springframework.util.Assert; + +/** + * EL bean resolver that operates against a Spring + * {@link org.springframework.beans.factory.BeanFactory}. + * + * @author Juergen Hoeller + * @since 3.0.4 + */ +public class BeanFactoryResolver implements BeanResolver { + + private final BeanFactory beanFactory; + + public BeanFactoryResolver(BeanFactory beanFactory) { + Assert.notNull(beanFactory, "BeanFactory must not be null"); + this.beanFactory = beanFactory; + } + + public Object resolve(EvaluationContext context, String beanName) throws AccessException { + try { + return this.beanFactory.getBean(beanName); + } + catch (BeansException ex) { + throw new AccessException("Could not resolve bean reference against BeanFactory", ex); + } + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/expression/MapAccessor.java b/org.springframework.context/src/main/java/org/springframework/context/expression/MapAccessor.java index bb523849b4..53ed9ce911 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/expression/MapAccessor.java +++ b/org.springframework.context/src/main/java/org/springframework/context/expression/MapAccessor.java @@ -1,84 +1,84 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.expression; - -import java.util.Map; - -import org.springframework.expression.AccessException; -import org.springframework.expression.EvaluationContext; -import org.springframework.expression.PropertyAccessor; -import org.springframework.expression.TypedValue; - -/** - * EL property accessor that knows how to traverse the keys - * of a standard {@link java.util.Map}. - * - * @author Juergen Hoeller - * @author Andy Clement - * @since 3.0 - */ -public class MapAccessor implements PropertyAccessor { - - public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { - Map map = (Map) target; - return map.containsKey(name); - } - - public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { - Map map = (Map) target; - Object value = map.get(name); - if (value == null && !map.containsKey(name)) { - throw new MapAccessException(name); - } - return new TypedValue(value); - } - - public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { - return true; - } - - @SuppressWarnings("unchecked") - public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { - Map map = (Map) target; - map.put(name, newValue); - } - - public Class[] getSpecificTargetClasses() { - return new Class[] {Map.class}; - } - - - /** - * Exception thrown from read in order to reset a cached - * PropertyAccessor, allowing other accessors to have a try. - */ - private static class MapAccessException extends AccessException { - - private final String key; - - public MapAccessException(String key) { - super(null); - this.key = key; - } - - @Override - public String getMessage() { - return "Map does not contain a value for key '" + this.key + "'"; - } - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.expression; + +import java.util.Map; + +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.TypedValue; + +/** + * EL property accessor that knows how to traverse the keys + * of a standard {@link java.util.Map}. + * + * @author Juergen Hoeller + * @author Andy Clement + * @since 3.0 + */ +public class MapAccessor implements PropertyAccessor { + + public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { + Map map = (Map) target; + return map.containsKey(name); + } + + public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { + Map map = (Map) target; + Object value = map.get(name); + if (value == null && !map.containsKey(name)) { + throw new MapAccessException(name); + } + return new TypedValue(value); + } + + public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { + return true; + } + + @SuppressWarnings("unchecked") + public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { + Map map = (Map) target; + map.put(name, newValue); + } + + public Class[] getSpecificTargetClasses() { + return new Class[] {Map.class}; + } + + + /** + * Exception thrown from read in order to reset a cached + * PropertyAccessor, allowing other accessors to have a try. + */ + private static class MapAccessException extends AccessException { + + private final String key; + + public MapAccessException(String key) { + super(null); + this.key = key; + } + + @Override + public String getMessage() { + return "Map does not contain a value for key '" + this.key + "'"; + } + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/expression/StandardBeanExpressionResolver.java b/org.springframework.context/src/main/java/org/springframework/context/expression/StandardBeanExpressionResolver.java index 9fb1960952..80b546f2e6 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/expression/StandardBeanExpressionResolver.java +++ b/org.springframework.context/src/main/java/org/springframework/context/expression/StandardBeanExpressionResolver.java @@ -1,153 +1,153 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.expression; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanExpressionException; -import org.springframework.beans.factory.config.BeanExpressionContext; -import org.springframework.beans.factory.config.BeanExpressionResolver; -import org.springframework.core.convert.ConversionService; -import org.springframework.expression.Expression; -import org.springframework.expression.ExpressionParser; -import org.springframework.expression.ParserContext; -import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.expression.spel.support.StandardEvaluationContext; -import org.springframework.expression.spel.support.StandardTypeConverter; -import org.springframework.expression.spel.support.StandardTypeLocator; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -/** - * Standard implementation of the - * {@link org.springframework.beans.factory.config.BeanExpressionResolver} - * interface, parsing and evaluating Spring EL using Spring's expression module. - * - * @author Juergen Hoeller - * @since 3.0 - * @see org.springframework.expression.ExpressionParser - * @see org.springframework.expression.spel.standard.SpelExpressionParser - * @see org.springframework.expression.spel.support.StandardEvaluationContext - */ -public class StandardBeanExpressionResolver implements BeanExpressionResolver { - - /** Default expression prefix: "#{" */ - public static final String DEFAULT_EXPRESSION_PREFIX = "#{"; - - /** Default expression suffix: "}" */ - public static final String DEFAULT_EXPRESSION_SUFFIX = "}"; - - - private String expressionPrefix = DEFAULT_EXPRESSION_PREFIX; - - private String expressionSuffix = DEFAULT_EXPRESSION_SUFFIX; - - private ExpressionParser expressionParser = new SpelExpressionParser(); - - private final Map expressionCache = new ConcurrentHashMap(); - - private final Map evaluationCache = - new ConcurrentHashMap(); - - private final ParserContext beanExpressionParserContext = new ParserContext() { - public boolean isTemplate() { - return true; - } - public String getExpressionPrefix() { - return expressionPrefix; - } - public String getExpressionSuffix() { - return expressionSuffix; - } - }; - - - /** - * Set the prefix that an expression string starts with. - * The default is "#{". - * @see #DEFAULT_EXPRESSION_PREFIX - */ - public void setExpressionPrefix(String expressionPrefix) { - Assert.hasText(expressionPrefix, "Expression prefix must not be empty"); - this.expressionPrefix = expressionPrefix; - } - - /** - * Set the suffix that an expression string ends with. - * The default is "}". - * @see #DEFAULT_EXPRESSION_SUFFIX - */ - public void setExpressionSuffix(String expressionSuffix) { - Assert.hasText(expressionSuffix, "Expression suffix must not be empty"); - this.expressionSuffix = expressionSuffix; - } - - /** - * Specify the EL parser to use for expression parsing. - *

Default is a {@link org.springframework.expression.spel.standard.SpelExpressionParser}, - * compatible with standard Unified EL style expression syntax. - */ - public void setExpressionParser(ExpressionParser expressionParser) { - Assert.notNull(expressionParser, "ExpressionParser must not be null"); - this.expressionParser = expressionParser; - } - - - public Object evaluate(String value, BeanExpressionContext evalContext) throws BeansException { - if (!StringUtils.hasLength(value)) { - return value; - } - try { - Expression expr = this.expressionCache.get(value); - if (expr == null) { - expr = this.expressionParser.parseExpression(value, this.beanExpressionParserContext); - this.expressionCache.put(value, expr); - } - StandardEvaluationContext sec = this.evaluationCache.get(evalContext); - if (sec == null) { - sec = new StandardEvaluationContext(); - sec.setRootObject(evalContext); - sec.addPropertyAccessor(new BeanExpressionContextAccessor()); - sec.addPropertyAccessor(new BeanFactoryAccessor()); - sec.addPropertyAccessor(new MapAccessor()); - sec.addPropertyAccessor(new EnvironmentAccessor()); - sec.setBeanResolver(new BeanFactoryResolver(evalContext.getBeanFactory())); - sec.setTypeLocator(new StandardTypeLocator(evalContext.getBeanFactory().getBeanClassLoader())); - ConversionService conversionService = evalContext.getBeanFactory().getConversionService(); - if (conversionService != null) { - sec.setTypeConverter(new StandardTypeConverter(conversionService)); - } - customizeEvaluationContext(sec); - this.evaluationCache.put(evalContext, sec); - } - return expr.getValue(sec); - } - catch (Exception ex) { - throw new BeanExpressionException("Expression parsing failed", ex); - } - } - - /** - * Template method for customizing the expression evaluation context. - *

The default implementation is empty. - */ - protected void customizeEvaluationContext(StandardEvaluationContext evalContext) { - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.expression; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanExpressionException; +import org.springframework.beans.factory.config.BeanExpressionContext; +import org.springframework.beans.factory.config.BeanExpressionResolver; +import org.springframework.core.convert.ConversionService; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.ParserContext; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.expression.spel.support.StandardTypeConverter; +import org.springframework.expression.spel.support.StandardTypeLocator; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * Standard implementation of the + * {@link org.springframework.beans.factory.config.BeanExpressionResolver} + * interface, parsing and evaluating Spring EL using Spring's expression module. + * + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.expression.ExpressionParser + * @see org.springframework.expression.spel.standard.SpelExpressionParser + * @see org.springframework.expression.spel.support.StandardEvaluationContext + */ +public class StandardBeanExpressionResolver implements BeanExpressionResolver { + + /** Default expression prefix: "#{" */ + public static final String DEFAULT_EXPRESSION_PREFIX = "#{"; + + /** Default expression suffix: "}" */ + public static final String DEFAULT_EXPRESSION_SUFFIX = "}"; + + + private String expressionPrefix = DEFAULT_EXPRESSION_PREFIX; + + private String expressionSuffix = DEFAULT_EXPRESSION_SUFFIX; + + private ExpressionParser expressionParser = new SpelExpressionParser(); + + private final Map expressionCache = new ConcurrentHashMap(); + + private final Map evaluationCache = + new ConcurrentHashMap(); + + private final ParserContext beanExpressionParserContext = new ParserContext() { + public boolean isTemplate() { + return true; + } + public String getExpressionPrefix() { + return expressionPrefix; + } + public String getExpressionSuffix() { + return expressionSuffix; + } + }; + + + /** + * Set the prefix that an expression string starts with. + * The default is "#{". + * @see #DEFAULT_EXPRESSION_PREFIX + */ + public void setExpressionPrefix(String expressionPrefix) { + Assert.hasText(expressionPrefix, "Expression prefix must not be empty"); + this.expressionPrefix = expressionPrefix; + } + + /** + * Set the suffix that an expression string ends with. + * The default is "}". + * @see #DEFAULT_EXPRESSION_SUFFIX + */ + public void setExpressionSuffix(String expressionSuffix) { + Assert.hasText(expressionSuffix, "Expression suffix must not be empty"); + this.expressionSuffix = expressionSuffix; + } + + /** + * Specify the EL parser to use for expression parsing. + *

Default is a {@link org.springframework.expression.spel.standard.SpelExpressionParser}, + * compatible with standard Unified EL style expression syntax. + */ + public void setExpressionParser(ExpressionParser expressionParser) { + Assert.notNull(expressionParser, "ExpressionParser must not be null"); + this.expressionParser = expressionParser; + } + + + public Object evaluate(String value, BeanExpressionContext evalContext) throws BeansException { + if (!StringUtils.hasLength(value)) { + return value; + } + try { + Expression expr = this.expressionCache.get(value); + if (expr == null) { + expr = this.expressionParser.parseExpression(value, this.beanExpressionParserContext); + this.expressionCache.put(value, expr); + } + StandardEvaluationContext sec = this.evaluationCache.get(evalContext); + if (sec == null) { + sec = new StandardEvaluationContext(); + sec.setRootObject(evalContext); + sec.addPropertyAccessor(new BeanExpressionContextAccessor()); + sec.addPropertyAccessor(new BeanFactoryAccessor()); + sec.addPropertyAccessor(new MapAccessor()); + sec.addPropertyAccessor(new EnvironmentAccessor()); + sec.setBeanResolver(new BeanFactoryResolver(evalContext.getBeanFactory())); + sec.setTypeLocator(new StandardTypeLocator(evalContext.getBeanFactory().getBeanClassLoader())); + ConversionService conversionService = evalContext.getBeanFactory().getConversionService(); + if (conversionService != null) { + sec.setTypeConverter(new StandardTypeConverter(conversionService)); + } + customizeEvaluationContext(sec); + this.evaluationCache.put(evalContext, sec); + } + return expr.getValue(sec); + } + catch (Exception ex) { + throw new BeanExpressionException("Expression parsing failed", ex); + } + } + + /** + * Template method for customizing the expression evaluation context. + *

The default implementation is empty. + */ + protected void customizeEvaluationContext(StandardEvaluationContext evalContext) { + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/context/support/GenericXmlApplicationContext.java b/org.springframework.context/src/main/java/org/springframework/context/support/GenericXmlApplicationContext.java index b276ba04a0..00b6555849 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/support/GenericXmlApplicationContext.java +++ b/org.springframework.context/src/main/java/org/springframework/context/support/GenericXmlApplicationContext.java @@ -1,134 +1,134 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.support; - -import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; - -/** - * Convenient application context with built-in XML support. - * This is a flexible alternative to {@link ClassPathXmlApplicationContext} - * and {@link FileSystemXmlApplicationContext}, to be configured via setters, - * with an eventual {@link #refresh()} call activating the context. - * - *

In case of multiple configuration files, bean definitions in later files - * will override those defined in earlier files. This can be leveraged to - * deliberately override certain bean definitions via an extra configuration file. - * - * @author Juergen Hoeller - * @author Chris Beams - * @since 3.0 - * @see #load - * @see XmlBeanDefinitionReader - * @see org.springframework.context.annotation.AnnotationConfigApplicationContext - */ -public class GenericXmlApplicationContext extends GenericApplicationContext { - - private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this); - - - /** - * Create a new GenericXmlApplicationContext that needs to be - * {@linkplain #load loaded} and then manually {@link #refresh refreshed}. - */ - public GenericXmlApplicationContext() { - reader.setEnvironment(this.getEnvironment()); - } - - /** - * Create a new GenericXmlApplicationContext, loading bean definitions - * from the given resources and automatically refreshing the context. - * @param resources the resources to load from - */ - public GenericXmlApplicationContext(Resource... resources) { - load(resources); - refresh(); - } - - /** - * Create a new GenericXmlApplicationContext, loading bean definitions - * from the given resource locations and automatically refreshing the context. - * @param resourceLocations the resources to load from - */ - public GenericXmlApplicationContext(String... resourceLocations) { - load(resourceLocations); - refresh(); - } - - /** - * Create a new GenericXmlApplicationContext, loading bean definitions - * from the given resource locations and automatically refreshing the context. - * @param relativeClass class whose package will be used as a prefix when - * loading each specified resource name - * @param resourceNames relatively-qualified names of resources to load - */ - public GenericXmlApplicationContext(Class relativeClass, String... resourceNames) { - load(relativeClass, resourceNames); - refresh(); - } - - /** - * Set whether to use XML validation. Default is true. - */ - public void setValidating(boolean validating) { - this.reader.setValidating(validating); - } - - /** - * {@inheritDoc} - *

Delegates the given environment to underlying {@link XmlBeanDefinitionReader}. - * Should be called before any call to {@link #load}. - */ - @Override - public void setEnvironment(ConfigurableEnvironment environment) { - super.setEnvironment(environment); - this.reader.setEnvironment(this.getEnvironment()); - } - - /** - * Load bean definitions from the given XML resources. - * @param resources one or more resources to load from - */ - public void load(Resource... resources) { - this.reader.loadBeanDefinitions(resources); - } - - /** - * Load bean definitions from the given XML resources. - * @param resourceLocations one or more resource locations to load from - */ - public void load(String... resourceLocations) { - this.reader.loadBeanDefinitions(resourceLocations); - } - - /** - * Load bean definitions from the given XML resources. - * @param relativeClass class whose package will be used as a prefix when - * loading each specified resource name - * @param resourceNames relatively-qualified names of resources to load - */ - public void load(Class relativeClass, String... resourceNames) { - Resource[] resources = new Resource[resourceNames.length]; - for (int i = 0; i < resourceNames.length; i++) { - resources[i] = new ClassPathResource(resourceNames[i], relativeClass); - } - this.load(resources); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.support; + +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +/** + * Convenient application context with built-in XML support. + * This is a flexible alternative to {@link ClassPathXmlApplicationContext} + * and {@link FileSystemXmlApplicationContext}, to be configured via setters, + * with an eventual {@link #refresh()} call activating the context. + * + *

In case of multiple configuration files, bean definitions in later files + * will override those defined in earlier files. This can be leveraged to + * deliberately override certain bean definitions via an extra configuration file. + * + * @author Juergen Hoeller + * @author Chris Beams + * @since 3.0 + * @see #load + * @see XmlBeanDefinitionReader + * @see org.springframework.context.annotation.AnnotationConfigApplicationContext + */ +public class GenericXmlApplicationContext extends GenericApplicationContext { + + private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this); + + + /** + * Create a new GenericXmlApplicationContext that needs to be + * {@linkplain #load loaded} and then manually {@link #refresh refreshed}. + */ + public GenericXmlApplicationContext() { + reader.setEnvironment(this.getEnvironment()); + } + + /** + * Create a new GenericXmlApplicationContext, loading bean definitions + * from the given resources and automatically refreshing the context. + * @param resources the resources to load from + */ + public GenericXmlApplicationContext(Resource... resources) { + load(resources); + refresh(); + } + + /** + * Create a new GenericXmlApplicationContext, loading bean definitions + * from the given resource locations and automatically refreshing the context. + * @param resourceLocations the resources to load from + */ + public GenericXmlApplicationContext(String... resourceLocations) { + load(resourceLocations); + refresh(); + } + + /** + * Create a new GenericXmlApplicationContext, loading bean definitions + * from the given resource locations and automatically refreshing the context. + * @param relativeClass class whose package will be used as a prefix when + * loading each specified resource name + * @param resourceNames relatively-qualified names of resources to load + */ + public GenericXmlApplicationContext(Class relativeClass, String... resourceNames) { + load(relativeClass, resourceNames); + refresh(); + } + + /** + * Set whether to use XML validation. Default is true. + */ + public void setValidating(boolean validating) { + this.reader.setValidating(validating); + } + + /** + * {@inheritDoc} + *

Delegates the given environment to underlying {@link XmlBeanDefinitionReader}. + * Should be called before any call to {@link #load}. + */ + @Override + public void setEnvironment(ConfigurableEnvironment environment) { + super.setEnvironment(environment); + this.reader.setEnvironment(this.getEnvironment()); + } + + /** + * Load bean definitions from the given XML resources. + * @param resources one or more resources to load from + */ + public void load(Resource... resources) { + this.reader.loadBeanDefinitions(resources); + } + + /** + * Load bean definitions from the given XML resources. + * @param resourceLocations one or more resource locations to load from + */ + public void load(String... resourceLocations) { + this.reader.loadBeanDefinitions(resourceLocations); + } + + /** + * Load bean definitions from the given XML resources. + * @param relativeClass class whose package will be used as a prefix when + * loading each specified resource name + * @param resourceNames relatively-qualified names of resources to load + */ + public void load(Class relativeClass, String... resourceNames) { + Resource[] resources = new Resource[resourceNames.length]; + for (int i = 0; i < resourceNames.length; i++) { + resources[i] = new ClassPathResource(resourceNames[i], relativeClass); + } + this.load(resources); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/format/number/AbstractNumberFormatter.java b/org.springframework.context/src/main/java/org/springframework/format/number/AbstractNumberFormatter.java index 63795d6e80..0d1d5aa973 100644 --- a/org.springframework.context/src/main/java/org/springframework/format/number/AbstractNumberFormatter.java +++ b/org.springframework.context/src/main/java/org/springframework/format/number/AbstractNumberFormatter.java @@ -1,74 +1,74 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.format.number; - -import java.text.NumberFormat; -import java.text.ParseException; -import java.text.ParsePosition; -import java.util.Locale; - -import org.springframework.format.Formatter; - -/** - * Abstract formatter for Numbers, - * providing a {@link #getNumberFormat(java.util.Locale)} template method. - * - * @author Juergen Hoeller - * @author Keith Donald - * @since 3.0 - */ -public abstract class AbstractNumberFormatter implements Formatter { - - private boolean lenient = false; - - /** - * Specify whether or not parsing is to be lenient. Default is false. - *

With lenient parsing, the parser may allow inputs that do not precisely match the format. - * With strict parsing, inputs must match the format exactly. - */ - public void setLenient(boolean lenient) { - this.lenient = lenient; - } - - public String print(Number number, Locale locale) { - return getNumberFormat(locale).format(number); - } - - public Number parse(String text, Locale locale) throws ParseException { - NumberFormat format = getNumberFormat(locale); - ParsePosition position = new ParsePosition(0); - Number number = format.parse(text, position); - if (position.getErrorIndex() != -1) { - throw new ParseException(text, position.getIndex()); - } - if (!this.lenient) { - if (text.length() != position.getIndex()) { - // indicates a part of the string that was not parsed - throw new ParseException(text, position.getIndex()); - } - } - return number; - } - - /** - * Obtain a concrete NumberFormat for the specified locale. - * @param locale the current locale - * @return the NumberFormat instance (never null) - */ - protected abstract NumberFormat getNumberFormat(Locale locale); - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.format.number; + +import java.text.NumberFormat; +import java.text.ParseException; +import java.text.ParsePosition; +import java.util.Locale; + +import org.springframework.format.Formatter; + +/** + * Abstract formatter for Numbers, + * providing a {@link #getNumberFormat(java.util.Locale)} template method. + * + * @author Juergen Hoeller + * @author Keith Donald + * @since 3.0 + */ +public abstract class AbstractNumberFormatter implements Formatter { + + private boolean lenient = false; + + /** + * Specify whether or not parsing is to be lenient. Default is false. + *

With lenient parsing, the parser may allow inputs that do not precisely match the format. + * With strict parsing, inputs must match the format exactly. + */ + public void setLenient(boolean lenient) { + this.lenient = lenient; + } + + public String print(Number number, Locale locale) { + return getNumberFormat(locale).format(number); + } + + public Number parse(String text, Locale locale) throws ParseException { + NumberFormat format = getNumberFormat(locale); + ParsePosition position = new ParsePosition(0); + Number number = format.parse(text, position); + if (position.getErrorIndex() != -1) { + throw new ParseException(text, position.getIndex()); + } + if (!this.lenient) { + if (text.length() != position.getIndex()) { + // indicates a part of the string that was not parsed + throw new ParseException(text, position.getIndex()); + } + } + return number; + } + + /** + * Obtain a concrete NumberFormat for the specified locale. + * @param locale the current locale + * @return the NumberFormat instance (never null) + */ + protected abstract NumberFormat getNumberFormat(Locale locale); + +} diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/glassfish/GlassFishClassLoaderAdapter.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/glassfish/GlassFishClassLoaderAdapter.java index 550ef939fb..8d114b2bec 100644 --- a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/glassfish/GlassFishClassLoaderAdapter.java +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/glassfish/GlassFishClassLoaderAdapter.java @@ -1,128 +1,128 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.instrument.classloading.glassfish; - -import java.lang.instrument.ClassFileTransformer; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * Reflective wrapper around the GlassFish class loader. Used to - * encapsulate the classloader-specific methods (discovered and - * called through reflection) from the load-time weaver. - * - *

Supports GlassFish V1, V2 and V3 (currently in beta). - * - * @author Costin Leau - * @since 3.0 - */ -class GlassFishClassLoaderAdapter { - - static final String INSTRUMENTABLE_CLASSLOADER_GLASSFISH_V2 = "com.sun.enterprise.loader.InstrumentableClassLoader"; - - static final String INSTRUMENTABLE_CLASSLOADER_GLASSFISH_V3 = "org.glassfish.api.deployment.InstrumentableClassLoader"; - - private static final String CLASS_TRANSFORMER = "javax.persistence.spi.ClassTransformer"; - - - private final ClassLoader classLoader; - - private final Method addTransformer; - - private final Method copy; - - private final boolean glassFishV3; - - - public GlassFishClassLoaderAdapter(ClassLoader classLoader) { - Class instrumentableLoaderClass; - boolean glassV3 = false; - try { - // try the V1/V2 API first - instrumentableLoaderClass = classLoader.loadClass(INSTRUMENTABLE_CLASSLOADER_GLASSFISH_V2); - } - catch (ClassNotFoundException ex) { - // fall back to V3 - try { - instrumentableLoaderClass = classLoader.loadClass(INSTRUMENTABLE_CLASSLOADER_GLASSFISH_V3); - glassV3 = true; - } - catch (ClassNotFoundException cnfe) { - throw new IllegalStateException("Could not initialize GlassFish LoadTimeWeaver because " + - "GlassFish (V1, V2 or V3) API classes are not available", ex); - } - } - try { - Class classTransformerClass = - (glassV3 ? ClassFileTransformer.class : classLoader.loadClass(CLASS_TRANSFORMER)); - - this.addTransformer = instrumentableLoaderClass.getMethod("addTransformer", classTransformerClass); - this.copy = instrumentableLoaderClass.getMethod("copy"); - } - catch (Exception ex) { - throw new IllegalStateException( - "Could not initialize GlassFish LoadTimeWeaver because GlassFish API classes are not available", ex); - } - - ClassLoader clazzLoader = null; - // Detect transformation-aware ClassLoader by traversing the hierarchy - // (as in GlassFish, Spring can be loaded by the WebappClassLoader). - for (ClassLoader cl = classLoader; cl != null && clazzLoader == null; cl = cl.getParent()) { - if (instrumentableLoaderClass.isInstance(cl)) { - clazzLoader = cl; - } - } - - if (clazzLoader == null) { - throw new IllegalArgumentException(classLoader + " and its parents are not suitable ClassLoaders: A [" + - instrumentableLoaderClass.getName() + "] implementation is required."); - } - - this.classLoader = clazzLoader; - this.glassFishV3 = glassV3; - } - - public void addTransformer(ClassFileTransformer transformer) { - try { - this.addTransformer.invoke(this.classLoader, - (this.glassFishV3 ? transformer : new ClassTransformerAdapter(transformer))); - } - catch (InvocationTargetException ex) { - throw new IllegalStateException("GlassFish addTransformer method threw exception ", ex.getCause()); - } - catch (Exception ex) { - throw new IllegalStateException("Could not invoke GlassFish addTransformer method", ex); - } - } - - public ClassLoader getClassLoader() { - return this.classLoader; - } - - public ClassLoader getThrowawayClassLoader() { - try { - return (ClassLoader) this.copy.invoke(this.classLoader); - } - catch (InvocationTargetException ex) { - throw new IllegalStateException("GlassFish copy method threw exception ", ex.getCause()); - } - catch (Exception ex) { - throw new IllegalStateException("Could not invoke GlassFish copy method", ex); - } - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.instrument.classloading.glassfish; + +import java.lang.instrument.ClassFileTransformer; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Reflective wrapper around the GlassFish class loader. Used to + * encapsulate the classloader-specific methods (discovered and + * called through reflection) from the load-time weaver. + * + *

Supports GlassFish V1, V2 and V3 (currently in beta). + * + * @author Costin Leau + * @since 3.0 + */ +class GlassFishClassLoaderAdapter { + + static final String INSTRUMENTABLE_CLASSLOADER_GLASSFISH_V2 = "com.sun.enterprise.loader.InstrumentableClassLoader"; + + static final String INSTRUMENTABLE_CLASSLOADER_GLASSFISH_V3 = "org.glassfish.api.deployment.InstrumentableClassLoader"; + + private static final String CLASS_TRANSFORMER = "javax.persistence.spi.ClassTransformer"; + + + private final ClassLoader classLoader; + + private final Method addTransformer; + + private final Method copy; + + private final boolean glassFishV3; + + + public GlassFishClassLoaderAdapter(ClassLoader classLoader) { + Class instrumentableLoaderClass; + boolean glassV3 = false; + try { + // try the V1/V2 API first + instrumentableLoaderClass = classLoader.loadClass(INSTRUMENTABLE_CLASSLOADER_GLASSFISH_V2); + } + catch (ClassNotFoundException ex) { + // fall back to V3 + try { + instrumentableLoaderClass = classLoader.loadClass(INSTRUMENTABLE_CLASSLOADER_GLASSFISH_V3); + glassV3 = true; + } + catch (ClassNotFoundException cnfe) { + throw new IllegalStateException("Could not initialize GlassFish LoadTimeWeaver because " + + "GlassFish (V1, V2 or V3) API classes are not available", ex); + } + } + try { + Class classTransformerClass = + (glassV3 ? ClassFileTransformer.class : classLoader.loadClass(CLASS_TRANSFORMER)); + + this.addTransformer = instrumentableLoaderClass.getMethod("addTransformer", classTransformerClass); + this.copy = instrumentableLoaderClass.getMethod("copy"); + } + catch (Exception ex) { + throw new IllegalStateException( + "Could not initialize GlassFish LoadTimeWeaver because GlassFish API classes are not available", ex); + } + + ClassLoader clazzLoader = null; + // Detect transformation-aware ClassLoader by traversing the hierarchy + // (as in GlassFish, Spring can be loaded by the WebappClassLoader). + for (ClassLoader cl = classLoader; cl != null && clazzLoader == null; cl = cl.getParent()) { + if (instrumentableLoaderClass.isInstance(cl)) { + clazzLoader = cl; + } + } + + if (clazzLoader == null) { + throw new IllegalArgumentException(classLoader + " and its parents are not suitable ClassLoaders: A [" + + instrumentableLoaderClass.getName() + "] implementation is required."); + } + + this.classLoader = clazzLoader; + this.glassFishV3 = glassV3; + } + + public void addTransformer(ClassFileTransformer transformer) { + try { + this.addTransformer.invoke(this.classLoader, + (this.glassFishV3 ? transformer : new ClassTransformerAdapter(transformer))); + } + catch (InvocationTargetException ex) { + throw new IllegalStateException("GlassFish addTransformer method threw exception ", ex.getCause()); + } + catch (Exception ex) { + throw new IllegalStateException("Could not invoke GlassFish addTransformer method", ex); + } + } + + public ClassLoader getClassLoader() { + return this.classLoader; + } + + public ClassLoader getThrowawayClassLoader() { + try { + return (ClassLoader) this.copy.invoke(this.classLoader); + } + catch (InvocationTargetException ex) { + throw new IllegalStateException("GlassFish copy method threw exception ", ex.getCause()); + } + catch (Exception ex) { + throw new IllegalStateException("Could not invoke GlassFish copy method", ex); + } + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossClassLoaderAdapter.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossClassLoaderAdapter.java index 38126a76cd..e4b448017e 100644 --- a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossClassLoaderAdapter.java +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossClassLoaderAdapter.java @@ -1,33 +1,33 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.jboss; - -import java.lang.instrument.ClassFileTransformer; - -/** - * Simple interface used for handling the different JBoss class loader adapters. - * - * @author Costin Leau - * @since 3.1 - */ -interface JBossClassLoaderAdapter { - - void addTransformer(ClassFileTransformer transformer); - - ClassLoader getInstrumentableClassLoader(); - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.jboss; + +import java.lang.instrument.ClassFileTransformer; + +/** + * Simple interface used for handling the different JBoss class loader adapters. + * + * @author Costin Leau + * @since 3.1 + */ +interface JBossClassLoaderAdapter { + + void addTransformer(ClassFileTransformer transformer); + + ClassLoader getInstrumentableClassLoader(); + +} diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossLoadTimeWeaver.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossLoadTimeWeaver.java index b182c7181c..243724af27 100644 --- a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossLoadTimeWeaver.java +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossLoadTimeWeaver.java @@ -1,91 +1,91 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.jboss; - -import java.lang.instrument.ClassFileTransformer; - -import org.springframework.instrument.classloading.LoadTimeWeaver; -import org.springframework.instrument.classloading.SimpleThrowawayClassLoader; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; - -/** - * {@link LoadTimeWeaver} implementation for JBoss's instrumentable ClassLoader. - * Autodetects the specific JBoss version at runtime: currently supports - * JBoss AS 5, 6 and 7 (as of Spring 3.1). - * - *

NOTE: On JBoss 6.0, to avoid the container loading the classes before the - * application actually starts, one needs to add a WEB-INF/jboss-scanning.xml - * file to the application archive - with the following content: - *

<scanning xmlns="urn:jboss:scanning:1.0"/>
- * - *

Thanks to Ales Justin and Marius Bogoevici for the initial prototype. - * - * @author Costin Leau - * @since 3.0 - */ -public class JBossLoadTimeWeaver implements LoadTimeWeaver { - - private final JBossClassLoaderAdapter adapter; - - - /** - * Create a new instance of the {@link JBossLoadTimeWeaver} class using - * the default {@link ClassLoader class loader}. - * @see org.springframework.util.ClassUtils#getDefaultClassLoader() - */ - public JBossLoadTimeWeaver() { - this(ClassUtils.getDefaultClassLoader()); - } - - /** - * Create a new instance of the {@link JBossLoadTimeWeaver} class using - * the supplied {@link ClassLoader}. - * @param classLoader the ClassLoader to delegate to for - * weaving (must not be null) - */ - public JBossLoadTimeWeaver(ClassLoader classLoader) { - Assert.notNull(classLoader, "ClassLoader must not be null"); - String loaderClassName = classLoader.getClass().getName(); - - if (loaderClassName.startsWith("org.jboss.classloader")) { - // JBoss AS 5 or JBoss AS 6 - this.adapter = new JBossMCAdapter(classLoader); - } - else if (loaderClassName.startsWith("org.jboss.modules")) { - // JBoss AS 7 - this.adapter = new JBossModulesAdapter(classLoader); - } - else { - throw new IllegalArgumentException("Unexpected ClassLoader type: " + loaderClassName); - } - } - - - public void addTransformer(ClassFileTransformer transformer) { - this.adapter.addTransformer(transformer); - } - - public ClassLoader getInstrumentableClassLoader() { - return this.adapter.getInstrumentableClassLoader(); - } - - public ClassLoader getThrowawayClassLoader() { - return new SimpleThrowawayClassLoader(getInstrumentableClassLoader()); - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.jboss; + +import java.lang.instrument.ClassFileTransformer; + +import org.springframework.instrument.classloading.LoadTimeWeaver; +import org.springframework.instrument.classloading.SimpleThrowawayClassLoader; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; + +/** + * {@link LoadTimeWeaver} implementation for JBoss's instrumentable ClassLoader. + * Autodetects the specific JBoss version at runtime: currently supports + * JBoss AS 5, 6 and 7 (as of Spring 3.1). + * + *

NOTE: On JBoss 6.0, to avoid the container loading the classes before the + * application actually starts, one needs to add a WEB-INF/jboss-scanning.xml + * file to the application archive - with the following content: + *

<scanning xmlns="urn:jboss:scanning:1.0"/>
+ * + *

Thanks to Ales Justin and Marius Bogoevici for the initial prototype. + * + * @author Costin Leau + * @since 3.0 + */ +public class JBossLoadTimeWeaver implements LoadTimeWeaver { + + private final JBossClassLoaderAdapter adapter; + + + /** + * Create a new instance of the {@link JBossLoadTimeWeaver} class using + * the default {@link ClassLoader class loader}. + * @see org.springframework.util.ClassUtils#getDefaultClassLoader() + */ + public JBossLoadTimeWeaver() { + this(ClassUtils.getDefaultClassLoader()); + } + + /** + * Create a new instance of the {@link JBossLoadTimeWeaver} class using + * the supplied {@link ClassLoader}. + * @param classLoader the ClassLoader to delegate to for + * weaving (must not be null) + */ + public JBossLoadTimeWeaver(ClassLoader classLoader) { + Assert.notNull(classLoader, "ClassLoader must not be null"); + String loaderClassName = classLoader.getClass().getName(); + + if (loaderClassName.startsWith("org.jboss.classloader")) { + // JBoss AS 5 or JBoss AS 6 + this.adapter = new JBossMCAdapter(classLoader); + } + else if (loaderClassName.startsWith("org.jboss.modules")) { + // JBoss AS 7 + this.adapter = new JBossModulesAdapter(classLoader); + } + else { + throw new IllegalArgumentException("Unexpected ClassLoader type: " + loaderClassName); + } + } + + + public void addTransformer(ClassFileTransformer transformer) { + this.adapter.addTransformer(transformer); + } + + public ClassLoader getInstrumentableClassLoader() { + return this.adapter.getInstrumentableClassLoader(); + } + + public ClassLoader getThrowawayClassLoader() { + return new SimpleThrowawayClassLoader(getInstrumentableClassLoader()); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossMCAdapter.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossMCAdapter.java index 4e7d16bcfd..5216b5cd50 100644 --- a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossMCAdapter.java +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossMCAdapter.java @@ -1,145 +1,145 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.jboss; - -import java.lang.instrument.ClassFileTransformer; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -import org.springframework.util.Assert; -import org.springframework.util.ReflectionUtils; - -/** - * Reflective wrapper around a JBoss 5 and 6 class loader methods (discovered and called - * through reflection) for load time weaving. - * - * @author Costin Leau - * @since 3.1 - */ -class JBossMCAdapter implements JBossClassLoaderAdapter { - - private static final String TRANSLATOR_NAME = "org.jboss.util.loading.Translator"; - private static final String POLICY_NAME = "org.jboss.classloader.spi.base.BaseClassLoaderPolicy"; - private static final String DOMAIN_NAME = "org.jboss.classloader.spi.base.BaseClassLoaderDomain"; - private static final String DEDICATED_SYSTEM = "org.jboss.classloader.spi.ClassLoaderSystem"; - private static final String LOADER_NAME = "org.jboss.classloader.spi.base.BaseClassLoader"; - private static final String GET_POLICY = "getPolicy"; - private static final String GET_DOMAIN = "getClassLoaderDomain"; - private static final String GET_SYSTEM = "getClassLoaderSystem"; - - // available since JBoss AS 5.1.0 / MC 2.0.6 (allows multiple transformers to be added) - private static final String ADD_TRANSLATOR_NAME = "addTranslator"; - // available since JBoss AS 5.0.0 / MC 2.0.1 (allows only one transformer to be added) - private static final String SET_TRANSLATOR_NAME = "setTranslator"; - - private final ClassLoader classLoader; - private final Class translatorClass; - - private final Method addTranslator; - private final Object target; - - JBossMCAdapter(ClassLoader classLoader) { - Class clazzLoaderType = null; - try { - // resolve BaseClassLoader.class - clazzLoaderType = classLoader.loadClass(LOADER_NAME); - - ClassLoader clazzLoader = null; - // walk the hierarchy to detect the instrumentation aware classloader - for (ClassLoader cl = classLoader; cl != null && clazzLoader == null; cl = cl.getParent()) { - if (clazzLoaderType.isInstance(cl)) { - clazzLoader = cl; - } - } - - if (clazzLoader == null) { - throw new IllegalArgumentException(classLoader + " and its parents are not suitable ClassLoaders: " - + "A [" + LOADER_NAME + "] implementation is required."); - } - - this.classLoader = clazzLoader; - // use the classloader that loaded the classloader to load - // the types for reflection purposes - classLoader = clazzLoader.getClass().getClassLoader(); - - // BaseClassLoader#getPolicy - Method method = clazzLoaderType.getDeclaredMethod(GET_POLICY); - ReflectionUtils.makeAccessible(method); - Object policy = method.invoke(this.classLoader); - - Object addTarget = null; - Method addMethod = null; - - // try the 5.1.x hooks - // check existence of BaseClassLoaderPolicy#addTranslator(Translator) - this.translatorClass = classLoader.loadClass(TRANSLATOR_NAME); - Class clazz = classLoader.loadClass(POLICY_NAME); - try { - addMethod = clazz.getDeclaredMethod(ADD_TRANSLATOR_NAME, translatorClass); - addTarget = policy; - } catch (NoSuchMethodException ex) { - } - - // fall back to 5.0.x method - if (addMethod == null) { - - // BaseClassLoaderPolicy#getClassLoaderDomain - method = clazz.getDeclaredMethod(GET_DOMAIN); - ReflectionUtils.makeAccessible(method); - Object domain = method.invoke(policy); - - // BaseClassLoaderDomain#getClassLoaderSystem - clazz = classLoader.loadClass(DOMAIN_NAME); - method = clazz.getDeclaredMethod(GET_SYSTEM); - ReflectionUtils.makeAccessible(method); - Object system = method.invoke(domain); - - // resolve ClassLoaderSystem - clazz = classLoader.loadClass(DEDICATED_SYSTEM); - Assert.isInstanceOf(clazz, system, "JBoss LoadTimeWeaver requires JBoss loader system of type " - + clazz.getName() + " on JBoss 5.0.x"); - - // ClassLoaderSystem#setTranslator - addMethod = clazz.getDeclaredMethod(SET_TRANSLATOR_NAME, translatorClass); - addTarget = system; - } - - this.addTranslator = addMethod; - this.target = addTarget; - - } catch (Exception ex) { - throw new IllegalStateException( - "Could not initialize JBoss LoadTimeWeaver because the JBoss 5 API classes are not available", ex); - } - } - - public void addTransformer(ClassFileTransformer transformer) { - InvocationHandler adapter = new JBossMCTranslatorAdapter(transformer); - Object adapterInstance = Proxy.newProxyInstance(this.translatorClass.getClassLoader(), - new Class[] { this.translatorClass }, adapter); - - try { - addTranslator.invoke(target, adapterInstance); - } catch (Exception ex) { - throw new IllegalStateException("Could not add transformer on JBoss 5/6 classloader " + classLoader, ex); - } - } - - public ClassLoader getInstrumentableClassLoader() { - return classLoader; - } +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.jboss; + +import java.lang.instrument.ClassFileTransformer; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; + +/** + * Reflective wrapper around a JBoss 5 and 6 class loader methods (discovered and called + * through reflection) for load time weaving. + * + * @author Costin Leau + * @since 3.1 + */ +class JBossMCAdapter implements JBossClassLoaderAdapter { + + private static final String TRANSLATOR_NAME = "org.jboss.util.loading.Translator"; + private static final String POLICY_NAME = "org.jboss.classloader.spi.base.BaseClassLoaderPolicy"; + private static final String DOMAIN_NAME = "org.jboss.classloader.spi.base.BaseClassLoaderDomain"; + private static final String DEDICATED_SYSTEM = "org.jboss.classloader.spi.ClassLoaderSystem"; + private static final String LOADER_NAME = "org.jboss.classloader.spi.base.BaseClassLoader"; + private static final String GET_POLICY = "getPolicy"; + private static final String GET_DOMAIN = "getClassLoaderDomain"; + private static final String GET_SYSTEM = "getClassLoaderSystem"; + + // available since JBoss AS 5.1.0 / MC 2.0.6 (allows multiple transformers to be added) + private static final String ADD_TRANSLATOR_NAME = "addTranslator"; + // available since JBoss AS 5.0.0 / MC 2.0.1 (allows only one transformer to be added) + private static final String SET_TRANSLATOR_NAME = "setTranslator"; + + private final ClassLoader classLoader; + private final Class translatorClass; + + private final Method addTranslator; + private final Object target; + + JBossMCAdapter(ClassLoader classLoader) { + Class clazzLoaderType = null; + try { + // resolve BaseClassLoader.class + clazzLoaderType = classLoader.loadClass(LOADER_NAME); + + ClassLoader clazzLoader = null; + // walk the hierarchy to detect the instrumentation aware classloader + for (ClassLoader cl = classLoader; cl != null && clazzLoader == null; cl = cl.getParent()) { + if (clazzLoaderType.isInstance(cl)) { + clazzLoader = cl; + } + } + + if (clazzLoader == null) { + throw new IllegalArgumentException(classLoader + " and its parents are not suitable ClassLoaders: " + + "A [" + LOADER_NAME + "] implementation is required."); + } + + this.classLoader = clazzLoader; + // use the classloader that loaded the classloader to load + // the types for reflection purposes + classLoader = clazzLoader.getClass().getClassLoader(); + + // BaseClassLoader#getPolicy + Method method = clazzLoaderType.getDeclaredMethod(GET_POLICY); + ReflectionUtils.makeAccessible(method); + Object policy = method.invoke(this.classLoader); + + Object addTarget = null; + Method addMethod = null; + + // try the 5.1.x hooks + // check existence of BaseClassLoaderPolicy#addTranslator(Translator) + this.translatorClass = classLoader.loadClass(TRANSLATOR_NAME); + Class clazz = classLoader.loadClass(POLICY_NAME); + try { + addMethod = clazz.getDeclaredMethod(ADD_TRANSLATOR_NAME, translatorClass); + addTarget = policy; + } catch (NoSuchMethodException ex) { + } + + // fall back to 5.0.x method + if (addMethod == null) { + + // BaseClassLoaderPolicy#getClassLoaderDomain + method = clazz.getDeclaredMethod(GET_DOMAIN); + ReflectionUtils.makeAccessible(method); + Object domain = method.invoke(policy); + + // BaseClassLoaderDomain#getClassLoaderSystem + clazz = classLoader.loadClass(DOMAIN_NAME); + method = clazz.getDeclaredMethod(GET_SYSTEM); + ReflectionUtils.makeAccessible(method); + Object system = method.invoke(domain); + + // resolve ClassLoaderSystem + clazz = classLoader.loadClass(DEDICATED_SYSTEM); + Assert.isInstanceOf(clazz, system, "JBoss LoadTimeWeaver requires JBoss loader system of type " + + clazz.getName() + " on JBoss 5.0.x"); + + // ClassLoaderSystem#setTranslator + addMethod = clazz.getDeclaredMethod(SET_TRANSLATOR_NAME, translatorClass); + addTarget = system; + } + + this.addTranslator = addMethod; + this.target = addTarget; + + } catch (Exception ex) { + throw new IllegalStateException( + "Could not initialize JBoss LoadTimeWeaver because the JBoss 5 API classes are not available", ex); + } + } + + public void addTransformer(ClassFileTransformer transformer) { + InvocationHandler adapter = new JBossMCTranslatorAdapter(transformer); + Object adapterInstance = Proxy.newProxyInstance(this.translatorClass.getClassLoader(), + new Class[] { this.translatorClass }, adapter); + + try { + addTranslator.invoke(target, adapterInstance); + } catch (Exception ex) { + throw new IllegalStateException("Could not add transformer on JBoss 5/6 classloader " + classLoader, ex); + } + } + + public ClassLoader getInstrumentableClassLoader() { + return classLoader; + } } \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossMCTranslatorAdapter.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossMCTranslatorAdapter.java index 16570a514f..794864e5f6 100644 --- a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossMCTranslatorAdapter.java +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossMCTranslatorAdapter.java @@ -1,82 +1,82 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.jboss; - -import java.lang.instrument.ClassFileTransformer; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.security.ProtectionDomain; - -/** - * Adapter that implements JBoss Translator interface, delegating to a - * standard JDK {@link ClassFileTransformer} underneath. - * - *

To avoid compile time checks again the vendor API, a dynamic proxy is - * being used. - * - * @author Costin Leau - * @since 3.1 - */ -class JBossMCTranslatorAdapter implements InvocationHandler { - - private final ClassFileTransformer transformer; - - /** - * Creates a new {@link JBossMCTranslatorAdapter}. - * @param transformer the {@link ClassFileTransformer} to be adapted (must - * not be null) - */ - public JBossMCTranslatorAdapter(ClassFileTransformer transformer) { - this.transformer = transformer; - } - - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - String name = method.getName(); - - if ("equals".equals(name)) { - return (Boolean.valueOf(proxy == args[0])); - } else if ("hashCode".equals(name)) { - return hashCode(); - } else if ("toString".equals(name)) { - return toString(); - } else if ("transform".equals(name)) { - return transform((ClassLoader) args[0], (String) args[1], (Class) args[2], (ProtectionDomain) args[3], - (byte[]) args[4]); - } else if ("unregisterClassLoader".equals(name)) { - unregisterClassLoader((ClassLoader) args[0]); - return null; - - } else { - throw new IllegalArgumentException("Unknown method: " + method); - } - } - - public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, - ProtectionDomain protectionDomain, byte[] classfileBuffer) throws Exception { - return transformer.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer); - } - - public void unregisterClassLoader(ClassLoader loader) { - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(getClass().getName()); - builder.append(" for transformer: "); - builder.append(this.transformer); - return builder.toString(); - } +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.jboss; + +import java.lang.instrument.ClassFileTransformer; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.security.ProtectionDomain; + +/** + * Adapter that implements JBoss Translator interface, delegating to a + * standard JDK {@link ClassFileTransformer} underneath. + * + *

To avoid compile time checks again the vendor API, a dynamic proxy is + * being used. + * + * @author Costin Leau + * @since 3.1 + */ +class JBossMCTranslatorAdapter implements InvocationHandler { + + private final ClassFileTransformer transformer; + + /** + * Creates a new {@link JBossMCTranslatorAdapter}. + * @param transformer the {@link ClassFileTransformer} to be adapted (must + * not be null) + */ + public JBossMCTranslatorAdapter(ClassFileTransformer transformer) { + this.transformer = transformer; + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + String name = method.getName(); + + if ("equals".equals(name)) { + return (Boolean.valueOf(proxy == args[0])); + } else if ("hashCode".equals(name)) { + return hashCode(); + } else if ("toString".equals(name)) { + return toString(); + } else if ("transform".equals(name)) { + return transform((ClassLoader) args[0], (String) args[1], (Class) args[2], (ProtectionDomain) args[3], + (byte[]) args[4]); + } else if ("unregisterClassLoader".equals(name)) { + unregisterClassLoader((ClassLoader) args[0]); + return null; + + } else { + throw new IllegalArgumentException("Unknown method: " + method); + } + } + + public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, + ProtectionDomain protectionDomain, byte[] classfileBuffer) throws Exception { + return transformer.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer); + } + + public void unregisterClassLoader(ClassLoader loader) { + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(getClass().getName()); + builder.append(" for transformer: "); + builder.append(this.transformer); + return builder.toString(); + } } \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossModulesAdapter.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossModulesAdapter.java index be0291d59d..f9ba2b6204 100644 --- a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossModulesAdapter.java +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/JBossModulesAdapter.java @@ -1,71 +1,71 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.jboss; - -import java.lang.instrument.ClassFileTransformer; -import java.lang.reflect.Field; -import java.lang.reflect.Method; - -import org.springframework.util.Assert; -import org.springframework.util.ReflectionUtils; - -/** - * JBoss 7 adapter. - * - * @author Costin Leau - * @since 3.1 - */ -class JBossModulesAdapter implements JBossClassLoaderAdapter { - - private static final String TRANSFORMER_FIELD_NAME = "transformer"; - private static final String TRANSFORMER_ADD_METHOD_NAME = "addTransformer"; - private static final String DELEGATING_TRANSFORMER_CLASS_NAME = "org.jboss.as.server.deployment.module.DelegatingClassFileTransformer"; - private final ClassLoader classLoader; - private final Method addTransformer; - private final Object delegatingTransformer; - - public JBossModulesAdapter(ClassLoader loader) { - this.classLoader = loader; - - try { - Field transformers = ReflectionUtils.findField(classLoader.getClass(), TRANSFORMER_FIELD_NAME); - transformers.setAccessible(true); - - delegatingTransformer = transformers.get(classLoader); - - Assert.state(delegatingTransformer.getClass().getName().equals(DELEGATING_TRANSFORMER_CLASS_NAME), - "Transformer not of the expected type: " + delegatingTransformer.getClass().getName()); - addTransformer = ReflectionUtils.findMethod(delegatingTransformer.getClass(), TRANSFORMER_ADD_METHOD_NAME, - ClassFileTransformer.class); - addTransformer.setAccessible(true); - } catch (Exception ex) { - throw new IllegalStateException("Could not initialize JBoss 7 LoadTimeWeaver", ex); - } - } - - public void addTransformer(ClassFileTransformer transformer) { - try { - addTransformer.invoke(delegatingTransformer, transformer); - } catch (Exception ex) { - throw new IllegalStateException("Could not add transformer on JBoss 7 classloader " + classLoader, ex); - } - } - - public ClassLoader getInstrumentableClassLoader() { - return classLoader; - } +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.jboss; + +import java.lang.instrument.ClassFileTransformer; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; + +/** + * JBoss 7 adapter. + * + * @author Costin Leau + * @since 3.1 + */ +class JBossModulesAdapter implements JBossClassLoaderAdapter { + + private static final String TRANSFORMER_FIELD_NAME = "transformer"; + private static final String TRANSFORMER_ADD_METHOD_NAME = "addTransformer"; + private static final String DELEGATING_TRANSFORMER_CLASS_NAME = "org.jboss.as.server.deployment.module.DelegatingClassFileTransformer"; + private final ClassLoader classLoader; + private final Method addTransformer; + private final Object delegatingTransformer; + + public JBossModulesAdapter(ClassLoader loader) { + this.classLoader = loader; + + try { + Field transformers = ReflectionUtils.findField(classLoader.getClass(), TRANSFORMER_FIELD_NAME); + transformers.setAccessible(true); + + delegatingTransformer = transformers.get(classLoader); + + Assert.state(delegatingTransformer.getClass().getName().equals(DELEGATING_TRANSFORMER_CLASS_NAME), + "Transformer not of the expected type: " + delegatingTransformer.getClass().getName()); + addTransformer = ReflectionUtils.findMethod(delegatingTransformer.getClass(), TRANSFORMER_ADD_METHOD_NAME, + ClassFileTransformer.class); + addTransformer.setAccessible(true); + } catch (Exception ex) { + throw new IllegalStateException("Could not initialize JBoss 7 LoadTimeWeaver", ex); + } + } + + public void addTransformer(ClassFileTransformer transformer) { + try { + addTransformer.invoke(delegatingTransformer, transformer); + } catch (Exception ex) { + throw new IllegalStateException("Could not add transformer on JBoss 7 classloader " + classLoader, ex); + } + } + + public ClassLoader getInstrumentableClassLoader() { + return classLoader; + } } \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/package-info.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/package-info.java index 0c861f32e9..4072d51f6c 100644 --- a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/package-info.java +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/jboss/package-info.java @@ -1,8 +1,8 @@ - -/** - * - * Support for class instrumentation on JBoss AS 5.x / JBoss MC 2.0.x. - * - */ -package org.springframework.instrument.classloading.jboss; - + +/** + * + * Support for class instrumentation on JBoss AS 5.x / JBoss MC 2.0.x. + * + */ +package org.springframework.instrument.classloading.jboss; + diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/oc4j/OC4JClassLoaderAdapter.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/oc4j/OC4JClassLoaderAdapter.java index 15b1a41fc2..c138338518 100644 --- a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/oc4j/OC4JClassLoaderAdapter.java +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/oc4j/OC4JClassLoaderAdapter.java @@ -1,88 +1,88 @@ -/* - * Copyright 2006-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.instrument.classloading.oc4j; - -import java.lang.instrument.ClassFileTransformer; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; - -import org.springframework.util.Assert; - -/** - * Reflective wrapper around a OC4J class loader. Used to - * encapsulate the classloader-specific methods (discovered and - * called through reflection) from the load-time weaver. - * - * @author Costin Leau - */ -class OC4JClassLoaderAdapter { - - private static final String CL_UTILS = "oracle.classloader.util.ClassLoaderUtilities"; - private static final String PREPROCESS_UTILS = "oracle.classloader.util.ClassPreprocessor"; - - private final ClassLoader classLoader; - private final Class processorClass; - private final Method addTransformer; - private final Method copy; - - public OC4JClassLoaderAdapter(ClassLoader classLoader) { - try { - // Since OC4J 10.1.3's PolicyClassLoader is going to be removed, - // we rely on the ClassLoaderUtilities API instead. - Class utilClass = classLoader.loadClass(CL_UTILS); - this.processorClass = classLoader.loadClass(PREPROCESS_UTILS); - - this.addTransformer = utilClass.getMethod("addPreprocessor", new Class[] { ClassLoader.class, - this.processorClass }); - this.copy = utilClass.getMethod("copy", new Class[] { ClassLoader.class }); - - } catch (Exception ex) { - throw new IllegalStateException( - "Could not initialize OC4J LoadTimeWeaver because OC4J API classes are not available", ex); - } - - this.classLoader = classLoader; - } - - public void addTransformer(ClassFileTransformer transformer) { - Assert.notNull(transformer, "ClassFileTransformer must not be null"); - try { - OC4JClassPreprocessorAdapter adapter = new OC4JClassPreprocessorAdapter(transformer); - Object adapterInstance = Proxy.newProxyInstance(this.processorClass.getClassLoader(), - new Class[] { this.processorClass }, adapter); - this.addTransformer.invoke(null, new Object[] { this.classLoader, adapterInstance }); - } catch (InvocationTargetException ex) { - throw new IllegalStateException("OC4J addPreprocessor method threw exception", ex.getCause()); - } catch (Exception ex) { - throw new IllegalStateException("Could not invoke OC4J addPreprocessor method", ex); - } - } - - public ClassLoader getClassLoader() { - return this.classLoader; - } - - public ClassLoader getThrowawayClassLoader() { - try { - return (ClassLoader) this.copy.invoke(null, new Object[] { this.classLoader }); - } catch (InvocationTargetException ex) { - throw new IllegalStateException("OC4J copy method failed", ex.getCause()); - } catch (Exception ex) { - throw new IllegalStateException("Could not copy OC4J classloader", ex); - } - } +/* + * Copyright 2006-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.instrument.classloading.oc4j; + +import java.lang.instrument.ClassFileTransformer; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +import org.springframework.util.Assert; + +/** + * Reflective wrapper around a OC4J class loader. Used to + * encapsulate the classloader-specific methods (discovered and + * called through reflection) from the load-time weaver. + * + * @author Costin Leau + */ +class OC4JClassLoaderAdapter { + + private static final String CL_UTILS = "oracle.classloader.util.ClassLoaderUtilities"; + private static final String PREPROCESS_UTILS = "oracle.classloader.util.ClassPreprocessor"; + + private final ClassLoader classLoader; + private final Class processorClass; + private final Method addTransformer; + private final Method copy; + + public OC4JClassLoaderAdapter(ClassLoader classLoader) { + try { + // Since OC4J 10.1.3's PolicyClassLoader is going to be removed, + // we rely on the ClassLoaderUtilities API instead. + Class utilClass = classLoader.loadClass(CL_UTILS); + this.processorClass = classLoader.loadClass(PREPROCESS_UTILS); + + this.addTransformer = utilClass.getMethod("addPreprocessor", new Class[] { ClassLoader.class, + this.processorClass }); + this.copy = utilClass.getMethod("copy", new Class[] { ClassLoader.class }); + + } catch (Exception ex) { + throw new IllegalStateException( + "Could not initialize OC4J LoadTimeWeaver because OC4J API classes are not available", ex); + } + + this.classLoader = classLoader; + } + + public void addTransformer(ClassFileTransformer transformer) { + Assert.notNull(transformer, "ClassFileTransformer must not be null"); + try { + OC4JClassPreprocessorAdapter adapter = new OC4JClassPreprocessorAdapter(transformer); + Object adapterInstance = Proxy.newProxyInstance(this.processorClass.getClassLoader(), + new Class[] { this.processorClass }, adapter); + this.addTransformer.invoke(null, new Object[] { this.classLoader, adapterInstance }); + } catch (InvocationTargetException ex) { + throw new IllegalStateException("OC4J addPreprocessor method threw exception", ex.getCause()); + } catch (Exception ex) { + throw new IllegalStateException("Could not invoke OC4J addPreprocessor method", ex); + } + } + + public ClassLoader getClassLoader() { + return this.classLoader; + } + + public ClassLoader getThrowawayClassLoader() { + try { + return (ClassLoader) this.copy.invoke(null, new Object[] { this.classLoader }); + } catch (InvocationTargetException ex) { + throw new IllegalStateException("OC4J copy method failed", ex.getCause()); + } catch (Exception ex) { + throw new IllegalStateException("Could not copy OC4J classloader", ex); + } + } } \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/oc4j/OC4JClassPreprocessorAdapter.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/oc4j/OC4JClassPreprocessorAdapter.java index 2948b691e0..540aed883e 100644 --- a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/oc4j/OC4JClassPreprocessorAdapter.java +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/oc4j/OC4JClassPreprocessorAdapter.java @@ -1,95 +1,95 @@ -/* - * Copyright 2006-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.instrument.classloading.oc4j; - -import java.lang.instrument.ClassFileTransformer; -import java.lang.instrument.IllegalClassFormatException; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.security.ProtectionDomain; - -/** - * Adapter that implements OC4J ClassPreProcessor interface, delegating to a - * standard JDK {@link ClassFileTransformer} underneath. - * - *

To avoid compile time checks again the vendor API, a dynamic proxy is - * being used. - * - * @author Costin Leau - */ -class OC4JClassPreprocessorAdapter implements InvocationHandler { - - private final ClassFileTransformer transformer; - - /** - * Creates a new {@link OC4JClassPreprocessorAdapter}. - * @param transformer the {@link ClassFileTransformer} to be adapted (must - * not be null) - */ - public OC4JClassPreprocessorAdapter(ClassFileTransformer transformer) { - this.transformer = transformer; - } - - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - String name = method.getName(); - - if ("equals".equals(name)) { - return (Boolean.valueOf(proxy == args[0])); - } else if ("hashCode".equals(name)) { - return hashCode(); - } else if ("toString".equals(name)) { - return toString(); - } else if ("initialize".equals(name)) { - initialize(proxy, (ClassLoader) args[0]); - return null; - } else if ("processClass".equals(name)) { - return processClass((String) args[0], (byte[]) args[1], (Integer) args[2], (Integer) args[3], - (ProtectionDomain) args[4], (ClassLoader) args[5]); - } else { - throw new IllegalArgumentException("Unknown method: " + method); - } - } - - // maps to oracle.classloader.util.ClassPreprocessor#initialize - // the proxy is passed since it implements the Oracle interface which - // is asked as a return type - public Object initialize(Object proxy, ClassLoader loader) { - return proxy; - } - - public byte[] processClass(String className, byte origClassBytes[], int offset, int length, ProtectionDomain pd, - ClassLoader loader) { - try { - byte[] tempArray = new byte[length]; - System.arraycopy(origClassBytes, offset, tempArray, 0, length); - - // NB: OC4J passes className as "." without class while the - // transformer expects a VM, "/" format - byte[] result = this.transformer.transform(loader, className.replace('.', '/'), null, pd, tempArray); - return (result != null ? result : origClassBytes); - } catch (IllegalClassFormatException ex) { - throw new IllegalStateException("Cannot transform because of illegal class format", ex); - } - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(getClass().getName()); - builder.append(" for transformer: "); - builder.append(this.transformer); - return builder.toString(); - } +/* + * Copyright 2006-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.instrument.classloading.oc4j; + +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.IllegalClassFormatException; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.security.ProtectionDomain; + +/** + * Adapter that implements OC4J ClassPreProcessor interface, delegating to a + * standard JDK {@link ClassFileTransformer} underneath. + * + *

To avoid compile time checks again the vendor API, a dynamic proxy is + * being used. + * + * @author Costin Leau + */ +class OC4JClassPreprocessorAdapter implements InvocationHandler { + + private final ClassFileTransformer transformer; + + /** + * Creates a new {@link OC4JClassPreprocessorAdapter}. + * @param transformer the {@link ClassFileTransformer} to be adapted (must + * not be null) + */ + public OC4JClassPreprocessorAdapter(ClassFileTransformer transformer) { + this.transformer = transformer; + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + String name = method.getName(); + + if ("equals".equals(name)) { + return (Boolean.valueOf(proxy == args[0])); + } else if ("hashCode".equals(name)) { + return hashCode(); + } else if ("toString".equals(name)) { + return toString(); + } else if ("initialize".equals(name)) { + initialize(proxy, (ClassLoader) args[0]); + return null; + } else if ("processClass".equals(name)) { + return processClass((String) args[0], (byte[]) args[1], (Integer) args[2], (Integer) args[3], + (ProtectionDomain) args[4], (ClassLoader) args[5]); + } else { + throw new IllegalArgumentException("Unknown method: " + method); + } + } + + // maps to oracle.classloader.util.ClassPreprocessor#initialize + // the proxy is passed since it implements the Oracle interface which + // is asked as a return type + public Object initialize(Object proxy, ClassLoader loader) { + return proxy; + } + + public byte[] processClass(String className, byte origClassBytes[], int offset, int length, ProtectionDomain pd, + ClassLoader loader) { + try { + byte[] tempArray = new byte[length]; + System.arraycopy(origClassBytes, offset, tempArray, 0, length); + + // NB: OC4J passes className as "." without class while the + // transformer expects a VM, "/" format + byte[] result = this.transformer.transform(loader, className.replace('.', '/'), null, pd, tempArray); + return (result != null ? result : origClassBytes); + } catch (IllegalClassFormatException ex) { + throw new IllegalStateException("Cannot transform because of illegal class format", ex); + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(getClass().getName()); + builder.append(" for transformer: "); + builder.append(this.transformer); + return builder.toString(); + } } \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/websphere/WebSphereClassLoaderAdapter.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/websphere/WebSphereClassLoaderAdapter.java index cc0a051e43..2e0fa5cf04 100644 --- a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/websphere/WebSphereClassLoaderAdapter.java +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/websphere/WebSphereClassLoaderAdapter.java @@ -1,111 +1,111 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.websphere; - -import java.lang.instrument.ClassFileTransformer; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.List; - -import org.springframework.util.Assert; - -/** - * - * Reflective wrapper around a WebSphere 7 class loader. Used to - * encapsulate the classloader-specific methods (discovered and - * called through reflection) from the load-time weaver. - * - * @author Costin Leau - * @since 3.1 - */ -class WebSphereClassLoaderAdapter { - - private static final String COMPOUND_CLASS_LOADER_NAME = "com.ibm.ws.classloader.CompoundClassLoader"; - private static final String CLASS_PRE_PROCESSOR_NAME = "com.ibm.websphere.classloader.ClassLoaderInstancePreDefinePlugin"; - private static final String PLUGINS_FIELD = "preDefinePlugins"; - - private ClassLoader classLoader; - private Class wsPreProcessorClass; - private Method addPreDefinePlugin; - private Constructor cloneConstructor; - private Field transformerList; - - public WebSphereClassLoaderAdapter(ClassLoader classLoader) { - Class wsCompoundClassLoaderClass = null; - try { - wsCompoundClassLoaderClass = classLoader.loadClass(COMPOUND_CLASS_LOADER_NAME); - cloneConstructor = classLoader.getClass().getDeclaredConstructor(wsCompoundClassLoaderClass); - cloneConstructor.setAccessible(true); - - wsPreProcessorClass = classLoader.loadClass(CLASS_PRE_PROCESSOR_NAME); - addPreDefinePlugin = classLoader.getClass().getMethod("addPreDefinePlugin", wsPreProcessorClass); - transformerList = wsCompoundClassLoaderClass.getDeclaredField(PLUGINS_FIELD); - transformerList.setAccessible(true); - } - catch (Exception ex) { - throw new IllegalStateException( - "Could not initialize WebSphere LoadTimeWeaver because WebSphere 7 API classes are not available", - ex); - } - Assert.isInstanceOf(wsCompoundClassLoaderClass, classLoader, - "ClassLoader must be instance of [" + COMPOUND_CLASS_LOADER_NAME + "]"); - this.classLoader = classLoader; - } - - public ClassLoader getClassLoader() { - return this.classLoader; - } - - public void addTransformer(ClassFileTransformer transformer) { - Assert.notNull(transformer, "ClassFileTransformer must not be null"); - try { - InvocationHandler adapter = new WebSphereClassPreDefinePlugin(transformer); - Object adapterInstance = Proxy.newProxyInstance(this.wsPreProcessorClass.getClassLoader(), - new Class[] { this.wsPreProcessorClass }, adapter); - this.addPreDefinePlugin.invoke(this.classLoader, adapterInstance); - - } - catch (InvocationTargetException ex) { - throw new IllegalStateException("WebSphere addPreDefinePlugin method threw exception", ex.getCause()); - } - catch (Exception ex) { - throw new IllegalStateException("Could not invoke WebSphere addPreDefinePlugin method", ex); - } - } - - @SuppressWarnings("unchecked") - public ClassLoader getThrowawayClassLoader() { - try { - ClassLoader loader = (ClassLoader) cloneConstructor.newInstance(getClassLoader()); - // clear out the transformers (copied as well) - List list = (List) transformerList.get(loader); - list.clear(); - return loader; - } - catch (InvocationTargetException ex) { - throw new IllegalStateException("WebSphere CompoundClassLoader constructor failed", ex.getCause()); - } - catch (Exception ex) { - throw new IllegalStateException("Could not construct WebSphere CompoundClassLoader", ex); - } - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.websphere; + +import java.lang.instrument.ClassFileTransformer; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.List; + +import org.springframework.util.Assert; + +/** + * + * Reflective wrapper around a WebSphere 7 class loader. Used to + * encapsulate the classloader-specific methods (discovered and + * called through reflection) from the load-time weaver. + * + * @author Costin Leau + * @since 3.1 + */ +class WebSphereClassLoaderAdapter { + + private static final String COMPOUND_CLASS_LOADER_NAME = "com.ibm.ws.classloader.CompoundClassLoader"; + private static final String CLASS_PRE_PROCESSOR_NAME = "com.ibm.websphere.classloader.ClassLoaderInstancePreDefinePlugin"; + private static final String PLUGINS_FIELD = "preDefinePlugins"; + + private ClassLoader classLoader; + private Class wsPreProcessorClass; + private Method addPreDefinePlugin; + private Constructor cloneConstructor; + private Field transformerList; + + public WebSphereClassLoaderAdapter(ClassLoader classLoader) { + Class wsCompoundClassLoaderClass = null; + try { + wsCompoundClassLoaderClass = classLoader.loadClass(COMPOUND_CLASS_LOADER_NAME); + cloneConstructor = classLoader.getClass().getDeclaredConstructor(wsCompoundClassLoaderClass); + cloneConstructor.setAccessible(true); + + wsPreProcessorClass = classLoader.loadClass(CLASS_PRE_PROCESSOR_NAME); + addPreDefinePlugin = classLoader.getClass().getMethod("addPreDefinePlugin", wsPreProcessorClass); + transformerList = wsCompoundClassLoaderClass.getDeclaredField(PLUGINS_FIELD); + transformerList.setAccessible(true); + } + catch (Exception ex) { + throw new IllegalStateException( + "Could not initialize WebSphere LoadTimeWeaver because WebSphere 7 API classes are not available", + ex); + } + Assert.isInstanceOf(wsCompoundClassLoaderClass, classLoader, + "ClassLoader must be instance of [" + COMPOUND_CLASS_LOADER_NAME + "]"); + this.classLoader = classLoader; + } + + public ClassLoader getClassLoader() { + return this.classLoader; + } + + public void addTransformer(ClassFileTransformer transformer) { + Assert.notNull(transformer, "ClassFileTransformer must not be null"); + try { + InvocationHandler adapter = new WebSphereClassPreDefinePlugin(transformer); + Object adapterInstance = Proxy.newProxyInstance(this.wsPreProcessorClass.getClassLoader(), + new Class[] { this.wsPreProcessorClass }, adapter); + this.addPreDefinePlugin.invoke(this.classLoader, adapterInstance); + + } + catch (InvocationTargetException ex) { + throw new IllegalStateException("WebSphere addPreDefinePlugin method threw exception", ex.getCause()); + } + catch (Exception ex) { + throw new IllegalStateException("Could not invoke WebSphere addPreDefinePlugin method", ex); + } + } + + @SuppressWarnings("unchecked") + public ClassLoader getThrowawayClassLoader() { + try { + ClassLoader loader = (ClassLoader) cloneConstructor.newInstance(getClassLoader()); + // clear out the transformers (copied as well) + List list = (List) transformerList.get(loader); + list.clear(); + return loader; + } + catch (InvocationTargetException ex) { + throw new IllegalStateException("WebSphere CompoundClassLoader constructor failed", ex.getCause()); + } + catch (Exception ex) { + throw new IllegalStateException("Could not construct WebSphere CompoundClassLoader", ex); + } + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/websphere/WebSphereClassPreDefinePlugin.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/websphere/WebSphereClassPreDefinePlugin.java index b4d70120e6..748ba182a4 100644 --- a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/websphere/WebSphereClassPreDefinePlugin.java +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/websphere/WebSphereClassPreDefinePlugin.java @@ -1,100 +1,100 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.websphere; - -import java.lang.instrument.ClassFileTransformer; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.security.CodeSource; - -import org.springframework.util.FileCopyUtils; - -/** - * Adapter that implements WebSphere 7.0 ClassPreProcessPlugin interface, - * delegating to a standard JDK {@link ClassFileTransformer} underneath. - * - *

To avoid compile time checks again the vendor API, a dynamic proxy is - * being used. - * - * @author Costin Leau - * @since 3.1 - */ -class WebSphereClassPreDefinePlugin implements InvocationHandler { - - private final ClassFileTransformer transformer; - - - /** - * Create a new {@link WebSphereClassPreDefinePlugin}. - * @param transformer the {@link ClassFileTransformer} to be adapted - * (must not be null) - */ - public WebSphereClassPreDefinePlugin(ClassFileTransformer transformer) { - this.transformer = transformer; - ClassLoader classLoader = transformer.getClass().getClassLoader(); - - // first force the full class loading of the weaver by invoking transformation on a dummy class - try { - String dummyClass = Dummy.class.getName().replace('.', '/'); - byte[] bytes = FileCopyUtils.copyToByteArray(classLoader.getResourceAsStream(dummyClass + ".class")); - transformer.transform(classLoader, dummyClass, null, null, bytes); - } - catch (Throwable ex) { - throw new IllegalArgumentException("Cannot load transformer", ex); - } - } - - - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - String name = method.getName(); - if ("equals".equals(name)) { - return (proxy == args[0]); - } - else if ("hashCode".equals(name)) { - return hashCode(); - } - else if ("toString".equals(name)) { - return toString(); - } - else if ("transformClass".equals(name)) { - return transform((String) args[0], (byte[]) args[1], (CodeSource) args[2], (ClassLoader) args[3]); - } - else { - throw new IllegalArgumentException("Unknown method: " + method); - } - } - - protected byte[] transform(String className, byte[] classfileBuffer, CodeSource codeSource, ClassLoader classLoader) - throws Exception { - - // NB: WebSphere passes className as "." without class while the transformer expects a VM, "/" format - byte[] result = transformer.transform(classLoader, className.replace('.', '/'), null, null, classfileBuffer); - return (result != null ? result : classfileBuffer); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(getClass().getName()); - builder.append(" for transformer: "); - builder.append(this.transformer); - return builder.toString(); - } - - - private static class Dummy { - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.websphere; + +import java.lang.instrument.ClassFileTransformer; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.security.CodeSource; + +import org.springframework.util.FileCopyUtils; + +/** + * Adapter that implements WebSphere 7.0 ClassPreProcessPlugin interface, + * delegating to a standard JDK {@link ClassFileTransformer} underneath. + * + *

To avoid compile time checks again the vendor API, a dynamic proxy is + * being used. + * + * @author Costin Leau + * @since 3.1 + */ +class WebSphereClassPreDefinePlugin implements InvocationHandler { + + private final ClassFileTransformer transformer; + + + /** + * Create a new {@link WebSphereClassPreDefinePlugin}. + * @param transformer the {@link ClassFileTransformer} to be adapted + * (must not be null) + */ + public WebSphereClassPreDefinePlugin(ClassFileTransformer transformer) { + this.transformer = transformer; + ClassLoader classLoader = transformer.getClass().getClassLoader(); + + // first force the full class loading of the weaver by invoking transformation on a dummy class + try { + String dummyClass = Dummy.class.getName().replace('.', '/'); + byte[] bytes = FileCopyUtils.copyToByteArray(classLoader.getResourceAsStream(dummyClass + ".class")); + transformer.transform(classLoader, dummyClass, null, null, bytes); + } + catch (Throwable ex) { + throw new IllegalArgumentException("Cannot load transformer", ex); + } + } + + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + String name = method.getName(); + if ("equals".equals(name)) { + return (proxy == args[0]); + } + else if ("hashCode".equals(name)) { + return hashCode(); + } + else if ("toString".equals(name)) { + return toString(); + } + else if ("transformClass".equals(name)) { + return transform((String) args[0], (byte[]) args[1], (CodeSource) args[2], (ClassLoader) args[3]); + } + else { + throw new IllegalArgumentException("Unknown method: " + method); + } + } + + protected byte[] transform(String className, byte[] classfileBuffer, CodeSource codeSource, ClassLoader classLoader) + throws Exception { + + // NB: WebSphere passes className as "." without class while the transformer expects a VM, "/" format + byte[] result = transformer.transform(classLoader, className.replace('.', '/'), null, null, classfileBuffer); + return (result != null ? result : classfileBuffer); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(getClass().getName()); + builder.append(" for transformer: "); + builder.append(this.transformer); + return builder.toString(); + } + + + private static class Dummy { + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/websphere/WebSphereLoadTimeWeaver.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/websphere/WebSphereLoadTimeWeaver.java index 724a1db6b1..1344bef8aa 100644 --- a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/websphere/WebSphereLoadTimeWeaver.java +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/websphere/WebSphereLoadTimeWeaver.java @@ -1,70 +1,70 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.websphere; - -import java.lang.instrument.ClassFileTransformer; - -import org.springframework.instrument.classloading.LoadTimeWeaver; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; - -/** - * {@link LoadTimeWeaver} implementation for WebSphere's instrumentable ClassLoader. - * Compatible with WebSphere 7 as well as 8. - * - * @author Costin Leau - * @since 3.1 - */ -public class WebSphereLoadTimeWeaver implements LoadTimeWeaver { - - private final WebSphereClassLoaderAdapter classLoader; - - - /** - * Create a new instance of the {@link WebSphereLoadTimeWeaver} class using - * the default {@link ClassLoader class loader}. - * @see org.springframework.util.ClassUtils#getDefaultClassLoader() - */ - public WebSphereLoadTimeWeaver() { - this(ClassUtils.getDefaultClassLoader()); - } - - /** - * Create a new instance of the {@link WebSphereLoadTimeWeaver} class using - * the supplied {@link ClassLoader}. - * @param classLoader the ClassLoader to delegate to for weaving - * (must not be null) - */ - public WebSphereLoadTimeWeaver(ClassLoader classLoader) { - Assert.notNull(classLoader, "ClassLoader must not be null"); - this.classLoader = new WebSphereClassLoaderAdapter(classLoader); - } - - - public void addTransformer(ClassFileTransformer transformer) { - this.classLoader.addTransformer(transformer); - } - - public ClassLoader getInstrumentableClassLoader() { - return this.classLoader.getClassLoader(); - } - - public ClassLoader getThrowawayClassLoader() { - return this.classLoader.getThrowawayClassLoader(); - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.websphere; + +import java.lang.instrument.ClassFileTransformer; + +import org.springframework.instrument.classloading.LoadTimeWeaver; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; + +/** + * {@link LoadTimeWeaver} implementation for WebSphere's instrumentable ClassLoader. + * Compatible with WebSphere 7 as well as 8. + * + * @author Costin Leau + * @since 3.1 + */ +public class WebSphereLoadTimeWeaver implements LoadTimeWeaver { + + private final WebSphereClassLoaderAdapter classLoader; + + + /** + * Create a new instance of the {@link WebSphereLoadTimeWeaver} class using + * the default {@link ClassLoader class loader}. + * @see org.springframework.util.ClassUtils#getDefaultClassLoader() + */ + public WebSphereLoadTimeWeaver() { + this(ClassUtils.getDefaultClassLoader()); + } + + /** + * Create a new instance of the {@link WebSphereLoadTimeWeaver} class using + * the supplied {@link ClassLoader}. + * @param classLoader the ClassLoader to delegate to for weaving + * (must not be null) + */ + public WebSphereLoadTimeWeaver(ClassLoader classLoader) { + Assert.notNull(classLoader, "ClassLoader must not be null"); + this.classLoader = new WebSphereClassLoaderAdapter(classLoader); + } + + + public void addTransformer(ClassFileTransformer transformer) { + this.classLoader.addTransformer(transformer); + } + + public ClassLoader getInstrumentableClassLoader() { + return this.classLoader.getClassLoader(); + } + + public ClassLoader getThrowawayClassLoader() { + return this.classLoader.getThrowawayClassLoader(); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/websphere/package-info.java b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/websphere/package-info.java index 2f65915eb2..5b5a27519a 100644 --- a/org.springframework.context/src/main/java/org/springframework/instrument/classloading/websphere/package-info.java +++ b/org.springframework.context/src/main/java/org/springframework/instrument/classloading/websphere/package-info.java @@ -1,8 +1,8 @@ - -/** - * - * Support for class instrumentation on IBM WebSphere Application Server 7. - * - */ -package org.springframework.instrument.classloading.websphere; - + +/** + * + * Support for class instrumentation on IBM WebSphere Application Server 7. + * + */ +package org.springframework.instrument.classloading.websphere; + diff --git a/org.springframework.context/src/main/java/org/springframework/jndi/JndiLocatorDelegate.java b/org.springframework.context/src/main/java/org/springframework/jndi/JndiLocatorDelegate.java index fd2687e033..9b4789a724 100644 --- a/org.springframework.context/src/main/java/org/springframework/jndi/JndiLocatorDelegate.java +++ b/org.springframework.context/src/main/java/org/springframework/jndi/JndiLocatorDelegate.java @@ -1,69 +1,69 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.jndi; - -import javax.naming.InitialContext; -import javax.naming.NamingException; - -/** - * {@link JndiLocatorSupport} subclass with public lookup methods, - * for convenient use as a delegate. - * - * @author Juergen Hoeller - * @since 3.0.1 - */ -public class JndiLocatorDelegate extends JndiLocatorSupport { - - @Override - public Object lookup(String jndiName) throws NamingException { - return super.lookup(jndiName); - } - - @Override - public T lookup(String jndiName, Class requiredType) throws NamingException { - return super.lookup(jndiName, requiredType); - } - - - /** - * Configure a {@code JndiLocatorDelegate} with its "resourceRef" property set to - * true, meaning that all names will be prefixed with "java:comp/env/". - * @see #setResourceRef - */ - public static JndiLocatorDelegate createDefaultResourceRefLocator() { - JndiLocatorDelegate jndiLocator = new JndiLocatorDelegate(); - jndiLocator.setResourceRef(true); - return jndiLocator; - } - - /** - * Check whether a default JNDI environment, as in a J2EE environment, - * is available on this JVM. - * @return true if a default InitialContext can be used, - * false if not - */ - public static boolean isDefaultJndiEnvironmentAvailable() { - try { - new InitialContext(); - return true; - } - catch (Throwable ex) { - return false; - } - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jndi; + +import javax.naming.InitialContext; +import javax.naming.NamingException; + +/** + * {@link JndiLocatorSupport} subclass with public lookup methods, + * for convenient use as a delegate. + * + * @author Juergen Hoeller + * @since 3.0.1 + */ +public class JndiLocatorDelegate extends JndiLocatorSupport { + + @Override + public Object lookup(String jndiName) throws NamingException { + return super.lookup(jndiName); + } + + @Override + public T lookup(String jndiName, Class requiredType) throws NamingException { + return super.lookup(jndiName, requiredType); + } + + + /** + * Configure a {@code JndiLocatorDelegate} with its "resourceRef" property set to + * true, meaning that all names will be prefixed with "java:comp/env/". + * @see #setResourceRef + */ + public static JndiLocatorDelegate createDefaultResourceRefLocator() { + JndiLocatorDelegate jndiLocator = new JndiLocatorDelegate(); + jndiLocator.setResourceRef(true); + return jndiLocator; + } + + /** + * Check whether a default JNDI environment, as in a J2EE environment, + * is available on this JVM. + * @return true if a default InitialContext can be used, + * false if not + */ + public static boolean isDefaultJndiEnvironmentAvailable() { + try { + new InitialContext(); + return true; + } + catch (Throwable ex) { + return false; + } + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/scheduling/TaskScheduler.java b/org.springframework.context/src/main/java/org/springframework/scheduling/TaskScheduler.java index 5b0dcaf2f5..6546c2160e 100644 --- a/org.springframework.context/src/main/java/org/springframework/scheduling/TaskScheduler.java +++ b/org.springframework.context/src/main/java/org/springframework/scheduling/TaskScheduler.java @@ -1,139 +1,139 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.scheduling; - -import java.util.Date; -import java.util.concurrent.ScheduledFuture; - -/** - * Task scheduler interface that abstracts the scheduling of - * {@link Runnable Runnables} based on different kinds of triggers. - * - *

This interface is separate from {@link SchedulingTaskExecutor} since it - * usually represents for a different kind of backend, i.e. a thread pool with - * different characteristics and capabilities. Implementations may implement - * both interfaces if they can handle both kinds of execution characteristics. - * - *

The 'default' implementation is - * {@link org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler}, - * wrapping a native {@link java.util.concurrent.ScheduledExecutorService} - * and adding extended trigger capabilities. - * - *

This interface is roughly equivalent to a JSR-236 - * ManagedScheduledExecutorService as supported in Java EE 6 - * environments. However, at the time of the Spring 3.0 release, the - * JSR-236 interfaces have not been released in official form yet. - * - * @author Juergen Hoeller - * @since 3.0 - * @see org.springframework.core.task.TaskExecutor - * @see java.util.concurrent.ScheduledExecutorService - * @see org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler - */ -public interface TaskScheduler { - - /** - * Schedule the given {@link Runnable}, invoking it whenever the trigger - * indicates a next execution time. - *

Execution will end once the scheduler shuts down or the returned - * {@link ScheduledFuture} gets cancelled. - * @param task the Runnable to execute whenever the trigger fires - * @param trigger an implementation of the {@link Trigger} interface, - * e.g. a {@link org.springframework.scheduling.support.CronTrigger} object - * wrapping a cron expression - * @return a {@link ScheduledFuture} representing pending completion of the task, - * or null if the given Trigger object never fires (i.e. returns - * null from {@link Trigger#nextExecutionTime}) - * @throws org.springframework.core.task.TaskRejectedException if the given task was not accepted - * for internal reasons (e.g. a pool overload handling policy or a pool shutdown in progress) - * @see org.springframework.scheduling.support.CronTrigger - */ - ScheduledFuture schedule(Runnable task, Trigger trigger); - - /** - * Schedule the given {@link Runnable}, invoking it at the specified execution time. - *

Execution will end once the scheduler shuts down or the returned - * {@link ScheduledFuture} gets cancelled. - * @param task the Runnable to execute whenever the trigger fires - * @param startTime the desired execution time for the task - * (if this is in the past, the task will be executed immediately, i.e. as soon as possible) - * @return a {@link ScheduledFuture} representing pending completion of the task - * @throws org.springframework.core.task.TaskRejectedException if the given task was not accepted - * for internal reasons (e.g. a pool overload handling policy or a pool shutdown in progress) - */ - ScheduledFuture schedule(Runnable task, Date startTime); - - /** - * Schedule the given {@link Runnable}, invoking it at the specified execution time - * and subsequently with the given period. - *

Execution will end once the scheduler shuts down or the returned - * {@link ScheduledFuture} gets cancelled. - * @param task the Runnable to execute whenever the trigger fires - * @param startTime the desired first execution time for the task - * (if this is in the past, the task will be executed immediately, i.e. as soon as possible) - * @param period the interval between successive executions of the task (in milliseconds) - * @return a {@link ScheduledFuture} representing pending completion of the task - * @throws org.springframework.core.task.TaskRejectedException if the given task was not accepted - * for internal reasons (e.g. a pool overload handling policy or a pool shutdown in progress) - */ - ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period); - - /** - * Schedule the given {@link Runnable}, starting as soon as possible and - * invoking it with the given period. - *

Execution will end once the scheduler shuts down or the returned - * {@link ScheduledFuture} gets cancelled. - * @param task the Runnable to execute whenever the trigger fires - * @param period the interval between successive executions of the task (in milliseconds) - * @return a {@link ScheduledFuture} representing pending completion of the task - * @throws org.springframework.core.task.TaskRejectedException if the given task was not accepted - * for internal reasons (e.g. a pool overload handling policy or a pool shutdown in progress) - */ - ScheduledFuture scheduleAtFixedRate(Runnable task, long period); - - /** - * Schedule the given {@link Runnable}, invoking it at the specified execution time - * and subsequently with the given delay between the completion of one execution - * and the start of the next. - *

Execution will end once the scheduler shuts down or the returned - * {@link ScheduledFuture} gets cancelled. - * @param task the Runnable to execute whenever the trigger fires - * @param startTime the desired first execution time for the task - * (if this is in the past, the task will be executed immediately, i.e. as soon as possible) - * @param delay the delay between the completion of one execution and the start - * of the next (in milliseconds) - * @return a {@link ScheduledFuture} representing pending completion of the task - * @throws org.springframework.core.task.TaskRejectedException if the given task was not accepted - * for internal reasons (e.g. a pool overload handling policy or a pool shutdown in progress) - */ - ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay); - - /** - * Schedule the given {@link Runnable}, starting as soon as possible and - * invoking it with the given delay between the completion of one execution - * and the start of the next. - *

Execution will end once the scheduler shuts down or the returned - * {@link ScheduledFuture} gets cancelled. - * @param task the Runnable to execute whenever the trigger fires - * @param delay the interval between successive executions of the task (in milliseconds) - * @return a {@link ScheduledFuture} representing pending completion of the task - * @throws org.springframework.core.task.TaskRejectedException if the given task was not accepted - * for internal reasons (e.g. a pool overload handling policy or a pool shutdown in progress) - */ - ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay); - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling; + +import java.util.Date; +import java.util.concurrent.ScheduledFuture; + +/** + * Task scheduler interface that abstracts the scheduling of + * {@link Runnable Runnables} based on different kinds of triggers. + * + *

This interface is separate from {@link SchedulingTaskExecutor} since it + * usually represents for a different kind of backend, i.e. a thread pool with + * different characteristics and capabilities. Implementations may implement + * both interfaces if they can handle both kinds of execution characteristics. + * + *

The 'default' implementation is + * {@link org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler}, + * wrapping a native {@link java.util.concurrent.ScheduledExecutorService} + * and adding extended trigger capabilities. + * + *

This interface is roughly equivalent to a JSR-236 + * ManagedScheduledExecutorService as supported in Java EE 6 + * environments. However, at the time of the Spring 3.0 release, the + * JSR-236 interfaces have not been released in official form yet. + * + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.core.task.TaskExecutor + * @see java.util.concurrent.ScheduledExecutorService + * @see org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler + */ +public interface TaskScheduler { + + /** + * Schedule the given {@link Runnable}, invoking it whenever the trigger + * indicates a next execution time. + *

Execution will end once the scheduler shuts down or the returned + * {@link ScheduledFuture} gets cancelled. + * @param task the Runnable to execute whenever the trigger fires + * @param trigger an implementation of the {@link Trigger} interface, + * e.g. a {@link org.springframework.scheduling.support.CronTrigger} object + * wrapping a cron expression + * @return a {@link ScheduledFuture} representing pending completion of the task, + * or null if the given Trigger object never fires (i.e. returns + * null from {@link Trigger#nextExecutionTime}) + * @throws org.springframework.core.task.TaskRejectedException if the given task was not accepted + * for internal reasons (e.g. a pool overload handling policy or a pool shutdown in progress) + * @see org.springframework.scheduling.support.CronTrigger + */ + ScheduledFuture schedule(Runnable task, Trigger trigger); + + /** + * Schedule the given {@link Runnable}, invoking it at the specified execution time. + *

Execution will end once the scheduler shuts down or the returned + * {@link ScheduledFuture} gets cancelled. + * @param task the Runnable to execute whenever the trigger fires + * @param startTime the desired execution time for the task + * (if this is in the past, the task will be executed immediately, i.e. as soon as possible) + * @return a {@link ScheduledFuture} representing pending completion of the task + * @throws org.springframework.core.task.TaskRejectedException if the given task was not accepted + * for internal reasons (e.g. a pool overload handling policy or a pool shutdown in progress) + */ + ScheduledFuture schedule(Runnable task, Date startTime); + + /** + * Schedule the given {@link Runnable}, invoking it at the specified execution time + * and subsequently with the given period. + *

Execution will end once the scheduler shuts down or the returned + * {@link ScheduledFuture} gets cancelled. + * @param task the Runnable to execute whenever the trigger fires + * @param startTime the desired first execution time for the task + * (if this is in the past, the task will be executed immediately, i.e. as soon as possible) + * @param period the interval between successive executions of the task (in milliseconds) + * @return a {@link ScheduledFuture} representing pending completion of the task + * @throws org.springframework.core.task.TaskRejectedException if the given task was not accepted + * for internal reasons (e.g. a pool overload handling policy or a pool shutdown in progress) + */ + ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period); + + /** + * Schedule the given {@link Runnable}, starting as soon as possible and + * invoking it with the given period. + *

Execution will end once the scheduler shuts down or the returned + * {@link ScheduledFuture} gets cancelled. + * @param task the Runnable to execute whenever the trigger fires + * @param period the interval between successive executions of the task (in milliseconds) + * @return a {@link ScheduledFuture} representing pending completion of the task + * @throws org.springframework.core.task.TaskRejectedException if the given task was not accepted + * for internal reasons (e.g. a pool overload handling policy or a pool shutdown in progress) + */ + ScheduledFuture scheduleAtFixedRate(Runnable task, long period); + + /** + * Schedule the given {@link Runnable}, invoking it at the specified execution time + * and subsequently with the given delay between the completion of one execution + * and the start of the next. + *

Execution will end once the scheduler shuts down or the returned + * {@link ScheduledFuture} gets cancelled. + * @param task the Runnable to execute whenever the trigger fires + * @param startTime the desired first execution time for the task + * (if this is in the past, the task will be executed immediately, i.e. as soon as possible) + * @param delay the delay between the completion of one execution and the start + * of the next (in milliseconds) + * @return a {@link ScheduledFuture} representing pending completion of the task + * @throws org.springframework.core.task.TaskRejectedException if the given task was not accepted + * for internal reasons (e.g. a pool overload handling policy or a pool shutdown in progress) + */ + ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay); + + /** + * Schedule the given {@link Runnable}, starting as soon as possible and + * invoking it with the given delay between the completion of one execution + * and the start of the next. + *

Execution will end once the scheduler shuts down or the returned + * {@link ScheduledFuture} gets cancelled. + * @param task the Runnable to execute whenever the trigger fires + * @param delay the interval between successive executions of the task (in milliseconds) + * @return a {@link ScheduledFuture} representing pending completion of the task + * @throws org.springframework.core.task.TaskRejectedException if the given task was not accepted + * for internal reasons (e.g. a pool overload handling policy or a pool shutdown in progress) + */ + ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay); + +} diff --git a/org.springframework.context/src/main/java/org/springframework/scheduling/Trigger.java b/org.springframework.context/src/main/java/org/springframework/scheduling/Trigger.java index 9849d4b932..1f17217ee9 100644 --- a/org.springframework.context/src/main/java/org/springframework/scheduling/Trigger.java +++ b/org.springframework.context/src/main/java/org/springframework/scheduling/Trigger.java @@ -1,41 +1,41 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.scheduling; - -import java.util.Date; - -/** - * Common interface for trigger objects that determine the next execution time - * of a task that they get associated with. - * - * @author Juergen Hoeller - * @since 3.0 - * @see TaskScheduler#schedule(Runnable, Trigger) - * @see org.springframework.scheduling.support.CronTrigger - */ -public interface Trigger { - - /** - * Determine the next execution time according to the given trigger context. - * @param triggerContext context object encapsulating last execution times - * and last completion time - * @return the next execution time as defined by the trigger, - * or null if the trigger won't fire anymore - */ - Date nextExecutionTime(TriggerContext triggerContext); - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling; + +import java.util.Date; + +/** + * Common interface for trigger objects that determine the next execution time + * of a task that they get associated with. + * + * @author Juergen Hoeller + * @since 3.0 + * @see TaskScheduler#schedule(Runnable, Trigger) + * @see org.springframework.scheduling.support.CronTrigger + */ +public interface Trigger { + + /** + * Determine the next execution time according to the given trigger context. + * @param triggerContext context object encapsulating last execution times + * and last completion time + * @return the next execution time as defined by the trigger, + * or null if the trigger won't fire anymore + */ + Date nextExecutionTime(TriggerContext triggerContext); + +} diff --git a/org.springframework.context/src/main/java/org/springframework/scheduling/TriggerContext.java b/org.springframework.context/src/main/java/org/springframework/scheduling/TriggerContext.java index 3785b43784..bd483a48e4 100644 --- a/org.springframework.context/src/main/java/org/springframework/scheduling/TriggerContext.java +++ b/org.springframework.context/src/main/java/org/springframework/scheduling/TriggerContext.java @@ -1,48 +1,48 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.scheduling; - -import java.util.Date; - -/** - * Context object encapsulating last execution times and last completion time - * of a given task. - * - * @author Juergen Hoeller - * @since 3.0 - */ -public interface TriggerContext { - - /** - * Return the last scheduled execution time of the task, - * or null if not scheduled before. - */ - Date lastScheduledExecutionTime(); - - /** - * Return the last actual execution time of the task, - * or null if not scheduled before. - */ - Date lastActualExecutionTime(); - - /** - * Return the last completion time of the task, - * or null if not scheduled before. - */ - Date lastCompletionTime(); - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling; + +import java.util.Date; + +/** + * Context object encapsulating last execution times and last completion time + * of a given task. + * + * @author Juergen Hoeller + * @since 3.0 + */ +public interface TriggerContext { + + /** + * Return the last scheduled execution time of the task, + * or null if not scheduled before. + */ + Date lastScheduledExecutionTime(); + + /** + * Return the last actual execution time of the task, + * or null if not scheduled before. + */ + Date lastActualExecutionTime(); + + /** + * Return the last completion time of the task, + * or null if not scheduled before. + */ + Date lastCompletionTime(); + +} diff --git a/org.springframework.context/src/main/java/org/springframework/scheduling/annotation/Async.java b/org.springframework.context/src/main/java/org/springframework/scheduling/annotation/Async.java index 90276bf638..c79f9ecd83 100644 --- a/org.springframework.context/src/main/java/org/springframework/scheduling/annotation/Async.java +++ b/org.springframework.context/src/main/java/org/springframework/scheduling/annotation/Async.java @@ -1,49 +1,49 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.scheduling.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation that marks a method as a candidate for asynchronous execution. - * Can also be used at the type level, in which case all of the type's methods are - * considered as asynchronous. - * - *

In terms of target method signatures, any parameter types are supported. - * However, the return type is constrained to either void or - * java.util.concurrent.Future. In the latter case, the Future handle - * returned from the proxy will be an actual asynchronous Future that can be used - * to track the result of the asynchronous method execution. However, since the - * target method needs to implement the same signature, it will have to return - * a temporary Future handle that just passes the return value through: e.g. - * Spring's {@link AsyncResult} or EJB 3.1's javax.ejb.AsyncResult. - * - * @author Juergen Hoeller - * @since 3.0 - * @see org.springframework.aop.interceptor.AsyncExecutionInterceptor - * @see AsyncAnnotationAdvisor - */ -@Target({ElementType.TYPE, ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface Async { - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation that marks a method as a candidate for asynchronous execution. + * Can also be used at the type level, in which case all of the type's methods are + * considered as asynchronous. + * + *

In terms of target method signatures, any parameter types are supported. + * However, the return type is constrained to either void or + * java.util.concurrent.Future. In the latter case, the Future handle + * returned from the proxy will be an actual asynchronous Future that can be used + * to track the result of the asynchronous method execution. However, since the + * target method needs to implement the same signature, it will have to return + * a temporary Future handle that just passes the return value through: e.g. + * Spring's {@link AsyncResult} or EJB 3.1's javax.ejb.AsyncResult. + * + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.aop.interceptor.AsyncExecutionInterceptor + * @see AsyncAnnotationAdvisor + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Async { + +} diff --git a/org.springframework.context/src/main/java/org/springframework/scheduling/annotation/AsyncResult.java b/org.springframework.context/src/main/java/org/springframework/scheduling/annotation/AsyncResult.java index f13e17cea3..bfe91befc4 100644 --- a/org.springframework.context/src/main/java/org/springframework/scheduling/annotation/AsyncResult.java +++ b/org.springframework.context/src/main/java/org/springframework/scheduling/annotation/AsyncResult.java @@ -1,63 +1,63 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.scheduling.annotation; - -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -/** - * A pass-through Future handle that can be used for method signatures - * which are declared with a Future return type for asynchronous execution. - * - * @author Juergen Hoeller - * @since 3.0 - * @see org.springframework.scheduling.annotation.Async - */ -public class AsyncResult implements Future { - - private final V value; - - - /** - * Create a new AsyncResult holder. - * @param value the value to pass through - */ - public AsyncResult(V value) { - this.value = value; - } - - public boolean cancel(boolean mayInterruptIfRunning) { - return false; - } - - public boolean isCancelled() { - return false; - } - - public boolean isDone() { - return true; - } - - public V get() { - return this.value; - } - - public V get(long timeout, TimeUnit unit) { - return this.value; - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling.annotation; + +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +/** + * A pass-through Future handle that can be used for method signatures + * which are declared with a Future return type for asynchronous execution. + * + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.scheduling.annotation.Async + */ +public class AsyncResult implements Future { + + private final V value; + + + /** + * Create a new AsyncResult holder. + * @param value the value to pass through + */ + public AsyncResult(V value) { + this.value = value; + } + + public boolean cancel(boolean mayInterruptIfRunning) { + return false; + } + + public boolean isCancelled() { + return false; + } + + public boolean isDone() { + return true; + } + + public V get() { + return this.value; + } + + public V get(long timeout, TimeUnit unit) { + return this.value; + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/scheduling/annotation/Scheduled.java b/org.springframework.context/src/main/java/org/springframework/scheduling/annotation/Scheduled.java index 87b9693acd..ccda008fcc 100644 --- a/org.springframework.context/src/main/java/org/springframework/scheduling/annotation/Scheduled.java +++ b/org.springframework.context/src/main/java/org/springframework/scheduling/annotation/Scheduled.java @@ -1,71 +1,71 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotation that marks a method to be scheduled. Exactly one of the - * cron, fixedDelay, or fixedRate - * attributes must be provided. - * - *

The annotated method must expect no arguments and have a - * void return type. - * - *

Processing of {@code @Scheduled} annotations is performed by - * registering a {@link ScheduledAnnotationBeanPostProcessor}. This can be - * done manually or, more conveniently, through the {@code } - * element or @{@link EnableScheduling} annotation. - * - * @author Mark Fisher - * @author Dave Syer - * @since 3.0 - * @see EnableScheduling - * @see ScheduledAnnotationBeanPostProcessor - */ -@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface Scheduled { - - /** - * A cron-like expression, extending the usual UN*X definition to include - * triggers on the second as well as minute, hour, day of month, month - * and day of week. e.g. "0 * * * * MON-FRI" means once - * per minute on weekdays (at the top of the minute - the 0th second). - * @return an expression that can be parsed to a cron schedule - */ - String cron() default ""; - - /** - * Execute the annotated method with a fixed period between the end - * of the last invocation and the start of the next. - * @return the delay in milliseconds - */ - long fixedDelay() default -1; - - /** - * Execute the annotated method with a fixed period between invocations. - * @return the period in milliseconds - */ - long fixedRate() default -1; - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation that marks a method to be scheduled. Exactly one of the + * cron, fixedDelay, or fixedRate + * attributes must be provided. + * + *

The annotated method must expect no arguments and have a + * void return type. + * + *

Processing of {@code @Scheduled} annotations is performed by + * registering a {@link ScheduledAnnotationBeanPostProcessor}. This can be + * done manually or, more conveniently, through the {@code } + * element or @{@link EnableScheduling} annotation. + * + * @author Mark Fisher + * @author Dave Syer + * @since 3.0 + * @see EnableScheduling + * @see ScheduledAnnotationBeanPostProcessor + */ +@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Scheduled { + + /** + * A cron-like expression, extending the usual UN*X definition to include + * triggers on the second as well as minute, hour, day of month, month + * and day of week. e.g. "0 * * * * MON-FRI" means once + * per minute on weekdays (at the top of the minute - the 0th second). + * @return an expression that can be parsed to a cron schedule + */ + String cron() default ""; + + /** + * Execute the annotated method with a fixed period between the end + * of the last invocation and the start of the next. + * @return the delay in milliseconds + */ + long fixedDelay() default -1; + + /** + * Execute the annotated method with a fixed period between invocations. + * @return the period in milliseconds + */ + long fixedRate() default -1; + +} diff --git a/org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskScheduler.java b/org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskScheduler.java index da79d35ade..ff4cf939e7 100644 --- a/org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskScheduler.java +++ b/org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskScheduler.java @@ -1,187 +1,187 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.Date; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - -import org.springframework.core.task.TaskRejectedException; -import org.springframework.scheduling.TaskScheduler; -import org.springframework.scheduling.Trigger; -import org.springframework.scheduling.support.TaskUtils; -import org.springframework.util.Assert; -import org.springframework.util.ErrorHandler; - -/** - * Adapter that takes a JDK 1.5 java.util.concurrent.ScheduledExecutorService - * and exposes a Spring {@link org.springframework.scheduling.TaskScheduler} for it. - * Extends {@link ConcurrentTaskExecutor} in order to implement the - * {@link org.springframework.scheduling.SchedulingTaskExecutor} interface as well. - * - *

Note that there is a pre-built {@link ThreadPoolTaskScheduler} that allows for - * defining a JDK 1.5 {@link java.util.concurrent.ScheduledThreadPoolExecutor} in bean style, - * exposing it as a Spring {@link org.springframework.scheduling.TaskScheduler} directly. - * This is a convenient alternative to a raw ScheduledThreadPoolExecutor definition with - * a separate definition of the present adapter class. - * - * @author Juergen Hoeller - * @author Mark Fisher - * @since 3.0 - * @see java.util.concurrent.ScheduledExecutorService - * @see java.util.concurrent.ScheduledThreadPoolExecutor - * @see java.util.concurrent.Executors - * @see ThreadPoolTaskScheduler - */ -public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements TaskScheduler { - - private volatile ScheduledExecutorService scheduledExecutor; - - private volatile ErrorHandler errorHandler; - - - /** - * Create a new ConcurrentTaskScheduler, - * using a single thread executor as default. - * @see java.util.concurrent.Executors#newSingleThreadScheduledExecutor() - */ - public ConcurrentTaskScheduler() { - super(); - setScheduledExecutor(null); - } - - /** - * Create a new ConcurrentTaskScheduler, - * using the given JDK 1.5 executor as shared delegate. - * @param scheduledExecutor the JDK 1.5 scheduled executor to delegate to - * for {@link org.springframework.scheduling.SchedulingTaskExecutor} as well - * as {@link TaskScheduler} invocations - */ - public ConcurrentTaskScheduler(ScheduledExecutorService scheduledExecutor) { - super(scheduledExecutor); - setScheduledExecutor(scheduledExecutor); - } - - /** - * Create a new ConcurrentTaskScheduler, - * using the given JDK 1.5 executors as delegates. - * @param concurrentExecutor the JDK 1.5 concurrent executor to delegate to - * for {@link org.springframework.scheduling.SchedulingTaskExecutor} invocations - * @param scheduledExecutor the JDK 1.5 scheduled executor to delegate to - * for {@link TaskScheduler} invocations - */ - public ConcurrentTaskScheduler(Executor concurrentExecutor, ScheduledExecutorService scheduledExecutor) { - super(concurrentExecutor); - setScheduledExecutor(scheduledExecutor); - } - - - /** - * Specify the JDK 1.5 scheduled executor to delegate to. - *

Note: This will only apply to {@link TaskScheduler} invocations. - * If you want the given executor to apply to - * {@link org.springframework.scheduling.SchedulingTaskExecutor} invocations - * as well, pass the same executor reference to {@link #setConcurrentExecutor}. - * @see #setConcurrentExecutor - */ - public final void setScheduledExecutor(ScheduledExecutorService scheduledExecutor) { - this.scheduledExecutor = - (scheduledExecutor != null ? scheduledExecutor : Executors.newSingleThreadScheduledExecutor()); - } - - /** - * Provide an {@link ErrorHandler} strategy. - */ - public void setErrorHandler(ErrorHandler errorHandler) { - Assert.notNull(errorHandler, "'errorHandler' must not be null"); - this.errorHandler = errorHandler; - } - - - public ScheduledFuture schedule(Runnable task, Trigger trigger) { - try { - ErrorHandler errorHandler = - (this.errorHandler != null ? this.errorHandler : TaskUtils.getDefaultErrorHandler(true)); - return new ReschedulingRunnable(task, trigger, this.scheduledExecutor, errorHandler).schedule(); - } - catch (RejectedExecutionException ex) { - throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex); - } - } - - public ScheduledFuture schedule(Runnable task, Date startTime) { - long initialDelay = startTime.getTime() - System.currentTimeMillis(); - try { - return this.scheduledExecutor.schedule( - errorHandlingTask(task, false), initialDelay, TimeUnit.MILLISECONDS); - } - catch (RejectedExecutionException ex) { - throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex); - } - } - - public ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period) { - long initialDelay = startTime.getTime() - System.currentTimeMillis(); - try { - return this.scheduledExecutor.scheduleAtFixedRate( - errorHandlingTask(task, true), initialDelay, period, TimeUnit.MILLISECONDS); - } - catch (RejectedExecutionException ex) { - throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex); - } - } - - public ScheduledFuture scheduleAtFixedRate(Runnable task, long period) { - try { - return this.scheduledExecutor.scheduleAtFixedRate( - errorHandlingTask(task, true), 0, period, TimeUnit.MILLISECONDS); - } - catch (RejectedExecutionException ex) { - throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex); - } - } - - public ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay) { - long initialDelay = startTime.getTime() - System.currentTimeMillis(); - try { - return this.scheduledExecutor.scheduleWithFixedDelay( - errorHandlingTask(task, true), initialDelay, delay, TimeUnit.MILLISECONDS); - } - catch (RejectedExecutionException ex) { - throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex); - } - } - - public ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay) { - try { - return this.scheduledExecutor.scheduleWithFixedDelay( - errorHandlingTask(task, true), 0, delay, TimeUnit.MILLISECONDS); - } - catch (RejectedExecutionException ex) { - throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex); - } - } - - private Runnable errorHandlingTask(Runnable task, boolean isRepeatingTask) { - return TaskUtils.decorateTaskWithErrorHandler(task, this.errorHandler, isRepeatingTask); - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.Date; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.springframework.core.task.TaskRejectedException; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.Trigger; +import org.springframework.scheduling.support.TaskUtils; +import org.springframework.util.Assert; +import org.springframework.util.ErrorHandler; + +/** + * Adapter that takes a JDK 1.5 java.util.concurrent.ScheduledExecutorService + * and exposes a Spring {@link org.springframework.scheduling.TaskScheduler} for it. + * Extends {@link ConcurrentTaskExecutor} in order to implement the + * {@link org.springframework.scheduling.SchedulingTaskExecutor} interface as well. + * + *

Note that there is a pre-built {@link ThreadPoolTaskScheduler} that allows for + * defining a JDK 1.5 {@link java.util.concurrent.ScheduledThreadPoolExecutor} in bean style, + * exposing it as a Spring {@link org.springframework.scheduling.TaskScheduler} directly. + * This is a convenient alternative to a raw ScheduledThreadPoolExecutor definition with + * a separate definition of the present adapter class. + * + * @author Juergen Hoeller + * @author Mark Fisher + * @since 3.0 + * @see java.util.concurrent.ScheduledExecutorService + * @see java.util.concurrent.ScheduledThreadPoolExecutor + * @see java.util.concurrent.Executors + * @see ThreadPoolTaskScheduler + */ +public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements TaskScheduler { + + private volatile ScheduledExecutorService scheduledExecutor; + + private volatile ErrorHandler errorHandler; + + + /** + * Create a new ConcurrentTaskScheduler, + * using a single thread executor as default. + * @see java.util.concurrent.Executors#newSingleThreadScheduledExecutor() + */ + public ConcurrentTaskScheduler() { + super(); + setScheduledExecutor(null); + } + + /** + * Create a new ConcurrentTaskScheduler, + * using the given JDK 1.5 executor as shared delegate. + * @param scheduledExecutor the JDK 1.5 scheduled executor to delegate to + * for {@link org.springframework.scheduling.SchedulingTaskExecutor} as well + * as {@link TaskScheduler} invocations + */ + public ConcurrentTaskScheduler(ScheduledExecutorService scheduledExecutor) { + super(scheduledExecutor); + setScheduledExecutor(scheduledExecutor); + } + + /** + * Create a new ConcurrentTaskScheduler, + * using the given JDK 1.5 executors as delegates. + * @param concurrentExecutor the JDK 1.5 concurrent executor to delegate to + * for {@link org.springframework.scheduling.SchedulingTaskExecutor} invocations + * @param scheduledExecutor the JDK 1.5 scheduled executor to delegate to + * for {@link TaskScheduler} invocations + */ + public ConcurrentTaskScheduler(Executor concurrentExecutor, ScheduledExecutorService scheduledExecutor) { + super(concurrentExecutor); + setScheduledExecutor(scheduledExecutor); + } + + + /** + * Specify the JDK 1.5 scheduled executor to delegate to. + *

Note: This will only apply to {@link TaskScheduler} invocations. + * If you want the given executor to apply to + * {@link org.springframework.scheduling.SchedulingTaskExecutor} invocations + * as well, pass the same executor reference to {@link #setConcurrentExecutor}. + * @see #setConcurrentExecutor + */ + public final void setScheduledExecutor(ScheduledExecutorService scheduledExecutor) { + this.scheduledExecutor = + (scheduledExecutor != null ? scheduledExecutor : Executors.newSingleThreadScheduledExecutor()); + } + + /** + * Provide an {@link ErrorHandler} strategy. + */ + public void setErrorHandler(ErrorHandler errorHandler) { + Assert.notNull(errorHandler, "'errorHandler' must not be null"); + this.errorHandler = errorHandler; + } + + + public ScheduledFuture schedule(Runnable task, Trigger trigger) { + try { + ErrorHandler errorHandler = + (this.errorHandler != null ? this.errorHandler : TaskUtils.getDefaultErrorHandler(true)); + return new ReschedulingRunnable(task, trigger, this.scheduledExecutor, errorHandler).schedule(); + } + catch (RejectedExecutionException ex) { + throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex); + } + } + + public ScheduledFuture schedule(Runnable task, Date startTime) { + long initialDelay = startTime.getTime() - System.currentTimeMillis(); + try { + return this.scheduledExecutor.schedule( + errorHandlingTask(task, false), initialDelay, TimeUnit.MILLISECONDS); + } + catch (RejectedExecutionException ex) { + throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex); + } + } + + public ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period) { + long initialDelay = startTime.getTime() - System.currentTimeMillis(); + try { + return this.scheduledExecutor.scheduleAtFixedRate( + errorHandlingTask(task, true), initialDelay, period, TimeUnit.MILLISECONDS); + } + catch (RejectedExecutionException ex) { + throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex); + } + } + + public ScheduledFuture scheduleAtFixedRate(Runnable task, long period) { + try { + return this.scheduledExecutor.scheduleAtFixedRate( + errorHandlingTask(task, true), 0, period, TimeUnit.MILLISECONDS); + } + catch (RejectedExecutionException ex) { + throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex); + } + } + + public ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay) { + long initialDelay = startTime.getTime() - System.currentTimeMillis(); + try { + return this.scheduledExecutor.scheduleWithFixedDelay( + errorHandlingTask(task, true), initialDelay, delay, TimeUnit.MILLISECONDS); + } + catch (RejectedExecutionException ex) { + throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex); + } + } + + public ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay) { + try { + return this.scheduledExecutor.scheduleWithFixedDelay( + errorHandlingTask(task, true), 0, delay, TimeUnit.MILLISECONDS); + } + catch (RejectedExecutionException ex) { + throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex); + } + } + + private Runnable errorHandlingTask(Runnable task, boolean isRepeatingTask) { + return TaskUtils.decorateTaskWithErrorHandler(task, this.errorHandler, isRepeatingTask); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ExecutorConfigurationSupport.java b/org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ExecutorConfigurationSupport.java index 1f8c37c31e..56bbca108f 100644 --- a/org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ExecutorConfigurationSupport.java +++ b/org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ExecutorConfigurationSupport.java @@ -1,160 +1,160 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.scheduling.concurrent; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.RejectedExecutionHandler; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.beans.factory.BeanNameAware; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; - -/** - * Base class for classes that are setting up a - * java.util.concurrent.ExecutorService - * (typically a {@link java.util.concurrent.ThreadPoolExecutor}). - * Defines common configuration settings and common lifecycle handling. - * - * @author Juergen Hoeller - * @since 3.0 - * @see java.util.concurrent.ExecutorService - * @see java.util.concurrent.Executors - * @see java.util.concurrent.ThreadPoolExecutor - */ -public abstract class ExecutorConfigurationSupport extends CustomizableThreadFactory - implements BeanNameAware, InitializingBean, DisposableBean { - - protected final Log logger = LogFactory.getLog(getClass()); - - private ThreadFactory threadFactory = this; - - private boolean threadNamePrefixSet = false; - - private RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy(); - - private boolean waitForTasksToCompleteOnShutdown = false; - - private String beanName; - - private ExecutorService executor; - - - /** - * Set the ThreadFactory to use for the ThreadPoolExecutor's thread pool. - * Default is the ThreadPoolExecutor's default thread factory. - * @see java.util.concurrent.Executors#defaultThreadFactory() - */ - public void setThreadFactory(ThreadFactory threadFactory) { - this.threadFactory = (threadFactory != null ? threadFactory : this); - } - - @Override - public void setThreadNamePrefix(String threadNamePrefix) { - super.setThreadNamePrefix(threadNamePrefix); - this.threadNamePrefixSet = true; - } - - /** - * Set the RejectedExecutionHandler to use for the ThreadPoolExecutor. - * Default is the ThreadPoolExecutor's default abort policy. - * @see java.util.concurrent.ThreadPoolExecutor.AbortPolicy - */ - public void setRejectedExecutionHandler(RejectedExecutionHandler rejectedExecutionHandler) { - this.rejectedExecutionHandler = - (rejectedExecutionHandler != null ? rejectedExecutionHandler : new ThreadPoolExecutor.AbortPolicy()); - } - - /** - * Set whether to wait for scheduled tasks to complete on shutdown. - *

Default is "false". Switch this to "true" if you prefer - * fully completed tasks at the expense of a longer shutdown phase. - * @see java.util.concurrent.ExecutorService#shutdown() - * @see java.util.concurrent.ExecutorService#shutdownNow() - */ - public void setWaitForTasksToCompleteOnShutdown(boolean waitForJobsToCompleteOnShutdown) { - this.waitForTasksToCompleteOnShutdown = waitForJobsToCompleteOnShutdown; - } - - public void setBeanName(String name) { - this.beanName = name; - } - - - /** - * Calls initialize() after the container applied all property values. - * @see #initialize() - */ - public void afterPropertiesSet() { - initialize(); - } - - /** - * Set up the ExecutorService. - */ - public void initialize() { - if (logger.isInfoEnabled()) { - logger.info("Initializing ExecutorService " + (this.beanName != null ? " '" + this.beanName + "'" : "")); - } - if (!this.threadNamePrefixSet && this.beanName != null) { - setThreadNamePrefix(this.beanName + "-"); - } - this.executor = initializeExecutor(this.threadFactory, this.rejectedExecutionHandler); - } - - /** - * Create the target {@link java.util.concurrent.ExecutorService} instance. - * Called by afterPropertiesSet. - * @param threadFactory the ThreadFactory to use - * @param rejectedExecutionHandler the RejectedExecutionHandler to use - * @return a new ExecutorService instance - * @see #afterPropertiesSet() - */ - protected abstract ExecutorService initializeExecutor( - ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler); - - - /** - * Calls shutdown when the BeanFactory destroys - * the task executor instance. - * @see #shutdown() - */ - public void destroy() { - shutdown(); - } - - /** - * Perform a shutdown on the ThreadPoolExecutor. - * @see java.util.concurrent.ExecutorService#shutdown() - */ - public void shutdown() { - if (logger.isInfoEnabled()) { - logger.info("Shutting down ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : "")); - } - if (this.waitForTasksToCompleteOnShutdown) { - this.executor.shutdown(); - } - else { - this.executor.shutdownNow(); - } - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling.concurrent; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; + +/** + * Base class for classes that are setting up a + * java.util.concurrent.ExecutorService + * (typically a {@link java.util.concurrent.ThreadPoolExecutor}). + * Defines common configuration settings and common lifecycle handling. + * + * @author Juergen Hoeller + * @since 3.0 + * @see java.util.concurrent.ExecutorService + * @see java.util.concurrent.Executors + * @see java.util.concurrent.ThreadPoolExecutor + */ +public abstract class ExecutorConfigurationSupport extends CustomizableThreadFactory + implements BeanNameAware, InitializingBean, DisposableBean { + + protected final Log logger = LogFactory.getLog(getClass()); + + private ThreadFactory threadFactory = this; + + private boolean threadNamePrefixSet = false; + + private RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.AbortPolicy(); + + private boolean waitForTasksToCompleteOnShutdown = false; + + private String beanName; + + private ExecutorService executor; + + + /** + * Set the ThreadFactory to use for the ThreadPoolExecutor's thread pool. + * Default is the ThreadPoolExecutor's default thread factory. + * @see java.util.concurrent.Executors#defaultThreadFactory() + */ + public void setThreadFactory(ThreadFactory threadFactory) { + this.threadFactory = (threadFactory != null ? threadFactory : this); + } + + @Override + public void setThreadNamePrefix(String threadNamePrefix) { + super.setThreadNamePrefix(threadNamePrefix); + this.threadNamePrefixSet = true; + } + + /** + * Set the RejectedExecutionHandler to use for the ThreadPoolExecutor. + * Default is the ThreadPoolExecutor's default abort policy. + * @see java.util.concurrent.ThreadPoolExecutor.AbortPolicy + */ + public void setRejectedExecutionHandler(RejectedExecutionHandler rejectedExecutionHandler) { + this.rejectedExecutionHandler = + (rejectedExecutionHandler != null ? rejectedExecutionHandler : new ThreadPoolExecutor.AbortPolicy()); + } + + /** + * Set whether to wait for scheduled tasks to complete on shutdown. + *

Default is "false". Switch this to "true" if you prefer + * fully completed tasks at the expense of a longer shutdown phase. + * @see java.util.concurrent.ExecutorService#shutdown() + * @see java.util.concurrent.ExecutorService#shutdownNow() + */ + public void setWaitForTasksToCompleteOnShutdown(boolean waitForJobsToCompleteOnShutdown) { + this.waitForTasksToCompleteOnShutdown = waitForJobsToCompleteOnShutdown; + } + + public void setBeanName(String name) { + this.beanName = name; + } + + + /** + * Calls initialize() after the container applied all property values. + * @see #initialize() + */ + public void afterPropertiesSet() { + initialize(); + } + + /** + * Set up the ExecutorService. + */ + public void initialize() { + if (logger.isInfoEnabled()) { + logger.info("Initializing ExecutorService " + (this.beanName != null ? " '" + this.beanName + "'" : "")); + } + if (!this.threadNamePrefixSet && this.beanName != null) { + setThreadNamePrefix(this.beanName + "-"); + } + this.executor = initializeExecutor(this.threadFactory, this.rejectedExecutionHandler); + } + + /** + * Create the target {@link java.util.concurrent.ExecutorService} instance. + * Called by afterPropertiesSet. + * @param threadFactory the ThreadFactory to use + * @param rejectedExecutionHandler the RejectedExecutionHandler to use + * @return a new ExecutorService instance + * @see #afterPropertiesSet() + */ + protected abstract ExecutorService initializeExecutor( + ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler); + + + /** + * Calls shutdown when the BeanFactory destroys + * the task executor instance. + * @see #shutdown() + */ + public void destroy() { + shutdown(); + } + + /** + * Perform a shutdown on the ThreadPoolExecutor. + * @see java.util.concurrent.ExecutorService#shutdown() + */ + public void shutdown() { + if (logger.isInfoEnabled()) { + logger.info("Shutting down ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : "")); + } + if (this.waitForTasksToCompleteOnShutdown) { + this.executor.shutdown(); + } + else { + this.executor.shutdownNow(); + } + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ReschedulingRunnable.java b/org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ReschedulingRunnable.java index f63a77bb06..729dc02e77 100644 --- a/org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ReschedulingRunnable.java +++ b/org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ReschedulingRunnable.java @@ -1,124 +1,124 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.scheduling.concurrent; - -import java.util.Date; -import java.util.concurrent.Delayed; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import org.springframework.scheduling.Trigger; -import org.springframework.scheduling.support.DelegatingErrorHandlingRunnable; -import org.springframework.scheduling.support.SimpleTriggerContext; -import org.springframework.util.ErrorHandler; - -/** - * Internal adapter that reschedules an underlying {@link Runnable} according - * to the next execution time suggested by a given {@link Trigger}. - * - *

Necessary because a native {@link ScheduledExecutorService} supports - * delay-driven execution only. The flexibility of the {@link Trigger} interface - * will be translated onto a delay for the next execution time (repeatedly). - * - * @author Juergen Hoeller - * @author Mark Fisher - * @since 3.0 - */ -class ReschedulingRunnable extends DelegatingErrorHandlingRunnable implements ScheduledFuture { - - private final Trigger trigger; - - private final SimpleTriggerContext triggerContext = new SimpleTriggerContext(); - - private final ScheduledExecutorService executor; - - private volatile ScheduledFuture currentFuture; - - private volatile Date scheduledExecutionTime; - - private final Object triggerContextMonitor = new Object(); - - - public ReschedulingRunnable(Runnable delegate, Trigger trigger, ScheduledExecutorService executor, ErrorHandler errorHandler) { - super(delegate, errorHandler); - this.trigger = trigger; - this.executor = executor; - } - - - public ScheduledFuture schedule() { - synchronized (this.triggerContextMonitor) { - this.scheduledExecutionTime = this.trigger.nextExecutionTime(this.triggerContext); - if (this.scheduledExecutionTime == null) { - return null; - } - long initialDelay = this.scheduledExecutionTime.getTime() - System.currentTimeMillis(); - this.currentFuture = this.executor.schedule(this, initialDelay, TimeUnit.MILLISECONDS); - return this; - } - } - - @Override - public void run() { - Date actualExecutionTime = new Date(); - super.run(); - Date completionTime = new Date(); - synchronized (this.triggerContextMonitor) { - this.triggerContext.update(this.scheduledExecutionTime, actualExecutionTime, completionTime); - } - if (!this.currentFuture.isCancelled()) { - schedule(); - } - } - - - public boolean cancel(boolean mayInterruptIfRunning) { - return this.currentFuture.cancel(mayInterruptIfRunning); - } - - public boolean isCancelled() { - return this.currentFuture.isCancelled(); - } - - public boolean isDone() { - return this.currentFuture.isDone(); - } - - public Object get() throws InterruptedException, ExecutionException { - return this.currentFuture.get(); - } - - public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { - return this.currentFuture.get(timeout, unit); - } - - public long getDelay(TimeUnit unit) { - return this.currentFuture.getDelay(unit); - } - - public int compareTo(Delayed other) { - if (this == other) { - return 0; - } - long diff = getDelay(TimeUnit.MILLISECONDS) - other.getDelay(TimeUnit.MILLISECONDS); - return (diff == 0 ? 0 : ((diff < 0)? -1 : 1)); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling.concurrent; + +import java.util.Date; +import java.util.concurrent.Delayed; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.springframework.scheduling.Trigger; +import org.springframework.scheduling.support.DelegatingErrorHandlingRunnable; +import org.springframework.scheduling.support.SimpleTriggerContext; +import org.springframework.util.ErrorHandler; + +/** + * Internal adapter that reschedules an underlying {@link Runnable} according + * to the next execution time suggested by a given {@link Trigger}. + * + *

Necessary because a native {@link ScheduledExecutorService} supports + * delay-driven execution only. The flexibility of the {@link Trigger} interface + * will be translated onto a delay for the next execution time (repeatedly). + * + * @author Juergen Hoeller + * @author Mark Fisher + * @since 3.0 + */ +class ReschedulingRunnable extends DelegatingErrorHandlingRunnable implements ScheduledFuture { + + private final Trigger trigger; + + private final SimpleTriggerContext triggerContext = new SimpleTriggerContext(); + + private final ScheduledExecutorService executor; + + private volatile ScheduledFuture currentFuture; + + private volatile Date scheduledExecutionTime; + + private final Object triggerContextMonitor = new Object(); + + + public ReschedulingRunnable(Runnable delegate, Trigger trigger, ScheduledExecutorService executor, ErrorHandler errorHandler) { + super(delegate, errorHandler); + this.trigger = trigger; + this.executor = executor; + } + + + public ScheduledFuture schedule() { + synchronized (this.triggerContextMonitor) { + this.scheduledExecutionTime = this.trigger.nextExecutionTime(this.triggerContext); + if (this.scheduledExecutionTime == null) { + return null; + } + long initialDelay = this.scheduledExecutionTime.getTime() - System.currentTimeMillis(); + this.currentFuture = this.executor.schedule(this, initialDelay, TimeUnit.MILLISECONDS); + return this; + } + } + + @Override + public void run() { + Date actualExecutionTime = new Date(); + super.run(); + Date completionTime = new Date(); + synchronized (this.triggerContextMonitor) { + this.triggerContext.update(this.scheduledExecutionTime, actualExecutionTime, completionTime); + } + if (!this.currentFuture.isCancelled()) { + schedule(); + } + } + + + public boolean cancel(boolean mayInterruptIfRunning) { + return this.currentFuture.cancel(mayInterruptIfRunning); + } + + public boolean isCancelled() { + return this.currentFuture.isCancelled(); + } + + public boolean isDone() { + return this.currentFuture.isDone(); + } + + public Object get() throws InterruptedException, ExecutionException { + return this.currentFuture.get(); + } + + public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + return this.currentFuture.get(timeout, unit); + } + + public long getDelay(TimeUnit unit) { + return this.currentFuture.getDelay(unit); + } + + public int compareTo(Delayed other) { + if (this == other) { + return 0; + } + long diff = getDelay(TimeUnit.MILLISECONDS) - other.getDelay(TimeUnit.MILLISECONDS); + return (diff == 0 ? 0 : ((diff < 0)? -1 : 1)); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolTaskScheduler.java b/org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolTaskScheduler.java index fa42583444..c78ba7876e 100644 --- a/org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolTaskScheduler.java +++ b/org.springframework.context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolTaskScheduler.java @@ -1,251 +1,251 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.Date; -import java.util.concurrent.Callable; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.RejectedExecutionHandler; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; - -import org.springframework.core.task.TaskRejectedException; -import org.springframework.scheduling.SchedulingTaskExecutor; -import org.springframework.scheduling.TaskScheduler; -import org.springframework.scheduling.Trigger; -import org.springframework.scheduling.support.TaskUtils; -import org.springframework.util.Assert; -import org.springframework.util.ErrorHandler; - -/** - * Implementation of Spring's {@link TaskScheduler} interface, wrapping - * a native {@link java.util.concurrent.ScheduledThreadPoolExecutor}. - * - * @author Juergen Hoeller - * @author Mark Fisher - * @since 3.0 - * @see #setPoolSize - * @see #setThreadFactory - * @see #setErrorHandler - */ -public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport - implements TaskScheduler, SchedulingTaskExecutor { - - private volatile int poolSize = 1; - - private volatile ScheduledExecutorService scheduledExecutor; - - private volatile ErrorHandler errorHandler; - - - /** - * Set the ScheduledExecutorService's pool size. - * Default is 1. - */ - public void setPoolSize(int poolSize) { - Assert.isTrue(poolSize > 0, "'poolSize' must be 1 or higher"); - this.poolSize = poolSize; - } - - /** - * Provide an {@link ErrorHandler} strategy. - */ - public void setErrorHandler(ErrorHandler errorHandler) { - Assert.notNull(errorHandler, "'errorHandler' must not be null"); - this.errorHandler = errorHandler; - } - - protected ExecutorService initializeExecutor( - ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { - - this.scheduledExecutor = createExecutor(this.poolSize, threadFactory, rejectedExecutionHandler); - return this.scheduledExecutor; - } - - /** - * Create a new {@link ScheduledExecutorService} instance. - *

The default implementation creates a {@link ScheduledThreadPoolExecutor}. - * Can be overridden in subclasses to provide custom {@link ScheduledExecutorService} instances. - * @param poolSize the specified pool size - * @param threadFactory the ThreadFactory to use - * @param rejectedExecutionHandler the RejectedExecutionHandler to use - * @return a new ScheduledExecutorService instance - * @see #afterPropertiesSet() - * @see java.util.concurrent.ScheduledThreadPoolExecutor - */ - protected ScheduledExecutorService createExecutor( - int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { - - return new ScheduledThreadPoolExecutor(poolSize, threadFactory, rejectedExecutionHandler); - } - - /** - * Return the underlying ScheduledExecutorService for native access. - * @return the underlying ScheduledExecutorService (never null) - * @throws IllegalStateException if the ThreadPoolTaskScheduler hasn't been initialized yet - */ - public ScheduledExecutorService getScheduledExecutor() throws IllegalStateException { - Assert.state(this.scheduledExecutor != null, "ThreadPoolTaskScheduler not initialized"); - return this.scheduledExecutor; - } - - - // SchedulingTaskExecutor implementation - - public void execute(Runnable task) { - Executor executor = getScheduledExecutor(); - try { - executor.execute(errorHandlingTask(task, false)); - } - catch (RejectedExecutionException ex) { - throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); - } - } - - public void execute(Runnable task, long startTimeout) { - execute(task); - } - - public Future submit(Runnable task) { - ExecutorService executor = getScheduledExecutor(); - try { - return executor.submit(errorHandlingTask(task, false)); - } - catch (RejectedExecutionException ex) { - throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); - } - } - - public Future submit(Callable task) { - ExecutorService executor = getScheduledExecutor(); - try { - if (this.errorHandler != null) { - task = new DelegatingErrorHandlingCallable(task, this.errorHandler); - } - return executor.submit(task); - } - catch (RejectedExecutionException ex) { - throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); - } - } - - public boolean prefersShortLivedTasks() { - return true; - } - - - // TaskScheduler implementation - - public ScheduledFuture schedule(Runnable task, Trigger trigger) { - ScheduledExecutorService executor = getScheduledExecutor(); - try { - ErrorHandler errorHandler = - (this.errorHandler != null ? this.errorHandler : TaskUtils.getDefaultErrorHandler(true)); - return new ReschedulingRunnable(task, trigger, executor, errorHandler).schedule(); - } - catch (RejectedExecutionException ex) { - throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); - } - } - - public ScheduledFuture schedule(Runnable task, Date startTime) { - ScheduledExecutorService executor = getScheduledExecutor(); - long initialDelay = startTime.getTime() - System.currentTimeMillis(); - try { - return executor.schedule(errorHandlingTask(task, false), initialDelay, TimeUnit.MILLISECONDS); - } - catch (RejectedExecutionException ex) { - throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); - } - } - - public ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period) { - ScheduledExecutorService executor = getScheduledExecutor(); - long initialDelay = startTime.getTime() - System.currentTimeMillis(); - try { - return executor.scheduleAtFixedRate(errorHandlingTask(task, true), initialDelay, period, TimeUnit.MILLISECONDS); - } - catch (RejectedExecutionException ex) { - throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); - } - } - - public ScheduledFuture scheduleAtFixedRate(Runnable task, long period) { - ScheduledExecutorService executor = getScheduledExecutor(); - try { - return executor.scheduleAtFixedRate(errorHandlingTask(task, true), 0, period, TimeUnit.MILLISECONDS); - } - catch (RejectedExecutionException ex) { - throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); - } - } - - public ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay) { - ScheduledExecutorService executor = getScheduledExecutor(); - long initialDelay = startTime.getTime() - System.currentTimeMillis(); - try { - return executor.scheduleWithFixedDelay(errorHandlingTask(task, true), initialDelay, delay, TimeUnit.MILLISECONDS); - } - catch (RejectedExecutionException ex) { - throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); - } - } - - public ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay) { - ScheduledExecutorService executor = getScheduledExecutor(); - try { - return executor.scheduleWithFixedDelay(errorHandlingTask(task, true), 0, delay, TimeUnit.MILLISECONDS); - } - catch (RejectedExecutionException ex) { - throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); - } - } - - private Runnable errorHandlingTask(Runnable task, boolean isRepeatingTask) { - return TaskUtils.decorateTaskWithErrorHandler(task, this.errorHandler, isRepeatingTask); - } - - - private static class DelegatingErrorHandlingCallable implements Callable { - - private final Callable delegate; - - private final ErrorHandler errorHandler; - - DelegatingErrorHandlingCallable(Callable delegate, ErrorHandler errorHandler) { - this.delegate = delegate; - this.errorHandler = errorHandler; - } - - public V call() throws Exception { - try { - return delegate.call(); - } - catch (Throwable t) { - this.errorHandler.handleError(t); - return null; - } - } - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.Date; +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +import org.springframework.core.task.TaskRejectedException; +import org.springframework.scheduling.SchedulingTaskExecutor; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.Trigger; +import org.springframework.scheduling.support.TaskUtils; +import org.springframework.util.Assert; +import org.springframework.util.ErrorHandler; + +/** + * Implementation of Spring's {@link TaskScheduler} interface, wrapping + * a native {@link java.util.concurrent.ScheduledThreadPoolExecutor}. + * + * @author Juergen Hoeller + * @author Mark Fisher + * @since 3.0 + * @see #setPoolSize + * @see #setThreadFactory + * @see #setErrorHandler + */ +public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport + implements TaskScheduler, SchedulingTaskExecutor { + + private volatile int poolSize = 1; + + private volatile ScheduledExecutorService scheduledExecutor; + + private volatile ErrorHandler errorHandler; + + + /** + * Set the ScheduledExecutorService's pool size. + * Default is 1. + */ + public void setPoolSize(int poolSize) { + Assert.isTrue(poolSize > 0, "'poolSize' must be 1 or higher"); + this.poolSize = poolSize; + } + + /** + * Provide an {@link ErrorHandler} strategy. + */ + public void setErrorHandler(ErrorHandler errorHandler) { + Assert.notNull(errorHandler, "'errorHandler' must not be null"); + this.errorHandler = errorHandler; + } + + protected ExecutorService initializeExecutor( + ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { + + this.scheduledExecutor = createExecutor(this.poolSize, threadFactory, rejectedExecutionHandler); + return this.scheduledExecutor; + } + + /** + * Create a new {@link ScheduledExecutorService} instance. + *

The default implementation creates a {@link ScheduledThreadPoolExecutor}. + * Can be overridden in subclasses to provide custom {@link ScheduledExecutorService} instances. + * @param poolSize the specified pool size + * @param threadFactory the ThreadFactory to use + * @param rejectedExecutionHandler the RejectedExecutionHandler to use + * @return a new ScheduledExecutorService instance + * @see #afterPropertiesSet() + * @see java.util.concurrent.ScheduledThreadPoolExecutor + */ + protected ScheduledExecutorService createExecutor( + int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { + + return new ScheduledThreadPoolExecutor(poolSize, threadFactory, rejectedExecutionHandler); + } + + /** + * Return the underlying ScheduledExecutorService for native access. + * @return the underlying ScheduledExecutorService (never null) + * @throws IllegalStateException if the ThreadPoolTaskScheduler hasn't been initialized yet + */ + public ScheduledExecutorService getScheduledExecutor() throws IllegalStateException { + Assert.state(this.scheduledExecutor != null, "ThreadPoolTaskScheduler not initialized"); + return this.scheduledExecutor; + } + + + // SchedulingTaskExecutor implementation + + public void execute(Runnable task) { + Executor executor = getScheduledExecutor(); + try { + executor.execute(errorHandlingTask(task, false)); + } + catch (RejectedExecutionException ex) { + throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); + } + } + + public void execute(Runnable task, long startTimeout) { + execute(task); + } + + public Future submit(Runnable task) { + ExecutorService executor = getScheduledExecutor(); + try { + return executor.submit(errorHandlingTask(task, false)); + } + catch (RejectedExecutionException ex) { + throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); + } + } + + public Future submit(Callable task) { + ExecutorService executor = getScheduledExecutor(); + try { + if (this.errorHandler != null) { + task = new DelegatingErrorHandlingCallable(task, this.errorHandler); + } + return executor.submit(task); + } + catch (RejectedExecutionException ex) { + throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); + } + } + + public boolean prefersShortLivedTasks() { + return true; + } + + + // TaskScheduler implementation + + public ScheduledFuture schedule(Runnable task, Trigger trigger) { + ScheduledExecutorService executor = getScheduledExecutor(); + try { + ErrorHandler errorHandler = + (this.errorHandler != null ? this.errorHandler : TaskUtils.getDefaultErrorHandler(true)); + return new ReschedulingRunnable(task, trigger, executor, errorHandler).schedule(); + } + catch (RejectedExecutionException ex) { + throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); + } + } + + public ScheduledFuture schedule(Runnable task, Date startTime) { + ScheduledExecutorService executor = getScheduledExecutor(); + long initialDelay = startTime.getTime() - System.currentTimeMillis(); + try { + return executor.schedule(errorHandlingTask(task, false), initialDelay, TimeUnit.MILLISECONDS); + } + catch (RejectedExecutionException ex) { + throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); + } + } + + public ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period) { + ScheduledExecutorService executor = getScheduledExecutor(); + long initialDelay = startTime.getTime() - System.currentTimeMillis(); + try { + return executor.scheduleAtFixedRate(errorHandlingTask(task, true), initialDelay, period, TimeUnit.MILLISECONDS); + } + catch (RejectedExecutionException ex) { + throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); + } + } + + public ScheduledFuture scheduleAtFixedRate(Runnable task, long period) { + ScheduledExecutorService executor = getScheduledExecutor(); + try { + return executor.scheduleAtFixedRate(errorHandlingTask(task, true), 0, period, TimeUnit.MILLISECONDS); + } + catch (RejectedExecutionException ex) { + throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); + } + } + + public ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay) { + ScheduledExecutorService executor = getScheduledExecutor(); + long initialDelay = startTime.getTime() - System.currentTimeMillis(); + try { + return executor.scheduleWithFixedDelay(errorHandlingTask(task, true), initialDelay, delay, TimeUnit.MILLISECONDS); + } + catch (RejectedExecutionException ex) { + throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); + } + } + + public ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay) { + ScheduledExecutorService executor = getScheduledExecutor(); + try { + return executor.scheduleWithFixedDelay(errorHandlingTask(task, true), 0, delay, TimeUnit.MILLISECONDS); + } + catch (RejectedExecutionException ex) { + throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex); + } + } + + private Runnable errorHandlingTask(Runnable task, boolean isRepeatingTask) { + return TaskUtils.decorateTaskWithErrorHandler(task, this.errorHandler, isRepeatingTask); + } + + + private static class DelegatingErrorHandlingCallable implements Callable { + + private final Callable delegate; + + private final ErrorHandler errorHandler; + + DelegatingErrorHandlingCallable(Callable delegate, ErrorHandler errorHandler) { + this.delegate = delegate; + this.errorHandler = errorHandler; + } + + public V call() throws Exception { + try { + return delegate.call(); + } + catch (Throwable t) { + this.errorHandler.handleError(t); + return null; + } + } + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/scheduling/config/ScheduledTaskRegistrar.java b/org.springframework.context/src/main/java/org/springframework/scheduling/config/ScheduledTaskRegistrar.java index 3f4adc4907..1898441e21 100644 --- a/org.springframework.context/src/main/java/org/springframework/scheduling/config/ScheduledTaskRegistrar.java +++ b/org.springframework.context/src/main/java/org/springframework/scheduling/config/ScheduledTaskRegistrar.java @@ -1,213 +1,213 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.config; - -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.scheduling.TaskScheduler; -import org.springframework.scheduling.Trigger; -import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler; -import org.springframework.scheduling.support.CronTrigger; -import org.springframework.util.Assert; - -/** - * Helper bean for registering tasks with a {@link TaskScheduler}, - * typically using cron expressions. - * - *

As of Spring 3.1, {@code ScheduledTaskRegistrar} has a more prominent user-facing - * role when used in conjunction with the @{@link - * org.springframework.scheduling.annotation.EnableAsync EnableAsync} annotation and its - * {@link org.springframework.scheduling.annotation.SchedulingConfigurer - * SchedulingConfigurer} callback interface. - * - * @author Juergen Hoeller - * @since 3.0 - * @see org.springframework.scheduling.annotation.EnableAsync - * @see org.springframework.scheduling.annotation.SchedulingConfigurer - */ -public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean { - - private TaskScheduler taskScheduler; - - private ScheduledExecutorService localExecutor; - - private Map triggerTasks; - - private Map cronTasks; - - private Map fixedRateTasks; - - private Map fixedDelayTasks; - - private final Set> scheduledFutures = new LinkedHashSet>(); - - - /** - * Set the TaskScheduler to register scheduled tasks with. - */ - public void setTaskScheduler(TaskScheduler taskScheduler) { - Assert.notNull(taskScheduler, "TaskScheduler must not be null"); - this.taskScheduler = taskScheduler; - } - - /** - * Set the {@link org.springframework.scheduling.TaskScheduler} to register scheduled - * tasks with, or a {@link java.util.concurrent.ScheduledExecutorService} to be - * wrapped as a TaskScheduler. - */ - public void setScheduler(Object scheduler) { - Assert.notNull(scheduler, "Scheduler object must not be null"); - if (scheduler instanceof TaskScheduler) { - this.taskScheduler = (TaskScheduler) scheduler; - } - else if (scheduler instanceof ScheduledExecutorService) { - this.taskScheduler = new ConcurrentTaskScheduler(((ScheduledExecutorService) scheduler)); - } - else { - throw new IllegalArgumentException("Unsupported scheduler type: " + scheduler.getClass()); - } - } - - /** - * Return the scheduler instance for this registrar (may be null) - */ - public TaskScheduler getScheduler() { - return this.taskScheduler; - } - - /** - * Specify triggered tasks as a Map of Runnables (the tasks) and Trigger objects - * (typically custom implementations of the {@link Trigger} interface). - */ - public void setTriggerTasks(Map triggerTasks) { - this.triggerTasks = triggerTasks; - } - - /** - * Specify triggered tasks as a Map of Runnables (the tasks) and cron expressions. - * @see CronTrigger - */ - public void setCronTasks(Map cronTasks) { - this.cronTasks = cronTasks; - } - - /** - * Specify triggered tasks as a Map of Runnables (the tasks) and fixed-rate values. - * @see TaskScheduler#scheduleAtFixedRate(Runnable, long) - */ - public void setFixedRateTasks(Map fixedRateTasks) { - this.fixedRateTasks = fixedRateTasks; - } - - /** - * Add a Runnable task to be triggered per the given {@link Trigger}. - * @see TaskScheduler#scheduleAtFixedRate(Runnable, long) - */ - public void addTriggerTask(Runnable task, Trigger trigger) { - if (this.triggerTasks == null) { - this.triggerTasks = new HashMap(); - } - this.triggerTasks.put(task, trigger); - } - - /** - * Add a Runnable task to be triggered per the given cron expression - */ - public void addCronTask(Runnable task, String cronExpression) { - if (this.cronTasks == null) { - this.cronTasks = new HashMap(); - } - this.cronTasks.put(task, cronExpression); - } - - /** - * Add a Runnable task to be triggered with the given fixed delay. - * @see TaskScheduler#scheduleWithFixedDelay(Runnable, long) - */ - public void addFixedDelayTask(Runnable task, long delay) { - if (this.fixedDelayTasks == null) { - this.fixedDelayTasks = new HashMap(); - } - this.fixedDelayTasks.put(task, delay); - } - - /** - * Add a Runnable task to be triggered at the given fixed-rate period. - * @see TaskScheduler#scheduleAtFixedRate(Runnable, long) - */ - public void addFixedRateTask(Runnable task, long period) { - if (this.fixedRateTasks == null) { - this.fixedRateTasks = new HashMap(); - } - this.fixedRateTasks.put(task, period); - } - - /** - * Specify triggered tasks as a Map of Runnables (the tasks) and fixed-delay values. - * @see TaskScheduler#scheduleWithFixedDelay(Runnable, long) - */ - public void setFixedDelayTasks(Map fixedDelayTasks) { - this.fixedDelayTasks = fixedDelayTasks; - } - - - public void afterPropertiesSet() { - if (this.taskScheduler == null) { - this.localExecutor = Executors.newSingleThreadScheduledExecutor(); - this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor); - } - if (this.triggerTasks != null) { - for (Map.Entry entry : this.triggerTasks.entrySet()) { - this.scheduledFutures.add(this.taskScheduler.schedule(entry.getKey(), entry.getValue())); - } - } - if (this.cronTasks != null) { - for (Map.Entry entry : this.cronTasks.entrySet()) { - this.scheduledFutures.add(this.taskScheduler.schedule(entry.getKey(), new CronTrigger(entry.getValue()))); - } - } - if (this.fixedRateTasks != null) { - for (Map.Entry entry : this.fixedRateTasks.entrySet()) { - this.scheduledFutures.add(this.taskScheduler.scheduleAtFixedRate(entry.getKey(), entry.getValue())); - } - } - if (this.fixedDelayTasks != null) { - for (Map.Entry entry : this.fixedDelayTasks.entrySet()) { - this.scheduledFutures.add(this.taskScheduler.scheduleWithFixedDelay(entry.getKey(), entry.getValue())); - } - } - } - - - public void destroy() { - for (ScheduledFuture future : this.scheduledFutures) { - future.cancel(true); - } - if (this.localExecutor != null) { - this.localExecutor.shutdownNow(); - } - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.config; + +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.Trigger; +import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler; +import org.springframework.scheduling.support.CronTrigger; +import org.springframework.util.Assert; + +/** + * Helper bean for registering tasks with a {@link TaskScheduler}, + * typically using cron expressions. + * + *

As of Spring 3.1, {@code ScheduledTaskRegistrar} has a more prominent user-facing + * role when used in conjunction with the @{@link + * org.springframework.scheduling.annotation.EnableAsync EnableAsync} annotation and its + * {@link org.springframework.scheduling.annotation.SchedulingConfigurer + * SchedulingConfigurer} callback interface. + * + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.scheduling.annotation.EnableAsync + * @see org.springframework.scheduling.annotation.SchedulingConfigurer + */ +public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean { + + private TaskScheduler taskScheduler; + + private ScheduledExecutorService localExecutor; + + private Map triggerTasks; + + private Map cronTasks; + + private Map fixedRateTasks; + + private Map fixedDelayTasks; + + private final Set> scheduledFutures = new LinkedHashSet>(); + + + /** + * Set the TaskScheduler to register scheduled tasks with. + */ + public void setTaskScheduler(TaskScheduler taskScheduler) { + Assert.notNull(taskScheduler, "TaskScheduler must not be null"); + this.taskScheduler = taskScheduler; + } + + /** + * Set the {@link org.springframework.scheduling.TaskScheduler} to register scheduled + * tasks with, or a {@link java.util.concurrent.ScheduledExecutorService} to be + * wrapped as a TaskScheduler. + */ + public void setScheduler(Object scheduler) { + Assert.notNull(scheduler, "Scheduler object must not be null"); + if (scheduler instanceof TaskScheduler) { + this.taskScheduler = (TaskScheduler) scheduler; + } + else if (scheduler instanceof ScheduledExecutorService) { + this.taskScheduler = new ConcurrentTaskScheduler(((ScheduledExecutorService) scheduler)); + } + else { + throw new IllegalArgumentException("Unsupported scheduler type: " + scheduler.getClass()); + } + } + + /** + * Return the scheduler instance for this registrar (may be null) + */ + public TaskScheduler getScheduler() { + return this.taskScheduler; + } + + /** + * Specify triggered tasks as a Map of Runnables (the tasks) and Trigger objects + * (typically custom implementations of the {@link Trigger} interface). + */ + public void setTriggerTasks(Map triggerTasks) { + this.triggerTasks = triggerTasks; + } + + /** + * Specify triggered tasks as a Map of Runnables (the tasks) and cron expressions. + * @see CronTrigger + */ + public void setCronTasks(Map cronTasks) { + this.cronTasks = cronTasks; + } + + /** + * Specify triggered tasks as a Map of Runnables (the tasks) and fixed-rate values. + * @see TaskScheduler#scheduleAtFixedRate(Runnable, long) + */ + public void setFixedRateTasks(Map fixedRateTasks) { + this.fixedRateTasks = fixedRateTasks; + } + + /** + * Add a Runnable task to be triggered per the given {@link Trigger}. + * @see TaskScheduler#scheduleAtFixedRate(Runnable, long) + */ + public void addTriggerTask(Runnable task, Trigger trigger) { + if (this.triggerTasks == null) { + this.triggerTasks = new HashMap(); + } + this.triggerTasks.put(task, trigger); + } + + /** + * Add a Runnable task to be triggered per the given cron expression + */ + public void addCronTask(Runnable task, String cronExpression) { + if (this.cronTasks == null) { + this.cronTasks = new HashMap(); + } + this.cronTasks.put(task, cronExpression); + } + + /** + * Add a Runnable task to be triggered with the given fixed delay. + * @see TaskScheduler#scheduleWithFixedDelay(Runnable, long) + */ + public void addFixedDelayTask(Runnable task, long delay) { + if (this.fixedDelayTasks == null) { + this.fixedDelayTasks = new HashMap(); + } + this.fixedDelayTasks.put(task, delay); + } + + /** + * Add a Runnable task to be triggered at the given fixed-rate period. + * @see TaskScheduler#scheduleAtFixedRate(Runnable, long) + */ + public void addFixedRateTask(Runnable task, long period) { + if (this.fixedRateTasks == null) { + this.fixedRateTasks = new HashMap(); + } + this.fixedRateTasks.put(task, period); + } + + /** + * Specify triggered tasks as a Map of Runnables (the tasks) and fixed-delay values. + * @see TaskScheduler#scheduleWithFixedDelay(Runnable, long) + */ + public void setFixedDelayTasks(Map fixedDelayTasks) { + this.fixedDelayTasks = fixedDelayTasks; + } + + + public void afterPropertiesSet() { + if (this.taskScheduler == null) { + this.localExecutor = Executors.newSingleThreadScheduledExecutor(); + this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor); + } + if (this.triggerTasks != null) { + for (Map.Entry entry : this.triggerTasks.entrySet()) { + this.scheduledFutures.add(this.taskScheduler.schedule(entry.getKey(), entry.getValue())); + } + } + if (this.cronTasks != null) { + for (Map.Entry entry : this.cronTasks.entrySet()) { + this.scheduledFutures.add(this.taskScheduler.schedule(entry.getKey(), new CronTrigger(entry.getValue()))); + } + } + if (this.fixedRateTasks != null) { + for (Map.Entry entry : this.fixedRateTasks.entrySet()) { + this.scheduledFutures.add(this.taskScheduler.scheduleAtFixedRate(entry.getKey(), entry.getValue())); + } + } + if (this.fixedDelayTasks != null) { + for (Map.Entry entry : this.fixedDelayTasks.entrySet()) { + this.scheduledFutures.add(this.taskScheduler.scheduleWithFixedDelay(entry.getKey(), entry.getValue())); + } + } + } + + + public void destroy() { + for (ScheduledFuture future : this.scheduledFutures) { + future.cancel(true); + } + if (this.localExecutor != null) { + this.localExecutor.shutdownNow(); + } + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/scheduling/config/package-info.java b/org.springframework.context/src/main/java/org/springframework/scheduling/config/package-info.java index 2ae10a2301..1f9cc08abe 100644 --- a/org.springframework.context/src/main/java/org/springframework/scheduling/config/package-info.java +++ b/org.springframework.context/src/main/java/org/springframework/scheduling/config/package-info.java @@ -1,9 +1,9 @@ - -/** - * - * Support package for declarative scheduling configuration, - * with XML schema being the primary configuration format. - * - */ -package org.springframework.scheduling.config; - + +/** + * + * Support package for declarative scheduling configuration, + * with XML schema being the primary configuration format. + * + */ +package org.springframework.scheduling.config; + diff --git a/org.springframework.context/src/main/java/org/springframework/scheduling/support/CronTrigger.java b/org.springframework.context/src/main/java/org/springframework/scheduling/support/CronTrigger.java index 2df21a3348..a3c8fc8df0 100644 --- a/org.springframework.context/src/main/java/org/springframework/scheduling/support/CronTrigger.java +++ b/org.springframework.context/src/main/java/org/springframework/scheduling/support/CronTrigger.java @@ -1,92 +1,92 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.scheduling.support; - -import java.util.Date; -import java.util.TimeZone; - -import org.springframework.scheduling.Trigger; -import org.springframework.scheduling.TriggerContext; - -/** - * {@link Trigger} implementation for cron expressions. - * Wraps a {@link CronSequenceGenerator}. - * - * @author Juergen Hoeller - * @since 3.0 - * @see CronSequenceGenerator - */ -public class CronTrigger implements Trigger { - - private final CronSequenceGenerator sequenceGenerator; - - - /** - * Build a {@link CronTrigger} from the pattern provided in the default time zone. - * @param cronExpression a space-separated list of time fields, - * following cron expression conventions - */ - public CronTrigger(String cronExpression) { - this(cronExpression, TimeZone.getDefault()); - } - - /** - * Build a {@link CronTrigger} from the pattern provided. - * @param cronExpression a space-separated list of time fields, - * following cron expression conventions - * @param timeZone a time zone in which the trigger times will be generated - */ - public CronTrigger(String cronExpression, TimeZone timeZone) { - this.sequenceGenerator = new CronSequenceGenerator(cronExpression, timeZone); - } - - - public Date nextExecutionTime(TriggerContext triggerContext) { - Date date = triggerContext.lastCompletionTime(); - if (date != null) { - Date scheduled = triggerContext.lastScheduledExecutionTime(); - if (scheduled != null && date.before(scheduled)) { - // Previous task apparently executed too early... - // Let's simply use the last calculated execution time then, - // in order to prevent accidental re-fires in the same second. - date = scheduled; - } - } - else { - date = new Date(); - } - return this.sequenceGenerator.next(date); - } - - - @Override - public boolean equals(Object obj) { - return (this == obj || (obj instanceof CronTrigger && - this.sequenceGenerator.equals(((CronTrigger) obj).sequenceGenerator))); - } - - @Override - public int hashCode() { - return this.sequenceGenerator.hashCode(); - } - - @Override - public String toString() { - return sequenceGenerator.toString(); - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling.support; + +import java.util.Date; +import java.util.TimeZone; + +import org.springframework.scheduling.Trigger; +import org.springframework.scheduling.TriggerContext; + +/** + * {@link Trigger} implementation for cron expressions. + * Wraps a {@link CronSequenceGenerator}. + * + * @author Juergen Hoeller + * @since 3.0 + * @see CronSequenceGenerator + */ +public class CronTrigger implements Trigger { + + private final CronSequenceGenerator sequenceGenerator; + + + /** + * Build a {@link CronTrigger} from the pattern provided in the default time zone. + * @param cronExpression a space-separated list of time fields, + * following cron expression conventions + */ + public CronTrigger(String cronExpression) { + this(cronExpression, TimeZone.getDefault()); + } + + /** + * Build a {@link CronTrigger} from the pattern provided. + * @param cronExpression a space-separated list of time fields, + * following cron expression conventions + * @param timeZone a time zone in which the trigger times will be generated + */ + public CronTrigger(String cronExpression, TimeZone timeZone) { + this.sequenceGenerator = new CronSequenceGenerator(cronExpression, timeZone); + } + + + public Date nextExecutionTime(TriggerContext triggerContext) { + Date date = triggerContext.lastCompletionTime(); + if (date != null) { + Date scheduled = triggerContext.lastScheduledExecutionTime(); + if (scheduled != null && date.before(scheduled)) { + // Previous task apparently executed too early... + // Let's simply use the last calculated execution time then, + // in order to prevent accidental re-fires in the same second. + date = scheduled; + } + } + else { + date = new Date(); + } + return this.sequenceGenerator.next(date); + } + + + @Override + public boolean equals(Object obj) { + return (this == obj || (obj instanceof CronTrigger && + this.sequenceGenerator.equals(((CronTrigger) obj).sequenceGenerator))); + } + + @Override + public int hashCode() { + return this.sequenceGenerator.hashCode(); + } + + @Override + public String toString() { + return sequenceGenerator.toString(); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/scheduling/support/ScheduledMethodRunnable.java b/org.springframework.context/src/main/java/org/springframework/scheduling/support/ScheduledMethodRunnable.java index 207a717a05..5b7b9350fb 100644 --- a/org.springframework.context/src/main/java/org/springframework/scheduling/support/ScheduledMethodRunnable.java +++ b/org.springframework.context/src/main/java/org/springframework/scheduling/support/ScheduledMethodRunnable.java @@ -1,74 +1,74 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.support; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.UndeclaredThrowableException; - -import org.springframework.util.ReflectionUtils; - -/** - * Variant of {@link MethodInvokingRunnable} meant to be used for processing - * of no-arg scheduled methods. Propagates user exceptions to the caller, - * assuming that an error strategy for Runnables is in place. - * - * @author Juergen Hoeller - * @since 3.0.6 - * @see org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor - */ -public class ScheduledMethodRunnable implements Runnable { - - private final Object target; - - private final Method method; - - - public ScheduledMethodRunnable(Object target, Method method) { - this.target = target; - this.method = method; - } - - public ScheduledMethodRunnable(Object target, String methodName) throws NoSuchMethodException { - this.target = target; - this.method = target.getClass().getMethod(methodName); - } - - - public Object getTarget() { - return this.target; - } - - public Method getMethod() { - return this.method; - } - - - public void run() { - try { - ReflectionUtils.makeAccessible(this.method); - this.method.invoke(this.target); - } - catch (InvocationTargetException ex) { - ReflectionUtils.rethrowRuntimeException(ex.getTargetException()); - } - catch (IllegalAccessException ex) { - throw new UndeclaredThrowableException(ex); - } - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.support; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.UndeclaredThrowableException; + +import org.springframework.util.ReflectionUtils; + +/** + * Variant of {@link MethodInvokingRunnable} meant to be used for processing + * of no-arg scheduled methods. Propagates user exceptions to the caller, + * assuming that an error strategy for Runnables is in place. + * + * @author Juergen Hoeller + * @since 3.0.6 + * @see org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor + */ +public class ScheduledMethodRunnable implements Runnable { + + private final Object target; + + private final Method method; + + + public ScheduledMethodRunnable(Object target, Method method) { + this.target = target; + this.method = method; + } + + public ScheduledMethodRunnable(Object target, String methodName) throws NoSuchMethodException { + this.target = target; + this.method = target.getClass().getMethod(methodName); + } + + + public Object getTarget() { + return this.target; + } + + public Method getMethod() { + return this.method; + } + + + public void run() { + try { + ReflectionUtils.makeAccessible(this.method); + this.method.invoke(this.target); + } + catch (InvocationTargetException ex) { + ReflectionUtils.rethrowRuntimeException(ex.getTargetException()); + } + catch (IllegalAccessException ex) { + throw new UndeclaredThrowableException(ex); + } + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/scheduling/support/SimpleTriggerContext.java b/org.springframework.context/src/main/java/org/springframework/scheduling/support/SimpleTriggerContext.java index 5933bdf4ee..650d95ea73 100644 --- a/org.springframework.context/src/main/java/org/springframework/scheduling/support/SimpleTriggerContext.java +++ b/org.springframework.context/src/main/java/org/springframework/scheduling/support/SimpleTriggerContext.java @@ -1,63 +1,63 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.scheduling.support; - -import java.util.Date; - -import org.springframework.scheduling.TriggerContext; - -/** - * Simple data holder implementation of the {@link TriggerContext} interface. - * - * @author Juergen Hoeller - * @since 3.0 - */ -public class SimpleTriggerContext implements TriggerContext { - - private volatile Date lastScheduledExecutionTime; - - private volatile Date lastActualExecutionTime; - - private volatile Date lastCompletionTime; - - - /** - * Update this holder's state with the latest time values. - * @param lastScheduledExecutionTime last scheduled execution time - * @param lastActualExecutionTime last actual execution time - * @param lastCompletionTime last completion time - */ - public void update(Date lastScheduledExecutionTime, Date lastActualExecutionTime, Date lastCompletionTime) { - this.lastScheduledExecutionTime = lastScheduledExecutionTime; - this.lastActualExecutionTime = lastActualExecutionTime; - this.lastCompletionTime = lastCompletionTime; - } - - - public Date lastScheduledExecutionTime() { - return this.lastScheduledExecutionTime; - } - - public Date lastActualExecutionTime() { - return this.lastActualExecutionTime; - } - - public Date lastCompletionTime() { - return this.lastCompletionTime; - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling.support; + +import java.util.Date; + +import org.springframework.scheduling.TriggerContext; + +/** + * Simple data holder implementation of the {@link TriggerContext} interface. + * + * @author Juergen Hoeller + * @since 3.0 + */ +public class SimpleTriggerContext implements TriggerContext { + + private volatile Date lastScheduledExecutionTime; + + private volatile Date lastActualExecutionTime; + + private volatile Date lastCompletionTime; + + + /** + * Update this holder's state with the latest time values. + * @param lastScheduledExecutionTime last scheduled execution time + * @param lastActualExecutionTime last actual execution time + * @param lastCompletionTime last completion time + */ + public void update(Date lastScheduledExecutionTime, Date lastActualExecutionTime, Date lastCompletionTime) { + this.lastScheduledExecutionTime = lastScheduledExecutionTime; + this.lastActualExecutionTime = lastActualExecutionTime; + this.lastCompletionTime = lastCompletionTime; + } + + + public Date lastScheduledExecutionTime() { + return this.lastScheduledExecutionTime; + } + + public Date lastActualExecutionTime() { + return this.lastActualExecutionTime; + } + + public Date lastCompletionTime() { + return this.lastCompletionTime; + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/validation/annotation/package-info.java b/org.springframework.context/src/main/java/org/springframework/validation/annotation/package-info.java index f13f798131..2283a3bba6 100644 --- a/org.springframework.context/src/main/java/org/springframework/validation/annotation/package-info.java +++ b/org.springframework.context/src/main/java/org/springframework/validation/annotation/package-info.java @@ -1,8 +1,8 @@ -/** - * Support classes for annotation-based constraint evaluation, - * e.g. using a JSR-303 Bean Validation provider. - * - *

Provides an extended variant of JSR-303's @Valid, - * supporting the specification of validation groups. - */ -package org.springframework.validation.annotation; +/** + * Support classes for annotation-based constraint evaluation, + * e.g. using a JSR-303 Bean Validation provider. + * + *

Provides an extended variant of JSR-303's @Valid, + * supporting the specification of validation groups. + */ +package org.springframework.validation.annotation; diff --git a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/BeanValidationPostProcessor.java b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/BeanValidationPostProcessor.java index 3edc4581a4..899207cb5a 100644 --- a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/BeanValidationPostProcessor.java +++ b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/BeanValidationPostProcessor.java @@ -1,117 +1,117 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.validation.beanvalidation; - -import java.util.Iterator; -import java.util.Set; -import javax.validation.ConstraintViolation; -import javax.validation.Validation; -import javax.validation.Validator; -import javax.validation.ValidatorFactory; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanInitializationException; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.config.BeanPostProcessor; - -/** - * Simple {@link BeanPostProcessor} that checks JSR-303 constraint annotations - * in Spring-managed beans, throwing an initialization exception in case of - * constraint violations right before calling the bean's init method (if any). - * - * @author Juergen Hoeller - * @since 3.0 - */ -public class BeanValidationPostProcessor implements BeanPostProcessor, InitializingBean { - - private Validator validator; - - private boolean afterInitialization = false; - - - /** - * Set the JSR-303 Validator to delegate to for validating beans. - *

Default is the default ValidatorFactory's default Validator. - */ - public void setValidator(Validator validator) { - this.validator = validator; - } - - /** - * Set the JSR-303 ValidatorFactory to delegate to for validating beans, - * using its default Validator. - *

Default is the default ValidatorFactory's default Validator. - * @see javax.validation.ValidatorFactory#getValidator() - */ - public void setValidatorFactory(ValidatorFactory validatorFactory) { - this.validator = validatorFactory.getValidator(); - } - - /** - * Choose whether to perform validation after bean initialization - * (i.e. after init methods) instead of before (which is the default). - *

Default is "false" (before initialization). Switch this to "true" - * (after initialization) if you would like to give init methods a chance - * to populate constrained fields before they get validated. - */ - public void setAfterInitialization(boolean afterInitialization) { - this.afterInitialization = afterInitialization; - } - - public void afterPropertiesSet() { - if (this.validator == null) { - this.validator = Validation.buildDefaultValidatorFactory().getValidator(); - } - } - - - public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - if (!this.afterInitialization) { - doValidate(bean); - } - return bean; - } - - public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { - if (this.afterInitialization) { - doValidate(bean); - } - return bean; - } - - - /** - * Perform validation of the given bean. - * @param bean the bean instance to validate - * @see javax.validation.Validator#validate - */ - protected void doValidate(Object bean) { - Set> result = this.validator.validate(bean); - if (!result.isEmpty()) { - StringBuilder sb = new StringBuilder("Bean state is invalid: "); - for (Iterator> it = result.iterator(); it.hasNext();) { - ConstraintViolation violation = it.next(); - sb.append(violation.getPropertyPath()).append(" - ").append(violation.getMessage()); - if (it.hasNext()) { - sb.append("; "); - } - } - throw new BeanInitializationException(sb.toString()); - } - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.validation.beanvalidation; + +import java.util.Iterator; +import java.util.Set; +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanInitializationException; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.config.BeanPostProcessor; + +/** + * Simple {@link BeanPostProcessor} that checks JSR-303 constraint annotations + * in Spring-managed beans, throwing an initialization exception in case of + * constraint violations right before calling the bean's init method (if any). + * + * @author Juergen Hoeller + * @since 3.0 + */ +public class BeanValidationPostProcessor implements BeanPostProcessor, InitializingBean { + + private Validator validator; + + private boolean afterInitialization = false; + + + /** + * Set the JSR-303 Validator to delegate to for validating beans. + *

Default is the default ValidatorFactory's default Validator. + */ + public void setValidator(Validator validator) { + this.validator = validator; + } + + /** + * Set the JSR-303 ValidatorFactory to delegate to for validating beans, + * using its default Validator. + *

Default is the default ValidatorFactory's default Validator. + * @see javax.validation.ValidatorFactory#getValidator() + */ + public void setValidatorFactory(ValidatorFactory validatorFactory) { + this.validator = validatorFactory.getValidator(); + } + + /** + * Choose whether to perform validation after bean initialization + * (i.e. after init methods) instead of before (which is the default). + *

Default is "false" (before initialization). Switch this to "true" + * (after initialization) if you would like to give init methods a chance + * to populate constrained fields before they get validated. + */ + public void setAfterInitialization(boolean afterInitialization) { + this.afterInitialization = afterInitialization; + } + + public void afterPropertiesSet() { + if (this.validator == null) { + this.validator = Validation.buildDefaultValidatorFactory().getValidator(); + } + } + + + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + if (!this.afterInitialization) { + doValidate(bean); + } + return bean; + } + + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + if (this.afterInitialization) { + doValidate(bean); + } + return bean; + } + + + /** + * Perform validation of the given bean. + * @param bean the bean instance to validate + * @see javax.validation.Validator#validate + */ + protected void doValidate(Object bean) { + Set> result = this.validator.validate(bean); + if (!result.isEmpty()) { + StringBuilder sb = new StringBuilder("Bean state is invalid: "); + for (Iterator> it = result.iterator(); it.hasNext();) { + ConstraintViolation violation = it.next(); + sb.append(violation.getPropertyPath()).append(" - ").append(violation.getMessage()); + if (it.hasNext()) { + sb.append("; "); + } + } + throw new BeanInitializationException(sb.toString()); + } + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/CustomValidatorBean.java b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/CustomValidatorBean.java index bde13ced82..2001e78aee 100644 --- a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/CustomValidatorBean.java +++ b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/CustomValidatorBean.java @@ -1,86 +1,86 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.validation.beanvalidation; - -import javax.validation.MessageInterpolator; -import javax.validation.TraversableResolver; -import javax.validation.Validation; -import javax.validation.Validator; -import javax.validation.ValidatorContext; -import javax.validation.ValidatorFactory; - -import org.springframework.beans.factory.InitializingBean; - -/** - * Configurable bean class that exposes a specific JSR-303 Validator - * through its original interface as well as through the Spring - * {@link org.springframework.validation.Validator} interface. - * - * @author Juergen Hoeller - * @since 3.0 - */ -public class CustomValidatorBean extends SpringValidatorAdapter implements Validator, InitializingBean { - - private ValidatorFactory validatorFactory; - - private MessageInterpolator messageInterpolator; - - private TraversableResolver traversableResolver; - - - /** - * Set the ValidatorFactory to obtain the target Validator from. - *

Default is {@link javax.validation.Validation#buildDefaultValidatorFactory()}. - */ - public void setValidatorFactory(ValidatorFactory validatorFactory) { - this.validatorFactory = validatorFactory; - } - - /** - * Specify a custom MessageInterpolator to use for this Validator. - */ - public void setMessageInterpolator(MessageInterpolator messageInterpolator) { - this.messageInterpolator = messageInterpolator; - } - - /** - * Specify a custom TraversableResolver to use for this Validator. - */ - public void setTraversableResolver(TraversableResolver traversableResolver) { - this.traversableResolver = traversableResolver; - } - - - public void afterPropertiesSet() { - if (this.validatorFactory == null) { - this.validatorFactory = Validation.buildDefaultValidatorFactory(); - } - - ValidatorContext validatorContext = this.validatorFactory.usingContext(); - MessageInterpolator targetInterpolator = this.messageInterpolator; - if (targetInterpolator == null) { - targetInterpolator = this.validatorFactory.getMessageInterpolator(); - } - validatorContext.messageInterpolator(new LocaleContextMessageInterpolator(targetInterpolator)); - if (this.traversableResolver != null) { - validatorContext.traversableResolver(this.traversableResolver); - } - - setTargetValidator(validatorContext.getValidator()); - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.validation.beanvalidation; + +import javax.validation.MessageInterpolator; +import javax.validation.TraversableResolver; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorContext; +import javax.validation.ValidatorFactory; + +import org.springframework.beans.factory.InitializingBean; + +/** + * Configurable bean class that exposes a specific JSR-303 Validator + * through its original interface as well as through the Spring + * {@link org.springframework.validation.Validator} interface. + * + * @author Juergen Hoeller + * @since 3.0 + */ +public class CustomValidatorBean extends SpringValidatorAdapter implements Validator, InitializingBean { + + private ValidatorFactory validatorFactory; + + private MessageInterpolator messageInterpolator; + + private TraversableResolver traversableResolver; + + + /** + * Set the ValidatorFactory to obtain the target Validator from. + *

Default is {@link javax.validation.Validation#buildDefaultValidatorFactory()}. + */ + public void setValidatorFactory(ValidatorFactory validatorFactory) { + this.validatorFactory = validatorFactory; + } + + /** + * Specify a custom MessageInterpolator to use for this Validator. + */ + public void setMessageInterpolator(MessageInterpolator messageInterpolator) { + this.messageInterpolator = messageInterpolator; + } + + /** + * Specify a custom TraversableResolver to use for this Validator. + */ + public void setTraversableResolver(TraversableResolver traversableResolver) { + this.traversableResolver = traversableResolver; + } + + + public void afterPropertiesSet() { + if (this.validatorFactory == null) { + this.validatorFactory = Validation.buildDefaultValidatorFactory(); + } + + ValidatorContext validatorContext = this.validatorFactory.usingContext(); + MessageInterpolator targetInterpolator = this.messageInterpolator; + if (targetInterpolator == null) { + targetInterpolator = this.validatorFactory.getMessageInterpolator(); + } + validatorContext.messageInterpolator(new LocaleContextMessageInterpolator(targetInterpolator)); + if (this.traversableResolver != null) { + validatorContext.traversableResolver(this.traversableResolver); + } + + setTargetValidator(validatorContext.getValidator()); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.java b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.java index de9f3655af..bc3bc6b2d1 100644 --- a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.java +++ b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.java @@ -1,257 +1,257 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.validation.beanvalidation; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; -import javax.validation.Configuration; -import javax.validation.ConstraintValidatorFactory; -import javax.validation.MessageInterpolator; -import javax.validation.TraversableResolver; -import javax.validation.Validation; -import javax.validation.Validator; -import javax.validation.ValidatorContext; -import javax.validation.ValidatorFactory; -import javax.validation.spi.ValidationProvider; - -import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator; - -import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.MessageSource; -import org.springframework.core.io.Resource; -import org.springframework.util.CollectionUtils; - -/** - * This is the central class for javax.validation (JSR-303) setup - * in a Spring application context: It bootstraps a javax.validation.ValidationFactory - * and exposes it through the Spring {@link org.springframework.validation.Validator} interface - * as well as through the JSR-303 {@link javax.validation.Validator} interface and the - * {@link javax.validation.ValidatorFactory} interface itself. - * - *

When talking to an instance of this bean through the Spring or JSR-303 Validator interfaces, - * you'll be talking to the default Validator of the underlying ValidatorFactory. This is very - * convenient in that you don't have to perform yet another call on the factory, assuming that - * you will almost always use the default Validator anyway. This can also be injected directly - * into any target dependency of type {@link org.springframework.validation.Validator}! - * - * @author Juergen Hoeller - * @since 3.0 - * @see javax.validation.ValidatorFactory - * @see javax.validation.Validator - * @see javax.validation.Validation#buildDefaultValidatorFactory() - * @see javax.validation.ValidatorFactory#getValidator() - */ -public class LocalValidatorFactoryBean extends SpringValidatorAdapter - implements ValidatorFactory, ApplicationContextAware, InitializingBean { - - @SuppressWarnings("rawtypes") - private Class providerClass; - - private MessageInterpolator messageInterpolator; - - private TraversableResolver traversableResolver; - - private ConstraintValidatorFactory constraintValidatorFactory; - - private Resource[] mappingLocations; - - private final Map validationPropertyMap = new HashMap(); - - private ApplicationContext applicationContext; - - private ValidatorFactory validatorFactory; - - - /** - * Specify the desired provider class, if any. - *

If not specified, JSR-303's default search mechanism will be used. - * @see javax.validation.Validation#byProvider(Class) - * @see javax.validation.Validation#byDefaultProvider() - */ - @SuppressWarnings("rawtypes") - public void setProviderClass(Class providerClass) { - this.providerClass = providerClass; - } - - /** - * Specify a custom MessageInterpolator to use for this ValidatorFactory - * and its exposed default Validator. - */ - public void setMessageInterpolator(MessageInterpolator messageInterpolator) { - this.messageInterpolator = messageInterpolator; - } - - /** - * Specify a custom Spring MessageSource for resolving validation messages, - * instead of relying on JSR-303's default "ValidationMessages.properties" bundle - * in the classpath. This may refer to a Spring context's shared "messageSource" bean, - * or to some special MessageSource setup for validation purposes only. - *

NOTE: This feature requires Hibernate Validator 4.1 or higher on the classpath. - * You may nevertheless use a different validation provider but Hibernate Validator's - * {@link ResourceBundleMessageInterpolator} class must be accessible during configuration. - *

Specify either this property or {@link #setMessageInterpolator "messageInterpolator"}, - * not both. If you would like to build a custom MessageInterpolator, consider deriving from - * Hibernate Validator's {@link ResourceBundleMessageInterpolator} and passing in a - * Spring {@link MessageSourceResourceBundleLocator} when constructing your interpolator. - * @see ResourceBundleMessageInterpolator - * @see MessageSourceResourceBundleLocator - */ - public void setValidationMessageSource(MessageSource messageSource) { - this.messageInterpolator = HibernateValidatorDelegate.buildMessageInterpolator(messageSource); - } - - /** - * Specify a custom TraversableResolver to use for this ValidatorFactory - * and its exposed default Validator. - */ - public void setTraversableResolver(TraversableResolver traversableResolver) { - this.traversableResolver = traversableResolver; - } - - /** - * Specify a custom ConstraintValidatorFactory to use for this ValidatorFactory. - *

Default is a {@link SpringConstraintValidatorFactory}, delegating to the - * containing ApplicationContext for creating autowired ConstraintValidator instances. - */ - public void setConstraintValidatorFactory(ConstraintValidatorFactory constraintValidatorFactory) { - this.constraintValidatorFactory = constraintValidatorFactory; - } - - /** - * Specify resource locations to load XML constraint mapping files from, if any. - */ - public void setMappingLocations(Resource[] mappingLocations) { - this.mappingLocations = mappingLocations; - } - - /** - * Specify bean validation properties to be passed to the validation provider. - *

Can be populated with a String "value" (parsed via PropertiesEditor) - * or a "props" element in XML bean definitions. - * @see javax.validation.Configuration#addProperty(String, String) - */ - public void setValidationProperties(Properties jpaProperties) { - CollectionUtils.mergePropertiesIntoMap(jpaProperties, this.validationPropertyMap); - } - - /** - * Specify bean validation properties to be passed to the validation provider as a Map. - *

Can be populated with a "map" or "props" element in XML bean definitions. - * @see javax.validation.Configuration#addProperty(String, String) - */ - public void setValidationPropertyMap(Map validationProperties) { - if (validationProperties != null) { - this.validationPropertyMap.putAll(validationProperties); - } - } - - /** - * Allow Map access to the bean validation properties to be passed to the validation provider, - * with the option to add or override specific entries. - *

Useful for specifying entries directly, for example via "validationPropertyMap[myKey]". - */ - public Map getValidationPropertyMap() { - return this.validationPropertyMap; - } - - public void setApplicationContext(ApplicationContext applicationContext) { - this.applicationContext = applicationContext; - } - - - @SuppressWarnings("unchecked") - public void afterPropertiesSet() { - @SuppressWarnings("rawtypes") - Configuration configuration = (this.providerClass != null ? - Validation.byProvider(this.providerClass).configure() : - Validation.byDefaultProvider().configure()); - - MessageInterpolator targetInterpolator = this.messageInterpolator; - if (targetInterpolator == null) { - targetInterpolator = configuration.getDefaultMessageInterpolator(); - } - configuration.messageInterpolator(new LocaleContextMessageInterpolator(targetInterpolator)); - - if (this.traversableResolver != null) { - configuration.traversableResolver(this.traversableResolver); - } - - ConstraintValidatorFactory targetConstraintValidatorFactory = this.constraintValidatorFactory; - if (targetConstraintValidatorFactory == null && this.applicationContext != null) { - targetConstraintValidatorFactory = - new SpringConstraintValidatorFactory(this.applicationContext.getAutowireCapableBeanFactory()); - } - if (targetConstraintValidatorFactory != null) { - configuration.constraintValidatorFactory(targetConstraintValidatorFactory); - } - - if (this.mappingLocations != null) { - for (Resource location : this.mappingLocations) { - try { - configuration.addMapping(location.getInputStream()); - } - catch (IOException ex) { - throw new IllegalStateException("Cannot read mapping resource: " + location); - } - } - } - - for (Map.Entry entry : this.validationPropertyMap.entrySet()) { - configuration.addProperty(entry.getKey(), entry.getValue()); - } - - this.validatorFactory = configuration.buildValidatorFactory(); - setTargetValidator(this.validatorFactory.getValidator()); - } - - - public Validator getValidator() { - return this.validatorFactory.getValidator(); - } - - public ValidatorContext usingContext() { - return this.validatorFactory.usingContext(); - } - - public MessageInterpolator getMessageInterpolator() { - return this.validatorFactory.getMessageInterpolator(); - } - - public TraversableResolver getTraversableResolver() { - return this.validatorFactory.getTraversableResolver(); - } - - public ConstraintValidatorFactory getConstraintValidatorFactory() { - return this.validatorFactory.getConstraintValidatorFactory(); - } - - - /** - * Inner class to avoid a hard-coded Hibernate Validator 4.1 dependency. - */ - private static class HibernateValidatorDelegate { - - public static MessageInterpolator buildMessageInterpolator(MessageSource messageSource) { - return new ResourceBundleMessageInterpolator(new MessageSourceResourceBundleLocator(messageSource)); - } - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.validation.beanvalidation; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import javax.validation.Configuration; +import javax.validation.ConstraintValidatorFactory; +import javax.validation.MessageInterpolator; +import javax.validation.TraversableResolver; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorContext; +import javax.validation.ValidatorFactory; +import javax.validation.spi.ValidationProvider; + +import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.MessageSource; +import org.springframework.core.io.Resource; +import org.springframework.util.CollectionUtils; + +/** + * This is the central class for javax.validation (JSR-303) setup + * in a Spring application context: It bootstraps a javax.validation.ValidationFactory + * and exposes it through the Spring {@link org.springframework.validation.Validator} interface + * as well as through the JSR-303 {@link javax.validation.Validator} interface and the + * {@link javax.validation.ValidatorFactory} interface itself. + * + *

When talking to an instance of this bean through the Spring or JSR-303 Validator interfaces, + * you'll be talking to the default Validator of the underlying ValidatorFactory. This is very + * convenient in that you don't have to perform yet another call on the factory, assuming that + * you will almost always use the default Validator anyway. This can also be injected directly + * into any target dependency of type {@link org.springframework.validation.Validator}! + * + * @author Juergen Hoeller + * @since 3.0 + * @see javax.validation.ValidatorFactory + * @see javax.validation.Validator + * @see javax.validation.Validation#buildDefaultValidatorFactory() + * @see javax.validation.ValidatorFactory#getValidator() + */ +public class LocalValidatorFactoryBean extends SpringValidatorAdapter + implements ValidatorFactory, ApplicationContextAware, InitializingBean { + + @SuppressWarnings("rawtypes") + private Class providerClass; + + private MessageInterpolator messageInterpolator; + + private TraversableResolver traversableResolver; + + private ConstraintValidatorFactory constraintValidatorFactory; + + private Resource[] mappingLocations; + + private final Map validationPropertyMap = new HashMap(); + + private ApplicationContext applicationContext; + + private ValidatorFactory validatorFactory; + + + /** + * Specify the desired provider class, if any. + *

If not specified, JSR-303's default search mechanism will be used. + * @see javax.validation.Validation#byProvider(Class) + * @see javax.validation.Validation#byDefaultProvider() + */ + @SuppressWarnings("rawtypes") + public void setProviderClass(Class providerClass) { + this.providerClass = providerClass; + } + + /** + * Specify a custom MessageInterpolator to use for this ValidatorFactory + * and its exposed default Validator. + */ + public void setMessageInterpolator(MessageInterpolator messageInterpolator) { + this.messageInterpolator = messageInterpolator; + } + + /** + * Specify a custom Spring MessageSource for resolving validation messages, + * instead of relying on JSR-303's default "ValidationMessages.properties" bundle + * in the classpath. This may refer to a Spring context's shared "messageSource" bean, + * or to some special MessageSource setup for validation purposes only. + *

NOTE: This feature requires Hibernate Validator 4.1 or higher on the classpath. + * You may nevertheless use a different validation provider but Hibernate Validator's + * {@link ResourceBundleMessageInterpolator} class must be accessible during configuration. + *

Specify either this property or {@link #setMessageInterpolator "messageInterpolator"}, + * not both. If you would like to build a custom MessageInterpolator, consider deriving from + * Hibernate Validator's {@link ResourceBundleMessageInterpolator} and passing in a + * Spring {@link MessageSourceResourceBundleLocator} when constructing your interpolator. + * @see ResourceBundleMessageInterpolator + * @see MessageSourceResourceBundleLocator + */ + public void setValidationMessageSource(MessageSource messageSource) { + this.messageInterpolator = HibernateValidatorDelegate.buildMessageInterpolator(messageSource); + } + + /** + * Specify a custom TraversableResolver to use for this ValidatorFactory + * and its exposed default Validator. + */ + public void setTraversableResolver(TraversableResolver traversableResolver) { + this.traversableResolver = traversableResolver; + } + + /** + * Specify a custom ConstraintValidatorFactory to use for this ValidatorFactory. + *

Default is a {@link SpringConstraintValidatorFactory}, delegating to the + * containing ApplicationContext for creating autowired ConstraintValidator instances. + */ + public void setConstraintValidatorFactory(ConstraintValidatorFactory constraintValidatorFactory) { + this.constraintValidatorFactory = constraintValidatorFactory; + } + + /** + * Specify resource locations to load XML constraint mapping files from, if any. + */ + public void setMappingLocations(Resource[] mappingLocations) { + this.mappingLocations = mappingLocations; + } + + /** + * Specify bean validation properties to be passed to the validation provider. + *

Can be populated with a String "value" (parsed via PropertiesEditor) + * or a "props" element in XML bean definitions. + * @see javax.validation.Configuration#addProperty(String, String) + */ + public void setValidationProperties(Properties jpaProperties) { + CollectionUtils.mergePropertiesIntoMap(jpaProperties, this.validationPropertyMap); + } + + /** + * Specify bean validation properties to be passed to the validation provider as a Map. + *

Can be populated with a "map" or "props" element in XML bean definitions. + * @see javax.validation.Configuration#addProperty(String, String) + */ + public void setValidationPropertyMap(Map validationProperties) { + if (validationProperties != null) { + this.validationPropertyMap.putAll(validationProperties); + } + } + + /** + * Allow Map access to the bean validation properties to be passed to the validation provider, + * with the option to add or override specific entries. + *

Useful for specifying entries directly, for example via "validationPropertyMap[myKey]". + */ + public Map getValidationPropertyMap() { + return this.validationPropertyMap; + } + + public void setApplicationContext(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + + @SuppressWarnings("unchecked") + public void afterPropertiesSet() { + @SuppressWarnings("rawtypes") + Configuration configuration = (this.providerClass != null ? + Validation.byProvider(this.providerClass).configure() : + Validation.byDefaultProvider().configure()); + + MessageInterpolator targetInterpolator = this.messageInterpolator; + if (targetInterpolator == null) { + targetInterpolator = configuration.getDefaultMessageInterpolator(); + } + configuration.messageInterpolator(new LocaleContextMessageInterpolator(targetInterpolator)); + + if (this.traversableResolver != null) { + configuration.traversableResolver(this.traversableResolver); + } + + ConstraintValidatorFactory targetConstraintValidatorFactory = this.constraintValidatorFactory; + if (targetConstraintValidatorFactory == null && this.applicationContext != null) { + targetConstraintValidatorFactory = + new SpringConstraintValidatorFactory(this.applicationContext.getAutowireCapableBeanFactory()); + } + if (targetConstraintValidatorFactory != null) { + configuration.constraintValidatorFactory(targetConstraintValidatorFactory); + } + + if (this.mappingLocations != null) { + for (Resource location : this.mappingLocations) { + try { + configuration.addMapping(location.getInputStream()); + } + catch (IOException ex) { + throw new IllegalStateException("Cannot read mapping resource: " + location); + } + } + } + + for (Map.Entry entry : this.validationPropertyMap.entrySet()) { + configuration.addProperty(entry.getKey(), entry.getValue()); + } + + this.validatorFactory = configuration.buildValidatorFactory(); + setTargetValidator(this.validatorFactory.getValidator()); + } + + + public Validator getValidator() { + return this.validatorFactory.getValidator(); + } + + public ValidatorContext usingContext() { + return this.validatorFactory.usingContext(); + } + + public MessageInterpolator getMessageInterpolator() { + return this.validatorFactory.getMessageInterpolator(); + } + + public TraversableResolver getTraversableResolver() { + return this.validatorFactory.getTraversableResolver(); + } + + public ConstraintValidatorFactory getConstraintValidatorFactory() { + return this.validatorFactory.getConstraintValidatorFactory(); + } + + + /** + * Inner class to avoid a hard-coded Hibernate Validator 4.1 dependency. + */ + private static class HibernateValidatorDelegate { + + public static MessageInterpolator buildMessageInterpolator(MessageSource messageSource) { + return new ResourceBundleMessageInterpolator(new MessageSourceResourceBundleLocator(messageSource)); + } + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/LocaleContextMessageInterpolator.java b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/LocaleContextMessageInterpolator.java index 1bab6a4aa7..06c897fc16 100644 --- a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/LocaleContextMessageInterpolator.java +++ b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/LocaleContextMessageInterpolator.java @@ -1,56 +1,56 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.validation.beanvalidation; - -import java.util.Locale; -import javax.validation.MessageInterpolator; - -import org.springframework.context.i18n.LocaleContextHolder; -import org.springframework.util.Assert; - -/** - * Delegates to a target {@link MessageInterpolator} implementation but enforces Spring's - * managed Locale. Typically used to wrap the validation provider's default interpolator. - * - * @author Juergen Hoeller - * @since 3.0 - * @see org.springframework.context.i18n.LocaleContextHolder#getLocale() - */ -public class LocaleContextMessageInterpolator implements MessageInterpolator { - - private final MessageInterpolator targetInterpolator; - - - /** - * Create a new LocaleContextMessageInterpolator, wrapping the given target interpolator. - * @param targetInterpolator the target MessageInterpolator to wrap - */ - public LocaleContextMessageInterpolator(MessageInterpolator targetInterpolator) { - Assert.notNull(targetInterpolator, "Target MessageInterpolator must not be null"); - this.targetInterpolator = targetInterpolator; - } - - - public String interpolate(String message, Context context) { - return this.targetInterpolator.interpolate(message, context, LocaleContextHolder.getLocale()); - } - - public String interpolate(String message, Context context, Locale locale) { - return this.targetInterpolator.interpolate(message, context, locale); - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.validation.beanvalidation; + +import java.util.Locale; +import javax.validation.MessageInterpolator; + +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.util.Assert; + +/** + * Delegates to a target {@link MessageInterpolator} implementation but enforces Spring's + * managed Locale. Typically used to wrap the validation provider's default interpolator. + * + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.context.i18n.LocaleContextHolder#getLocale() + */ +public class LocaleContextMessageInterpolator implements MessageInterpolator { + + private final MessageInterpolator targetInterpolator; + + + /** + * Create a new LocaleContextMessageInterpolator, wrapping the given target interpolator. + * @param targetInterpolator the target MessageInterpolator to wrap + */ + public LocaleContextMessageInterpolator(MessageInterpolator targetInterpolator) { + Assert.notNull(targetInterpolator, "Target MessageInterpolator must not be null"); + this.targetInterpolator = targetInterpolator; + } + + + public String interpolate(String message, Context context) { + return this.targetInterpolator.interpolate(message, context, LocaleContextHolder.getLocale()); + } + + public String interpolate(String message, Context context, Locale locale) { + return this.targetInterpolator.interpolate(message, context, locale); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/MessageSourceResourceBundleLocator.java b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/MessageSourceResourceBundleLocator.java index cf9177c9ed..83c538e38c 100644 --- a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/MessageSourceResourceBundleLocator.java +++ b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/MessageSourceResourceBundleLocator.java @@ -1,55 +1,55 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.validation.beanvalidation; - -import java.util.Locale; -import java.util.ResourceBundle; - -import org.hibernate.validator.resourceloading.ResourceBundleLocator; - -import org.springframework.context.MessageSource; -import org.springframework.context.support.MessageSourceResourceBundle; -import org.springframework.util.Assert; - -/** - * Implementation of Hibernate Validator 4.1's {@link ResourceBundleLocator} interface, - * exposing a Spring {@link MessageSource} as localized {@link MessageSourceResourceBundle}. - * - * @author Juergen Hoeller - * @since 3.0.4 - * @see ResourceBundleLocator - * @see MessageSource - * @see MessageSourceResourceBundle - */ -public class MessageSourceResourceBundleLocator implements ResourceBundleLocator { - - private final MessageSource messageSource; - - /** - * Build a MessageSourceResourceBundleLocator for the given MessageSource. - * @param messageSource the Spring MessageSource to wrap - */ - public MessageSourceResourceBundleLocator(MessageSource messageSource) { - Assert.notNull(messageSource, "MessageSource must not be null"); - this.messageSource = messageSource; - } - - public ResourceBundle getResourceBundle(Locale locale) { - return new MessageSourceResourceBundle(this.messageSource, locale); - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.validation.beanvalidation; + +import java.util.Locale; +import java.util.ResourceBundle; + +import org.hibernate.validator.resourceloading.ResourceBundleLocator; + +import org.springframework.context.MessageSource; +import org.springframework.context.support.MessageSourceResourceBundle; +import org.springframework.util.Assert; + +/** + * Implementation of Hibernate Validator 4.1's {@link ResourceBundleLocator} interface, + * exposing a Spring {@link MessageSource} as localized {@link MessageSourceResourceBundle}. + * + * @author Juergen Hoeller + * @since 3.0.4 + * @see ResourceBundleLocator + * @see MessageSource + * @see MessageSourceResourceBundle + */ +public class MessageSourceResourceBundleLocator implements ResourceBundleLocator { + + private final MessageSource messageSource; + + /** + * Build a MessageSourceResourceBundleLocator for the given MessageSource. + * @param messageSource the Spring MessageSource to wrap + */ + public MessageSourceResourceBundleLocator(MessageSource messageSource) { + Assert.notNull(messageSource, "MessageSource must not be null"); + this.messageSource = messageSource; + } + + public ResourceBundle getResourceBundle(Locale locale) { + return new MessageSourceResourceBundle(this.messageSource, locale); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/SpringConstraintValidatorFactory.java b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/SpringConstraintValidatorFactory.java index 0fc183316f..e619287cff 100644 --- a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/SpringConstraintValidatorFactory.java +++ b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/SpringConstraintValidatorFactory.java @@ -1,53 +1,53 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.validation.beanvalidation; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorFactory; - -import org.springframework.beans.factory.config.AutowireCapableBeanFactory; -import org.springframework.util.Assert; - -/** - * JSR-303 {@link ConstraintValidatorFactory} implementation that delegates to a - * Spring BeanFactory for creating autowired {@link ConstraintValidator} instances. - * - * @author Juergen Hoeller - * @since 3.0 - * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#createBean(Class) - * @see org.springframework.context.ApplicationContext#getAutowireCapableBeanFactory() - */ -public class SpringConstraintValidatorFactory implements ConstraintValidatorFactory { - - private final AutowireCapableBeanFactory beanFactory; - - - /** - * Create a new SpringConstraintValidatorFactory for the given BeanFactory. - * @param beanFactory the target BeanFactory - */ - public SpringConstraintValidatorFactory(AutowireCapableBeanFactory beanFactory) { - Assert.notNull(beanFactory, "BeanFactory must not be null"); - this.beanFactory = beanFactory; - } - - - public > T getInstance(Class key) { - return this.beanFactory.createBean(key); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.validation.beanvalidation; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorFactory; + +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.util.Assert; + +/** + * JSR-303 {@link ConstraintValidatorFactory} implementation that delegates to a + * Spring BeanFactory for creating autowired {@link ConstraintValidator} instances. + * + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#createBean(Class) + * @see org.springframework.context.ApplicationContext#getAutowireCapableBeanFactory() + */ +public class SpringConstraintValidatorFactory implements ConstraintValidatorFactory { + + private final AutowireCapableBeanFactory beanFactory; + + + /** + * Create a new SpringConstraintValidatorFactory for the given BeanFactory. + * @param beanFactory the target BeanFactory + */ + public SpringConstraintValidatorFactory(AutowireCapableBeanFactory beanFactory) { + Assert.notNull(beanFactory, "BeanFactory must not be null"); + this.beanFactory = beanFactory; + } + + + public > T getInstance(Class key) { + return this.beanFactory.createBean(key); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java index 08ef9b89bd..91fd75ab60 100644 --- a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java +++ b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java @@ -1,216 +1,216 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.validation.beanvalidation; - -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import javax.validation.ConstraintViolation; -import javax.validation.metadata.BeanDescriptor; -import javax.validation.metadata.ConstraintDescriptor; - -import org.springframework.beans.NotReadablePropertyException; -import org.springframework.context.support.DefaultMessageSourceResolvable; -import org.springframework.util.Assert; -import org.springframework.validation.BindingResult; -import org.springframework.validation.Errors; -import org.springframework.validation.FieldError; -import org.springframework.validation.ObjectError; -import org.springframework.validation.SmartValidator; - -/** - * Adapter that takes a JSR-303 javax.validator.Validator - * and exposes it as a Spring {@link org.springframework.validation.Validator} - * while also exposing the original JSR-303 Validator interface itself. - * - *

Can be used as a programmatic wrapper. Also serves as base class for - * {@link CustomValidatorBean} and {@link LocalValidatorFactoryBean}. - * - * @author Juergen Hoeller - * @since 3.0 - */ -public class SpringValidatorAdapter implements SmartValidator, javax.validation.Validator { - - private static final Set internalAnnotationAttributes = new HashSet(3); - - static { - internalAnnotationAttributes.add("message"); - internalAnnotationAttributes.add("groups"); - internalAnnotationAttributes.add("payload"); - } - - private javax.validation.Validator targetValidator; - - - /** - * Create a new SpringValidatorAdapter for the given JSR-303 Validator. - * @param targetValidator the JSR-303 Validator to wrap - */ - public SpringValidatorAdapter(javax.validation.Validator targetValidator) { - Assert.notNull(targetValidator, "Target Validator must not be null"); - this.targetValidator = targetValidator; - } - - SpringValidatorAdapter() { - } - - void setTargetValidator(javax.validation.Validator targetValidator) { - this.targetValidator = targetValidator; - } - - - //--------------------------------------------------------------------- - // Implementation of Spring Validator interface - //--------------------------------------------------------------------- - - public boolean supports(Class clazz) { - return true; - } - - public void validate(Object target, Errors errors) { - processConstraintViolations(this.targetValidator.validate(target), errors); - } - - public void validate(Object target, Errors errors, Object... validationHints) { - Set groups = new LinkedHashSet(); - if (validationHints != null) { - for (Object hint : validationHints) { - if (hint instanceof Class) { - groups.add((Class) hint); - } - } - } - processConstraintViolations(this.targetValidator.validate(target, groups.toArray(new Class[groups.size()])), errors); - } - - /** - * Process the given JSR-303 ConstraintViolations, adding corresponding errors to - * the provided Spring {@link Errors} object. - * @param violations the JSR-303 ConstraintViolation results - * @param errors the Spring errors object to register to - */ - protected void processConstraintViolations(Set> violations, Errors errors) { - for (ConstraintViolation violation : violations) { - String field = violation.getPropertyPath().toString(); - FieldError fieldError = errors.getFieldError(field); - if (fieldError == null || !fieldError.isBindingFailure()) { - try { - String errorCode = violation.getConstraintDescriptor().getAnnotation().annotationType().getSimpleName(); - Object[] errorArgs = getArgumentsForConstraint(errors.getObjectName(), field, violation.getConstraintDescriptor()); - if (errors instanceof BindingResult) { - // can do custom FieldError registration with invalid value from ConstraintViolation, - // as necessary for Hibernate Validator compatibility (non-indexed set path in field) - BindingResult bindingResult = (BindingResult) errors; - String[] errorCodes = bindingResult.resolveMessageCodes(errorCode, field); - String nestedField = bindingResult.getNestedPath() + field; - ObjectError error; - if ("".equals(nestedField)) { - error = new ObjectError( - errors.getObjectName(), errorCodes, errorArgs, violation.getMessage()); - } - else { - Object invalidValue = violation.getInvalidValue(); - if (!"".equals(field) && invalidValue == violation.getLeafBean()) { - // bean constraint with property path: retrieve the actual property value - invalidValue = bindingResult.getRawFieldValue(field); - } - error = new FieldError( - errors.getObjectName(), nestedField, invalidValue, false, - errorCodes, errorArgs, violation.getMessage()); - } - bindingResult.addError(error); - } - else { - // got no BindingResult - can only do standard rejectValue call - // with automatic extraction of the current field value - errors.rejectValue(field, errorCode, errorArgs, violation.getMessage()); - } - } - catch (NotReadablePropertyException ex) { - throw new IllegalStateException("JSR-303 validated property '" + field + - "' does not have a corresponding accessor for Spring data binding - " + - "check your DataBinder's configuration (bean property versus direct field access)", ex); - } - } - } - } - - /** - * Return FieldError arguments for a validation error on the given field. - * Invoked for each violated constraint. - *

The default implementation returns a first argument indicating the field name - * (of type DefaultMessageSourceResolvable, with "objectName.field" and "field" as codes). - * Afterwards, it adds all actual constraint annotation attributes (i.e. excluding - * "message", "groups" and "payload") in alphabetical order of their attribute names. - *

Can be overridden to e.g. add further attributes from the constraint descriptor. - * @param objectName the name of the target object - * @param field the field that caused the binding error - * @param descriptor the JSR-303 constraint descriptor - * @return the Object array that represents the FieldError arguments - * @see org.springframework.validation.FieldError#getArguments - * @see org.springframework.context.support.DefaultMessageSourceResolvable - * @see org.springframework.validation.DefaultBindingErrorProcessor#getArgumentsForBindError - */ - protected Object[] getArgumentsForConstraint(String objectName, String field, ConstraintDescriptor descriptor) { - List arguments = new LinkedList(); - String[] codes = new String[] {objectName + Errors.NESTED_PATH_SEPARATOR + field, field}; - arguments.add(new DefaultMessageSourceResolvable(codes, field)); - // Using a TreeMap for alphabetical ordering of attribute names - Map attributesToExpose = new TreeMap(); - for (Map.Entry entry : descriptor.getAttributes().entrySet()) { - String attributeName = entry.getKey(); - Object attributeValue = entry.getValue(); - if (!internalAnnotationAttributes.contains(attributeName)) { - attributesToExpose.put(attributeName, attributeValue); - } - } - arguments.addAll(attributesToExpose.values()); - return arguments.toArray(new Object[arguments.size()]); - } - - - //--------------------------------------------------------------------- - // Implementation of JSR-303 Validator interface - //--------------------------------------------------------------------- - - public Set> validate(T object, Class... groups) { - return this.targetValidator.validate(object, groups); - } - - public Set> validateProperty(T object, String propertyName, Class... groups) { - return this.targetValidator.validateProperty(object, propertyName, groups); - } - - public Set> validateValue( - Class beanType, String propertyName, Object value, Class... groups) { - - return this.targetValidator.validateValue(beanType, propertyName, value, groups); - } - - public BeanDescriptor getConstraintsForClass(Class clazz) { - return this.targetValidator.getConstraintsForClass(clazz); - } - - public T unwrap(Class type) { - return this.targetValidator.unwrap(type); - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.validation.beanvalidation; + +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import javax.validation.ConstraintViolation; +import javax.validation.metadata.BeanDescriptor; +import javax.validation.metadata.ConstraintDescriptor; + +import org.springframework.beans.NotReadablePropertyException; +import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.util.Assert; +import org.springframework.validation.BindingResult; +import org.springframework.validation.Errors; +import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; +import org.springframework.validation.SmartValidator; + +/** + * Adapter that takes a JSR-303 javax.validator.Validator + * and exposes it as a Spring {@link org.springframework.validation.Validator} + * while also exposing the original JSR-303 Validator interface itself. + * + *

Can be used as a programmatic wrapper. Also serves as base class for + * {@link CustomValidatorBean} and {@link LocalValidatorFactoryBean}. + * + * @author Juergen Hoeller + * @since 3.0 + */ +public class SpringValidatorAdapter implements SmartValidator, javax.validation.Validator { + + private static final Set internalAnnotationAttributes = new HashSet(3); + + static { + internalAnnotationAttributes.add("message"); + internalAnnotationAttributes.add("groups"); + internalAnnotationAttributes.add("payload"); + } + + private javax.validation.Validator targetValidator; + + + /** + * Create a new SpringValidatorAdapter for the given JSR-303 Validator. + * @param targetValidator the JSR-303 Validator to wrap + */ + public SpringValidatorAdapter(javax.validation.Validator targetValidator) { + Assert.notNull(targetValidator, "Target Validator must not be null"); + this.targetValidator = targetValidator; + } + + SpringValidatorAdapter() { + } + + void setTargetValidator(javax.validation.Validator targetValidator) { + this.targetValidator = targetValidator; + } + + + //--------------------------------------------------------------------- + // Implementation of Spring Validator interface + //--------------------------------------------------------------------- + + public boolean supports(Class clazz) { + return true; + } + + public void validate(Object target, Errors errors) { + processConstraintViolations(this.targetValidator.validate(target), errors); + } + + public void validate(Object target, Errors errors, Object... validationHints) { + Set groups = new LinkedHashSet(); + if (validationHints != null) { + for (Object hint : validationHints) { + if (hint instanceof Class) { + groups.add((Class) hint); + } + } + } + processConstraintViolations(this.targetValidator.validate(target, groups.toArray(new Class[groups.size()])), errors); + } + + /** + * Process the given JSR-303 ConstraintViolations, adding corresponding errors to + * the provided Spring {@link Errors} object. + * @param violations the JSR-303 ConstraintViolation results + * @param errors the Spring errors object to register to + */ + protected void processConstraintViolations(Set> violations, Errors errors) { + for (ConstraintViolation violation : violations) { + String field = violation.getPropertyPath().toString(); + FieldError fieldError = errors.getFieldError(field); + if (fieldError == null || !fieldError.isBindingFailure()) { + try { + String errorCode = violation.getConstraintDescriptor().getAnnotation().annotationType().getSimpleName(); + Object[] errorArgs = getArgumentsForConstraint(errors.getObjectName(), field, violation.getConstraintDescriptor()); + if (errors instanceof BindingResult) { + // can do custom FieldError registration with invalid value from ConstraintViolation, + // as necessary for Hibernate Validator compatibility (non-indexed set path in field) + BindingResult bindingResult = (BindingResult) errors; + String[] errorCodes = bindingResult.resolveMessageCodes(errorCode, field); + String nestedField = bindingResult.getNestedPath() + field; + ObjectError error; + if ("".equals(nestedField)) { + error = new ObjectError( + errors.getObjectName(), errorCodes, errorArgs, violation.getMessage()); + } + else { + Object invalidValue = violation.getInvalidValue(); + if (!"".equals(field) && invalidValue == violation.getLeafBean()) { + // bean constraint with property path: retrieve the actual property value + invalidValue = bindingResult.getRawFieldValue(field); + } + error = new FieldError( + errors.getObjectName(), nestedField, invalidValue, false, + errorCodes, errorArgs, violation.getMessage()); + } + bindingResult.addError(error); + } + else { + // got no BindingResult - can only do standard rejectValue call + // with automatic extraction of the current field value + errors.rejectValue(field, errorCode, errorArgs, violation.getMessage()); + } + } + catch (NotReadablePropertyException ex) { + throw new IllegalStateException("JSR-303 validated property '" + field + + "' does not have a corresponding accessor for Spring data binding - " + + "check your DataBinder's configuration (bean property versus direct field access)", ex); + } + } + } + } + + /** + * Return FieldError arguments for a validation error on the given field. + * Invoked for each violated constraint. + *

The default implementation returns a first argument indicating the field name + * (of type DefaultMessageSourceResolvable, with "objectName.field" and "field" as codes). + * Afterwards, it adds all actual constraint annotation attributes (i.e. excluding + * "message", "groups" and "payload") in alphabetical order of their attribute names. + *

Can be overridden to e.g. add further attributes from the constraint descriptor. + * @param objectName the name of the target object + * @param field the field that caused the binding error + * @param descriptor the JSR-303 constraint descriptor + * @return the Object array that represents the FieldError arguments + * @see org.springframework.validation.FieldError#getArguments + * @see org.springframework.context.support.DefaultMessageSourceResolvable + * @see org.springframework.validation.DefaultBindingErrorProcessor#getArgumentsForBindError + */ + protected Object[] getArgumentsForConstraint(String objectName, String field, ConstraintDescriptor descriptor) { + List arguments = new LinkedList(); + String[] codes = new String[] {objectName + Errors.NESTED_PATH_SEPARATOR + field, field}; + arguments.add(new DefaultMessageSourceResolvable(codes, field)); + // Using a TreeMap for alphabetical ordering of attribute names + Map attributesToExpose = new TreeMap(); + for (Map.Entry entry : descriptor.getAttributes().entrySet()) { + String attributeName = entry.getKey(); + Object attributeValue = entry.getValue(); + if (!internalAnnotationAttributes.contains(attributeName)) { + attributesToExpose.put(attributeName, attributeValue); + } + } + arguments.addAll(attributesToExpose.values()); + return arguments.toArray(new Object[arguments.size()]); + } + + + //--------------------------------------------------------------------- + // Implementation of JSR-303 Validator interface + //--------------------------------------------------------------------- + + public Set> validate(T object, Class... groups) { + return this.targetValidator.validate(object, groups); + } + + public Set> validateProperty(T object, String propertyName, Class... groups) { + return this.targetValidator.validateProperty(object, propertyName, groups); + } + + public Set> validateValue( + Class beanType, String propertyName, Object value, Class... groups) { + + return this.targetValidator.validateValue(beanType, propertyName, value, groups); + } + + public BeanDescriptor getConstraintsForClass(Class clazz) { + return this.targetValidator.getConstraintsForClass(clazz); + } + + public T unwrap(Class type) { + return this.targetValidator.unwrap(type); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/package-info.java b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/package-info.java index f9c8354a40..7961d3ab94 100644 --- a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/package-info.java +++ b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/package-info.java @@ -1,11 +1,11 @@ -/** - * Support classes for integrating a JSR-303 Bean Validation provider - * (such as Hibernate Validator 4.0) into a Spring ApplicationContext - * and in particular with Spring's data binding and validation APIs. - * - *

The central class is {@link - * org.springframework.validation.beanvalidation.LocalValidatorFactoryBean} - * which defines a shared ValidatorFactory/Validator setup for availability - * to other Spring components. - */ -package org.springframework.validation.beanvalidation; +/** + * Support classes for integrating a JSR-303 Bean Validation provider + * (such as Hibernate Validator 4.0) into a Spring ApplicationContext + * and in particular with Spring's data binding and validation APIs. + * + *

The central class is {@link + * org.springframework.validation.beanvalidation.LocalValidatorFactoryBean} + * which defines a shared ValidatorFactory/Validator setup for availability + * to other Spring components. + */ +package org.springframework.validation.beanvalidation; diff --git a/org.springframework.context/src/test/java/org/springframework/cache/NoOpCacheManagerTests.java b/org.springframework.context/src/test/java/org/springframework/cache/NoOpCacheManagerTests.java index 2de234ebe5..79b39b60a6 100644 --- a/org.springframework.context/src/test/java/org/springframework/cache/NoOpCacheManagerTests.java +++ b/org.springframework.context/src/test/java/org/springframework/cache/NoOpCacheManagerTests.java @@ -1,61 +1,61 @@ -/* - * Copyright 2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cache; - -import static org.junit.Assert.*; - -import java.util.UUID; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.cache.support.NoOpCacheManager; - -public class NoOpCacheManagerTests { - - private CacheManager manager; - - @Before - public void setup() { - manager = new NoOpCacheManager(); - } - - @Test - public void testGetCache() throws Exception { - Cache cache = manager.getCache("bucket"); - assertNotNull(cache); - assertSame(cache, manager.getCache("bucket")); - } - - @Test - public void testNoOpCache() throws Exception { - String name = UUID.randomUUID().toString(); - Cache cache = manager.getCache(name); - assertEquals(name, cache.getName()); - Object key = new Object(); - cache.put(key, new Object()); - assertNull(cache.get(key)); - assertNull(cache.getNativeCache()); - } - - @Test - public void testCacheName() throws Exception { - String name = "bucket"; - assertFalse(manager.getCacheNames().contains(name)); - manager.getCache(name); - assertTrue(manager.getCacheNames().contains(name)); - } -} +/* + * Copyright 2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache; + +import static org.junit.Assert.*; + +import java.util.UUID; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.cache.support.NoOpCacheManager; + +public class NoOpCacheManagerTests { + + private CacheManager manager; + + @Before + public void setup() { + manager = new NoOpCacheManager(); + } + + @Test + public void testGetCache() throws Exception { + Cache cache = manager.getCache("bucket"); + assertNotNull(cache); + assertSame(cache, manager.getCache("bucket")); + } + + @Test + public void testNoOpCache() throws Exception { + String name = UUID.randomUUID().toString(); + Cache cache = manager.getCache(name); + assertEquals(name, cache.getName()); + Object key = new Object(); + cache.put(key, new Object()); + assertNull(cache.get(key)); + assertNull(cache.getNativeCache()); + } + + @Test + public void testCacheName() throws Exception { + String name = "bucket"; + assertFalse(manager.getCacheNames().contains(name)); + manager.getCache(name); + assertTrue(manager.getCacheNames().contains(name)); + } +} diff --git a/org.springframework.context/src/test/java/org/springframework/cache/concurrent/ConcurrentCacheTests.java b/org.springframework.context/src/test/java/org/springframework/cache/concurrent/ConcurrentCacheTests.java index 0669bc0c08..88ae4bfa88 100644 --- a/org.springframework.context/src/test/java/org/springframework/cache/concurrent/ConcurrentCacheTests.java +++ b/org.springframework.context/src/test/java/org/springframework/cache/concurrent/ConcurrentCacheTests.java @@ -1,39 +1,39 @@ -/* - * Copyright 2010-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cache.concurrent; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import org.springframework.cache.Cache; -import org.springframework.cache.vendor.AbstractNativeCacheTests; - -/** - * @author Costin Leau - */ -public class ConcurrentCacheTests extends AbstractNativeCacheTests> { - - @Override - protected Cache createCache(ConcurrentMap nativeCache) { - return new ConcurrentMapCache(CACHE_NAME, nativeCache, true); - } - - @Override - protected ConcurrentMap createNativeCache() throws Exception { - return new ConcurrentHashMap(); - } -} +/* + * Copyright 2010-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache.concurrent; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.springframework.cache.Cache; +import org.springframework.cache.vendor.AbstractNativeCacheTests; + +/** + * @author Costin Leau + */ +public class ConcurrentCacheTests extends AbstractNativeCacheTests> { + + @Override + protected Cache createCache(ConcurrentMap nativeCache) { + return new ConcurrentMapCache(CACHE_NAME, nativeCache, true); + } + + @Override + protected ConcurrentMap createNativeCache() throws Exception { + return new ConcurrentHashMap(); + } +} diff --git a/org.springframework.context/src/test/java/org/springframework/cache/concurrent/ConcurrentMapCacheManagerTests.java b/org.springframework.context/src/test/java/org/springframework/cache/concurrent/ConcurrentMapCacheManagerTests.java index 69b66d41cc..cc0c963070 100644 --- a/org.springframework.context/src/test/java/org/springframework/cache/concurrent/ConcurrentMapCacheManagerTests.java +++ b/org.springframework.context/src/test/java/org/springframework/cache/concurrent/ConcurrentMapCacheManagerTests.java @@ -1,63 +1,63 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cache.concurrent; - -import org.junit.Test; - -import org.springframework.cache.Cache; -import org.springframework.cache.CacheManager; - -import static org.junit.Assert.*; - -/** - * @author Juergen Hoeller - */ -public class ConcurrentMapCacheManagerTests { - - @Test - public void testDynamicMode() { - CacheManager cm = new ConcurrentMapCacheManager(); - Cache cache1 = cm.getCache("c1"); - assertTrue(cache1 instanceof ConcurrentMapCache); - Cache cache1again = cm.getCache("c1"); - assertSame(cache1again, cache1); - Cache cache2 = cm.getCache("c2"); - assertTrue(cache2 instanceof ConcurrentMapCache); - Cache cache2again = cm.getCache("c2"); - assertSame(cache2again, cache2); - Cache cache3 = cm.getCache("c3"); - assertTrue(cache3 instanceof ConcurrentMapCache); - Cache cache3again = cm.getCache("c3"); - assertSame(cache3again, cache3); - } - - @Test - public void testStaticMode() { - ConcurrentMapCacheManager cm = new ConcurrentMapCacheManager("c1", "c2"); - Cache cache1 = cm.getCache("c1"); - assertTrue(cache1 instanceof ConcurrentMapCache); - Cache cache1again = cm.getCache("c1"); - assertSame(cache1again, cache1); - Cache cache2 = cm.getCache("c2"); - assertTrue(cache2 instanceof ConcurrentMapCache); - Cache cache2again = cm.getCache("c2"); - assertSame(cache2again, cache2); - Cache cache3 = cm.getCache("c3"); - assertNull(cache3); - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache.concurrent; + +import org.junit.Test; + +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; + +import static org.junit.Assert.*; + +/** + * @author Juergen Hoeller + */ +public class ConcurrentMapCacheManagerTests { + + @Test + public void testDynamicMode() { + CacheManager cm = new ConcurrentMapCacheManager(); + Cache cache1 = cm.getCache("c1"); + assertTrue(cache1 instanceof ConcurrentMapCache); + Cache cache1again = cm.getCache("c1"); + assertSame(cache1again, cache1); + Cache cache2 = cm.getCache("c2"); + assertTrue(cache2 instanceof ConcurrentMapCache); + Cache cache2again = cm.getCache("c2"); + assertSame(cache2again, cache2); + Cache cache3 = cm.getCache("c3"); + assertTrue(cache3 instanceof ConcurrentMapCache); + Cache cache3again = cm.getCache("c3"); + assertSame(cache3again, cache3); + } + + @Test + public void testStaticMode() { + ConcurrentMapCacheManager cm = new ConcurrentMapCacheManager("c1", "c2"); + Cache cache1 = cm.getCache("c1"); + assertTrue(cache1 instanceof ConcurrentMapCache); + Cache cache1again = cm.getCache("c1"); + assertSame(cache1again, cache1); + Cache cache2 = cm.getCache("c2"); + assertTrue(cache2 instanceof ConcurrentMapCache); + Cache cache2again = cm.getCache("c2"); + assertSame(cache2again, cache2); + Cache cache3 = cm.getCache("c3"); + assertNull(cache3); + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/cache/config/AbstractAnnotationTests.java b/org.springframework.context/src/test/java/org/springframework/cache/config/AbstractAnnotationTests.java index cfc661281f..4bc0c888b3 100644 --- a/org.springframework.context/src/test/java/org/springframework/cache/config/AbstractAnnotationTests.java +++ b/org.springframework.context/src/test/java/org/springframework/cache/config/AbstractAnnotationTests.java @@ -1,621 +1,621 @@ -/* - * Copyright 2010-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cache.config; - -import static org.junit.Assert.*; - -import java.util.Collection; -import java.util.UUID; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.aop.framework.AopProxyUtils; -import org.springframework.cache.Cache; -import org.springframework.cache.CacheManager; -import org.springframework.context.ApplicationContext; - -/** - * Abstract annotation test (containing several reusable methods). - * - * @author Costin Leau - * @author Chris Beams - */ -public abstract class AbstractAnnotationTests { - - protected ApplicationContext ctx; - - protected CacheableService cs; - - protected CacheableService ccs; - - protected CacheManager cm; - - /** @return a refreshed application context */ - protected abstract ApplicationContext getApplicationContext(); - - @Before - public void setup() { - ctx = getApplicationContext(); - cs = ctx.getBean("service", CacheableService.class); - ccs = ctx.getBean("classService", CacheableService.class); - cm = ctx.getBean(CacheManager.class); - Collection cn = cm.getCacheNames(); - assertTrue(cn.contains("default")); - assertTrue(cn.contains("secondary")); - assertTrue(cn.contains("primary")); - } - - public void testCacheable(CacheableService service) throws Exception { - Object o1 = new Object(); - - Object r1 = service.cache(o1); - Object r2 = service.cache(o1); - Object r3 = service.cache(o1); - - assertSame(r1, r2); - assertSame(r1, r3); - } - - public void testEvict(CacheableService service) throws Exception { - Object o1 = new Object(); - - Object r1 = service.cache(o1); - Object r2 = service.cache(o1); - - assertSame(r1, r2); - service.invalidate(o1); - Object r3 = service.cache(o1); - Object r4 = service.cache(o1); - assertNotSame(r1, r3); - assertSame(r3, r4); - } - - public void testEvictEarly(CacheableService service) throws Exception { - Object o1 = new Object(); - - Object r1 = service.cache(o1); - Object r2 = service.cache(o1); - - assertSame(r1, r2); - try { - service.evictEarly(o1); - } catch (RuntimeException ex) { - // expected - } - - Object r3 = service.cache(o1); - Object r4 = service.cache(o1); - assertNotSame(r1, r3); - assertSame(r3, r4); - } - - public void testEvictException(CacheableService service) throws Exception { - Object o1 = new Object(); - - Object r1 = service.cache(o1); - Object r2 = service.cache(o1); - - assertSame(r1, r2); - try { - service.evictWithException(o1); - } catch (RuntimeException ex) { - // expected - } - // exception occurred, eviction skipped, data should still be in the cache - Object r3 = service.cache(o1); - assertSame(r1, r3); - } - - public void testEvictWKey(CacheableService service) throws Exception { - Object o1 = new Object(); - - Object r1 = service.cache(o1); - Object r2 = service.cache(o1); - - assertSame(r1, r2); - service.evict(o1, null); - Object r3 = service.cache(o1); - Object r4 = service.cache(o1); - assertNotSame(r1, r3); - assertSame(r3, r4); - } - - public void testEvictWKeyEarly(CacheableService service) throws Exception { - Object o1 = new Object(); - - Object r1 = service.cache(o1); - Object r2 = service.cache(o1); - - assertSame(r1, r2); - - try { - service.invalidateEarly(o1, null); - } catch (Exception ex) { - // expected - } - Object r3 = service.cache(o1); - Object r4 = service.cache(o1); - assertNotSame(r1, r3); - assertSame(r3, r4); - } - - public void testEvictAll(CacheableService service) throws Exception { - Object o1 = new Object(); - - Object r1 = service.cache(o1); - Object r2 = service.cache(o1); - - Object o2 = new Object(); - Object r10 = service.cache(o2); - - assertSame(r1, r2); - assertNotSame(r1, r10); - service.evictAll(new Object()); - Cache cache = cm.getCache("default"); - assertNull(cache.get(o1)); - assertNull(cache.get(o2)); - - Object r3 = service.cache(o1); - Object r4 = service.cache(o1); - assertNotSame(r1, r3); - assertSame(r3, r4); - } - - public void testConditionalExpression(CacheableService service) throws Exception { - Object r1 = service.conditional(4); - Object r2 = service.conditional(4); - - assertNotSame(r1, r2); - - Object r3 = service.conditional(3); - Object r4 = service.conditional(3); - - assertSame(r3, r4); - } - - public void testKeyExpression(CacheableService service) throws Exception { - Object r1 = service.key(5, 1); - Object r2 = service.key(5, 2); - - assertSame(r1, r2); - - Object r3 = service.key(1, 5); - Object r4 = service.key(2, 5); - - assertNotSame(r3, r4); - } - - public void testNullValue(CacheableService service) throws Exception { - Object key = new Object(); - assertNull(service.nullValue(key)); - int nr = service.nullInvocations().intValue(); - assertNull(service.nullValue(key)); - assertEquals(nr, service.nullInvocations().intValue()); - assertNull(service.nullValue(new Object())); - assertEquals(nr + 1, service.nullInvocations().intValue()); - } - - public void testMethodName(CacheableService service, String keyName) throws Exception { - Object key = new Object(); - Object r1 = service.name(key); - assertSame(r1, service.name(key)); - Cache cache = cm.getCache("default"); - // assert the method name is used - assertNotNull(cache.get(keyName)); - } - - public void testRootVars(CacheableService service) { - Object key = new Object(); - Object r1 = service.rootVars(key); - assertSame(r1, service.rootVars(key)); - Cache cache = cm.getCache("default"); - // assert the method name is used - String expectedKey = "rootVarsrootVars" + AopProxyUtils.ultimateTargetClass(service) + service; - assertNotNull(cache.get(expectedKey)); - } - - public void testCheckedThrowable(CacheableService service) throws Exception { - String arg = UUID.randomUUID().toString(); - try { - service.throwChecked(arg); - fail("Excepted exception"); - } catch (Exception ex) { - assertEquals(arg, ex.getMessage()); - } - } - - public void testUncheckedThrowable(CacheableService service) throws Exception { - try { - service.throwUnchecked(Long.valueOf(1)); - fail("Excepted exception"); - } catch (RuntimeException ex) { - assertTrue("Excepted different exception type and got " + ex.getClass(), - ex instanceof UnsupportedOperationException); - // expected - } - } - - public void testNullArg(CacheableService service) { - Object r1 = service.cache(null); - assertSame(r1, service.cache(null)); - } - - public void testCacheUpdate(CacheableService service) { - Object o = new Object(); - Cache cache = cm.getCache("default"); - assertNull(cache.get(o)); - Object r1 = service.update(o); - assertSame(r1, cache.get(o).get()); - - o = new Object(); - assertNull(cache.get(o)); - Object r2 = service.update(o); - assertSame(r2, cache.get(o).get()); - } - - public void testConditionalCacheUpdate(CacheableService service) { - Integer one = Integer.valueOf(1); - Integer three = Integer.valueOf(3); - - Cache cache = cm.getCache("default"); - assertEquals(one, Integer.valueOf(service.conditionalUpdate(one).toString())); - assertNull(cache.get(one)); - - assertEquals(three, Integer.valueOf(service.conditionalUpdate(three).toString())); - assertEquals(three, Integer.valueOf(cache.get(three).get().toString())); - } - - public void testMultiCache(CacheableService service) { - Object o1 = new Object(); - Object o2 = new Object(); - - Cache primary = cm.getCache("primary"); - Cache secondary = cm.getCache("secondary"); - - assertNull(primary.get(o1)); - assertNull(secondary.get(o1)); - Object r1 = service.multiCache(o1); - assertSame(r1, primary.get(o1).get()); - assertSame(r1, secondary.get(o1).get()); - - Object r2 = service.multiCache(o1); - Object r3 = service.multiCache(o1); - - assertSame(r1, r2); - assertSame(r1, r3); - - assertNull(primary.get(o2)); - assertNull(secondary.get(o2)); - Object r4 = service.multiCache(o2); - assertSame(r4, primary.get(o2).get()); - assertSame(r4, secondary.get(o2).get()); - } - - public void testMultiEvict(CacheableService service) { - Object o1 = new Object(); - Object o2 = o1.toString() + "A"; - - - Object r1 = service.multiCache(o1); - Object r2 = service.multiCache(o1); - - Cache primary = cm.getCache("primary"); - Cache secondary = cm.getCache("secondary"); - - primary.put(o2, o2); - assertSame(r1, r2); - assertSame(r1, primary.get(o1).get()); - assertSame(r1, secondary.get(o1).get()); - - service.multiEvict(o1); - assertNull(primary.get(o1)); - assertNull(secondary.get(o1)); - assertNull(primary.get(o2)); - - Object r3 = service.multiCache(o1); - Object r4 = service.multiCache(o1); - assertNotSame(r1, r3); - assertSame(r3, r4); - - assertSame(r3, primary.get(o1).get()); - assertSame(r4, secondary.get(o1).get()); - } - - public void testMultiPut(CacheableService service) { - Object o = Integer.valueOf(1); - - Cache primary = cm.getCache("primary"); - Cache secondary = cm.getCache("secondary"); - - assertNull(primary.get(o)); - assertNull(secondary.get(o)); - Object r1 = service.multiUpdate(o); - assertSame(r1, primary.get(o).get()); - assertSame(r1, secondary.get(o).get()); - - o = Integer.valueOf(2); - assertNull(primary.get(o)); - assertNull(secondary.get(o)); - Object r2 = service.multiUpdate(o); - assertSame(r2, primary.get(o).get()); - assertSame(r2, secondary.get(o).get()); - } - - public void testMultiCacheAndEvict(CacheableService service) { - String methodName = "multiCacheAndEvict"; - - Cache primary = cm.getCache("primary"); - Cache secondary = cm.getCache("secondary"); - Object key = Integer.valueOf(1); - - secondary.put(key, key); - - assertNull(secondary.get(methodName)); - assertSame(key, secondary.get(key).get()); - - Object r1 = service.multiCacheAndEvict(key); - assertSame(r1, service.multiCacheAndEvict(key)); - - // assert the method name is used - assertSame(r1, primary.get(methodName).get()); - assertNull(secondary.get(methodName)); - assertNull(secondary.get(key)); - } - - public void testMultiConditionalCacheAndEvict(CacheableService service) { - Cache primary = cm.getCache("primary"); - Cache secondary = cm.getCache("secondary"); - Object key = Integer.valueOf(1); - - secondary.put(key, key); - - assertNull(primary.get(key)); - assertSame(key, secondary.get(key).get()); - - Object r1 = service.multiConditionalCacheAndEvict(key); - Object r3 = service.multiConditionalCacheAndEvict(key); - - assertTrue(!r1.equals(r3)); - assertNull(primary.get(key)); - - Object key2 = Integer.valueOf(3); - Object r2 = service.multiConditionalCacheAndEvict(key2); - assertSame(r2, service.multiConditionalCacheAndEvict(key2)); - - // assert the method name is used - assertSame(r2, primary.get(key2).get()); - assertNull(secondary.get(key2)); - } - - @Test - public void testCacheable() throws Exception { - testCacheable(cs); - } - - @Test - public void testInvalidate() throws Exception { - testEvict(cs); - } - - @Test - public void testEarlyInvalidate() throws Exception { - testEvictEarly(cs); - } - - @Test - public void testEvictWithException() throws Exception { - testEvictException(cs); - } - - @Test - public void testEvictAll() throws Exception { - testEvictAll(cs); - } - - @Test - public void testInvalidateWithKey() throws Exception { - testEvictWKey(cs); - } - - @Test - public void testEarlyInvalidateWithKey() throws Exception { - testEvictWKeyEarly(cs); - } - - @Test - public void testConditionalExpression() throws Exception { - testConditionalExpression(cs); - } - - @Test - public void testKeyExpression() throws Exception { - testKeyExpression(cs); - } - - @Test - public void testClassCacheCacheable() throws Exception { - testCacheable(ccs); - } - - @Test - public void testClassCacheInvalidate() throws Exception { - testEvict(ccs); - } - - @Test - public void testClassEarlyInvalidate() throws Exception { - testEvictEarly(ccs); - } - - @Test - public void testClassEvictAll() throws Exception { - testEvictAll(ccs); - } - - @Test - public void testClassEvictWithException() throws Exception { - testEvictException(ccs); - } - - @Test - public void testClassCacheInvalidateWKey() throws Exception { - testEvictWKey(ccs); - } - - @Test - public void testClassEarlyInvalidateWithKey() throws Exception { - testEvictWKeyEarly(ccs); - } - - @Test - public void testNullValue() throws Exception { - testNullValue(cs); - } - - @Test - public void testClassNullValue() throws Exception { - Object key = new Object(); - assertNull(ccs.nullValue(key)); - int nr = ccs.nullInvocations().intValue(); - assertNull(ccs.nullValue(key)); - assertEquals(nr, ccs.nullInvocations().intValue()); - assertNull(ccs.nullValue(new Object())); - // the check method is also cached - assertEquals(nr, ccs.nullInvocations().intValue()); - assertEquals(nr + 1, AnnotatedClassCacheableService.nullInvocations.intValue()); - } - - @Test - public void testMethodName() throws Exception { - testMethodName(cs, "name"); - } - - @Test - public void testClassMethodName() throws Exception { - testMethodName(ccs, "namedefault"); - } - - @Test - public void testRootVars() throws Exception { - testRootVars(cs); - } - - @Test - public void testClassRootVars() throws Exception { - testRootVars(ccs); - } - - @Test - public void testNullArg() throws Exception { - testNullArg(cs); - } - - @Test - public void testClassNullArg() throws Exception { - testNullArg(ccs); - } - - @Test - public void testCheckedException() throws Exception { - testCheckedThrowable(cs); - } - - @Test - public void testClassCheckedException() throws Exception { - testCheckedThrowable(ccs); - } - - @Test - public void testUncheckedException() throws Exception { - testUncheckedThrowable(cs); - } - - @Test - public void testClassUncheckedException() throws Exception { - testUncheckedThrowable(ccs); - } - - @Test - public void testUpdate() { - testCacheUpdate(cs); - } - - @Test - public void testClassUpdate() { - testCacheUpdate(ccs); - } - - @Test - public void testConditionalUpdate() { - testConditionalCacheUpdate(cs); - } - - @Test - public void testClassConditionalUpdate() { - testConditionalCacheUpdate(ccs); - } - - @Test - public void testMultiCache() { - testMultiCache(cs); - } - - @Test - public void testClassMultiCache() { - testMultiCache(ccs); - } - - @Test - public void testMultiEvict() { - testMultiEvict(cs); - } - - @Test - public void testClassMultiEvict() { - testMultiEvict(ccs); - } - - @Test - public void testMultiPut() { - testMultiPut(cs); - } - - @Test - public void testClassMultiPut() { - testMultiPut(ccs); - } - - @Test - public void testMultiCacheAndEvict() { - testMultiCacheAndEvict(cs); - } - - @Test - public void testClassMultiCacheAndEvict() { - testMultiCacheAndEvict(ccs); - } - - @Test - public void testMultiConditionalCacheAndEvict() { - testMultiConditionalCacheAndEvict(cs); - } - - @Test - public void testClassMultiConditionalCacheAndEvict() { - testMultiConditionalCacheAndEvict(ccs); - } +/* + * Copyright 2010-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache.config; + +import static org.junit.Assert.*; + +import java.util.Collection; +import java.util.UUID; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.aop.framework.AopProxyUtils; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.context.ApplicationContext; + +/** + * Abstract annotation test (containing several reusable methods). + * + * @author Costin Leau + * @author Chris Beams + */ +public abstract class AbstractAnnotationTests { + + protected ApplicationContext ctx; + + protected CacheableService cs; + + protected CacheableService ccs; + + protected CacheManager cm; + + /** @return a refreshed application context */ + protected abstract ApplicationContext getApplicationContext(); + + @Before + public void setup() { + ctx = getApplicationContext(); + cs = ctx.getBean("service", CacheableService.class); + ccs = ctx.getBean("classService", CacheableService.class); + cm = ctx.getBean(CacheManager.class); + Collection cn = cm.getCacheNames(); + assertTrue(cn.contains("default")); + assertTrue(cn.contains("secondary")); + assertTrue(cn.contains("primary")); + } + + public void testCacheable(CacheableService service) throws Exception { + Object o1 = new Object(); + + Object r1 = service.cache(o1); + Object r2 = service.cache(o1); + Object r3 = service.cache(o1); + + assertSame(r1, r2); + assertSame(r1, r3); + } + + public void testEvict(CacheableService service) throws Exception { + Object o1 = new Object(); + + Object r1 = service.cache(o1); + Object r2 = service.cache(o1); + + assertSame(r1, r2); + service.invalidate(o1); + Object r3 = service.cache(o1); + Object r4 = service.cache(o1); + assertNotSame(r1, r3); + assertSame(r3, r4); + } + + public void testEvictEarly(CacheableService service) throws Exception { + Object o1 = new Object(); + + Object r1 = service.cache(o1); + Object r2 = service.cache(o1); + + assertSame(r1, r2); + try { + service.evictEarly(o1); + } catch (RuntimeException ex) { + // expected + } + + Object r3 = service.cache(o1); + Object r4 = service.cache(o1); + assertNotSame(r1, r3); + assertSame(r3, r4); + } + + public void testEvictException(CacheableService service) throws Exception { + Object o1 = new Object(); + + Object r1 = service.cache(o1); + Object r2 = service.cache(o1); + + assertSame(r1, r2); + try { + service.evictWithException(o1); + } catch (RuntimeException ex) { + // expected + } + // exception occurred, eviction skipped, data should still be in the cache + Object r3 = service.cache(o1); + assertSame(r1, r3); + } + + public void testEvictWKey(CacheableService service) throws Exception { + Object o1 = new Object(); + + Object r1 = service.cache(o1); + Object r2 = service.cache(o1); + + assertSame(r1, r2); + service.evict(o1, null); + Object r3 = service.cache(o1); + Object r4 = service.cache(o1); + assertNotSame(r1, r3); + assertSame(r3, r4); + } + + public void testEvictWKeyEarly(CacheableService service) throws Exception { + Object o1 = new Object(); + + Object r1 = service.cache(o1); + Object r2 = service.cache(o1); + + assertSame(r1, r2); + + try { + service.invalidateEarly(o1, null); + } catch (Exception ex) { + // expected + } + Object r3 = service.cache(o1); + Object r4 = service.cache(o1); + assertNotSame(r1, r3); + assertSame(r3, r4); + } + + public void testEvictAll(CacheableService service) throws Exception { + Object o1 = new Object(); + + Object r1 = service.cache(o1); + Object r2 = service.cache(o1); + + Object o2 = new Object(); + Object r10 = service.cache(o2); + + assertSame(r1, r2); + assertNotSame(r1, r10); + service.evictAll(new Object()); + Cache cache = cm.getCache("default"); + assertNull(cache.get(o1)); + assertNull(cache.get(o2)); + + Object r3 = service.cache(o1); + Object r4 = service.cache(o1); + assertNotSame(r1, r3); + assertSame(r3, r4); + } + + public void testConditionalExpression(CacheableService service) throws Exception { + Object r1 = service.conditional(4); + Object r2 = service.conditional(4); + + assertNotSame(r1, r2); + + Object r3 = service.conditional(3); + Object r4 = service.conditional(3); + + assertSame(r3, r4); + } + + public void testKeyExpression(CacheableService service) throws Exception { + Object r1 = service.key(5, 1); + Object r2 = service.key(5, 2); + + assertSame(r1, r2); + + Object r3 = service.key(1, 5); + Object r4 = service.key(2, 5); + + assertNotSame(r3, r4); + } + + public void testNullValue(CacheableService service) throws Exception { + Object key = new Object(); + assertNull(service.nullValue(key)); + int nr = service.nullInvocations().intValue(); + assertNull(service.nullValue(key)); + assertEquals(nr, service.nullInvocations().intValue()); + assertNull(service.nullValue(new Object())); + assertEquals(nr + 1, service.nullInvocations().intValue()); + } + + public void testMethodName(CacheableService service, String keyName) throws Exception { + Object key = new Object(); + Object r1 = service.name(key); + assertSame(r1, service.name(key)); + Cache cache = cm.getCache("default"); + // assert the method name is used + assertNotNull(cache.get(keyName)); + } + + public void testRootVars(CacheableService service) { + Object key = new Object(); + Object r1 = service.rootVars(key); + assertSame(r1, service.rootVars(key)); + Cache cache = cm.getCache("default"); + // assert the method name is used + String expectedKey = "rootVarsrootVars" + AopProxyUtils.ultimateTargetClass(service) + service; + assertNotNull(cache.get(expectedKey)); + } + + public void testCheckedThrowable(CacheableService service) throws Exception { + String arg = UUID.randomUUID().toString(); + try { + service.throwChecked(arg); + fail("Excepted exception"); + } catch (Exception ex) { + assertEquals(arg, ex.getMessage()); + } + } + + public void testUncheckedThrowable(CacheableService service) throws Exception { + try { + service.throwUnchecked(Long.valueOf(1)); + fail("Excepted exception"); + } catch (RuntimeException ex) { + assertTrue("Excepted different exception type and got " + ex.getClass(), + ex instanceof UnsupportedOperationException); + // expected + } + } + + public void testNullArg(CacheableService service) { + Object r1 = service.cache(null); + assertSame(r1, service.cache(null)); + } + + public void testCacheUpdate(CacheableService service) { + Object o = new Object(); + Cache cache = cm.getCache("default"); + assertNull(cache.get(o)); + Object r1 = service.update(o); + assertSame(r1, cache.get(o).get()); + + o = new Object(); + assertNull(cache.get(o)); + Object r2 = service.update(o); + assertSame(r2, cache.get(o).get()); + } + + public void testConditionalCacheUpdate(CacheableService service) { + Integer one = Integer.valueOf(1); + Integer three = Integer.valueOf(3); + + Cache cache = cm.getCache("default"); + assertEquals(one, Integer.valueOf(service.conditionalUpdate(one).toString())); + assertNull(cache.get(one)); + + assertEquals(three, Integer.valueOf(service.conditionalUpdate(three).toString())); + assertEquals(three, Integer.valueOf(cache.get(three).get().toString())); + } + + public void testMultiCache(CacheableService service) { + Object o1 = new Object(); + Object o2 = new Object(); + + Cache primary = cm.getCache("primary"); + Cache secondary = cm.getCache("secondary"); + + assertNull(primary.get(o1)); + assertNull(secondary.get(o1)); + Object r1 = service.multiCache(o1); + assertSame(r1, primary.get(o1).get()); + assertSame(r1, secondary.get(o1).get()); + + Object r2 = service.multiCache(o1); + Object r3 = service.multiCache(o1); + + assertSame(r1, r2); + assertSame(r1, r3); + + assertNull(primary.get(o2)); + assertNull(secondary.get(o2)); + Object r4 = service.multiCache(o2); + assertSame(r4, primary.get(o2).get()); + assertSame(r4, secondary.get(o2).get()); + } + + public void testMultiEvict(CacheableService service) { + Object o1 = new Object(); + Object o2 = o1.toString() + "A"; + + + Object r1 = service.multiCache(o1); + Object r2 = service.multiCache(o1); + + Cache primary = cm.getCache("primary"); + Cache secondary = cm.getCache("secondary"); + + primary.put(o2, o2); + assertSame(r1, r2); + assertSame(r1, primary.get(o1).get()); + assertSame(r1, secondary.get(o1).get()); + + service.multiEvict(o1); + assertNull(primary.get(o1)); + assertNull(secondary.get(o1)); + assertNull(primary.get(o2)); + + Object r3 = service.multiCache(o1); + Object r4 = service.multiCache(o1); + assertNotSame(r1, r3); + assertSame(r3, r4); + + assertSame(r3, primary.get(o1).get()); + assertSame(r4, secondary.get(o1).get()); + } + + public void testMultiPut(CacheableService service) { + Object o = Integer.valueOf(1); + + Cache primary = cm.getCache("primary"); + Cache secondary = cm.getCache("secondary"); + + assertNull(primary.get(o)); + assertNull(secondary.get(o)); + Object r1 = service.multiUpdate(o); + assertSame(r1, primary.get(o).get()); + assertSame(r1, secondary.get(o).get()); + + o = Integer.valueOf(2); + assertNull(primary.get(o)); + assertNull(secondary.get(o)); + Object r2 = service.multiUpdate(o); + assertSame(r2, primary.get(o).get()); + assertSame(r2, secondary.get(o).get()); + } + + public void testMultiCacheAndEvict(CacheableService service) { + String methodName = "multiCacheAndEvict"; + + Cache primary = cm.getCache("primary"); + Cache secondary = cm.getCache("secondary"); + Object key = Integer.valueOf(1); + + secondary.put(key, key); + + assertNull(secondary.get(methodName)); + assertSame(key, secondary.get(key).get()); + + Object r1 = service.multiCacheAndEvict(key); + assertSame(r1, service.multiCacheAndEvict(key)); + + // assert the method name is used + assertSame(r1, primary.get(methodName).get()); + assertNull(secondary.get(methodName)); + assertNull(secondary.get(key)); + } + + public void testMultiConditionalCacheAndEvict(CacheableService service) { + Cache primary = cm.getCache("primary"); + Cache secondary = cm.getCache("secondary"); + Object key = Integer.valueOf(1); + + secondary.put(key, key); + + assertNull(primary.get(key)); + assertSame(key, secondary.get(key).get()); + + Object r1 = service.multiConditionalCacheAndEvict(key); + Object r3 = service.multiConditionalCacheAndEvict(key); + + assertTrue(!r1.equals(r3)); + assertNull(primary.get(key)); + + Object key2 = Integer.valueOf(3); + Object r2 = service.multiConditionalCacheAndEvict(key2); + assertSame(r2, service.multiConditionalCacheAndEvict(key2)); + + // assert the method name is used + assertSame(r2, primary.get(key2).get()); + assertNull(secondary.get(key2)); + } + + @Test + public void testCacheable() throws Exception { + testCacheable(cs); + } + + @Test + public void testInvalidate() throws Exception { + testEvict(cs); + } + + @Test + public void testEarlyInvalidate() throws Exception { + testEvictEarly(cs); + } + + @Test + public void testEvictWithException() throws Exception { + testEvictException(cs); + } + + @Test + public void testEvictAll() throws Exception { + testEvictAll(cs); + } + + @Test + public void testInvalidateWithKey() throws Exception { + testEvictWKey(cs); + } + + @Test + public void testEarlyInvalidateWithKey() throws Exception { + testEvictWKeyEarly(cs); + } + + @Test + public void testConditionalExpression() throws Exception { + testConditionalExpression(cs); + } + + @Test + public void testKeyExpression() throws Exception { + testKeyExpression(cs); + } + + @Test + public void testClassCacheCacheable() throws Exception { + testCacheable(ccs); + } + + @Test + public void testClassCacheInvalidate() throws Exception { + testEvict(ccs); + } + + @Test + public void testClassEarlyInvalidate() throws Exception { + testEvictEarly(ccs); + } + + @Test + public void testClassEvictAll() throws Exception { + testEvictAll(ccs); + } + + @Test + public void testClassEvictWithException() throws Exception { + testEvictException(ccs); + } + + @Test + public void testClassCacheInvalidateWKey() throws Exception { + testEvictWKey(ccs); + } + + @Test + public void testClassEarlyInvalidateWithKey() throws Exception { + testEvictWKeyEarly(ccs); + } + + @Test + public void testNullValue() throws Exception { + testNullValue(cs); + } + + @Test + public void testClassNullValue() throws Exception { + Object key = new Object(); + assertNull(ccs.nullValue(key)); + int nr = ccs.nullInvocations().intValue(); + assertNull(ccs.nullValue(key)); + assertEquals(nr, ccs.nullInvocations().intValue()); + assertNull(ccs.nullValue(new Object())); + // the check method is also cached + assertEquals(nr, ccs.nullInvocations().intValue()); + assertEquals(nr + 1, AnnotatedClassCacheableService.nullInvocations.intValue()); + } + + @Test + public void testMethodName() throws Exception { + testMethodName(cs, "name"); + } + + @Test + public void testClassMethodName() throws Exception { + testMethodName(ccs, "namedefault"); + } + + @Test + public void testRootVars() throws Exception { + testRootVars(cs); + } + + @Test + public void testClassRootVars() throws Exception { + testRootVars(ccs); + } + + @Test + public void testNullArg() throws Exception { + testNullArg(cs); + } + + @Test + public void testClassNullArg() throws Exception { + testNullArg(ccs); + } + + @Test + public void testCheckedException() throws Exception { + testCheckedThrowable(cs); + } + + @Test + public void testClassCheckedException() throws Exception { + testCheckedThrowable(ccs); + } + + @Test + public void testUncheckedException() throws Exception { + testUncheckedThrowable(cs); + } + + @Test + public void testClassUncheckedException() throws Exception { + testUncheckedThrowable(ccs); + } + + @Test + public void testUpdate() { + testCacheUpdate(cs); + } + + @Test + public void testClassUpdate() { + testCacheUpdate(ccs); + } + + @Test + public void testConditionalUpdate() { + testConditionalCacheUpdate(cs); + } + + @Test + public void testClassConditionalUpdate() { + testConditionalCacheUpdate(ccs); + } + + @Test + public void testMultiCache() { + testMultiCache(cs); + } + + @Test + public void testClassMultiCache() { + testMultiCache(ccs); + } + + @Test + public void testMultiEvict() { + testMultiEvict(cs); + } + + @Test + public void testClassMultiEvict() { + testMultiEvict(ccs); + } + + @Test + public void testMultiPut() { + testMultiPut(cs); + } + + @Test + public void testClassMultiPut() { + testMultiPut(ccs); + } + + @Test + public void testMultiCacheAndEvict() { + testMultiCacheAndEvict(cs); + } + + @Test + public void testClassMultiCacheAndEvict() { + testMultiCacheAndEvict(ccs); + } + + @Test + public void testMultiConditionalCacheAndEvict() { + testMultiConditionalCacheAndEvict(cs); + } + + @Test + public void testClassMultiConditionalCacheAndEvict() { + testMultiConditionalCacheAndEvict(ccs); + } } \ No newline at end of file diff --git a/org.springframework.context/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java b/org.springframework.context/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java index 744963e6c0..573a5d8ffc 100644 --- a/org.springframework.context/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java +++ b/org.springframework.context/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java @@ -1,138 +1,138 @@ -/* - * Copyright 2010-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cache.config; - -import java.util.concurrent.atomic.AtomicLong; - -import org.springframework.cache.annotation.CacheEvict; -import org.springframework.cache.annotation.CachePut; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.cache.annotation.Caching; - -/** - * @author Costin Leau - */ -@Cacheable("default") -public class AnnotatedClassCacheableService implements CacheableService { - - private final AtomicLong counter = new AtomicLong(); - public static final AtomicLong nullInvocations = new AtomicLong(); - - public Object cache(Object arg1) { - return counter.getAndIncrement(); - } - - public Object conditional(int field) { - return null; - } - - @CacheEvict("default") - public void invalidate(Object arg1) { - } - - @CacheEvict("default") - public void evictWithException(Object arg1) { - throw new RuntimeException("exception thrown - evict should NOT occur"); - } - - @CacheEvict(value = "default", allEntries = true) - public void evictAll(Object arg1) { - } - - @CacheEvict(value = "default", beforeInvocation = true) - public void evictEarly(Object arg1) { - throw new RuntimeException("exception thrown - evict should still occur"); - } - - @CacheEvict(value = "default", key = "#p0") - public void evict(Object arg1, Object arg2) { - } - - @CacheEvict(value = "default", key = "#p0", beforeInvocation = true) - public void invalidateEarly(Object arg1, Object arg2) { - throw new RuntimeException("exception thrown - evict should still occur"); - } - - @Cacheable(value = "default", key = "#p0") - public Object key(Object arg1, Object arg2) { - return counter.getAndIncrement(); - } - - @Cacheable(value = "default", key = "#root.methodName + #root.caches[0].name") - public Object name(Object arg1) { - return counter.getAndIncrement(); - } - - @Cacheable(value = "default", key = "#root.methodName + #root.method.name + #root.targetClass + #root.target") - public Object rootVars(Object arg1) { - return counter.getAndIncrement(); - } - - @CachePut("default") - public Object update(Object arg1) { - return counter.getAndIncrement(); - } - - @CachePut(value = "default", condition = "#arg.equals(3)") - public Object conditionalUpdate(Object arg) { - return arg; - } - - public Object nullValue(Object arg1) { - nullInvocations.incrementAndGet(); - return null; - } - - public Number nullInvocations() { - return nullInvocations.get(); - } - - public Long throwChecked(Object arg1) throws Exception { - throw new UnsupportedOperationException(arg1.toString()); - } - - public Long throwUnchecked(Object arg1) { - throw new UnsupportedOperationException(); - } - - // multi annotations - - @Caching(cacheable = { @Cacheable("primary"), @Cacheable("secondary") }) - public Object multiCache(Object arg1) { - return counter.getAndIncrement(); - } - - @Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0"), @CacheEvict(value = "primary", key = "#p0 + 'A'") }) - public Object multiEvict(Object arg1) { - return counter.getAndIncrement(); - } - - @Caching(cacheable = { @Cacheable(value = "primary", key = "#root.methodName") }, evict = { @CacheEvict("secondary") }) - public Object multiCacheAndEvict(Object arg1) { - return counter.getAndIncrement(); - } - - @Caching(cacheable = { @Cacheable(value = "primary", condition = "#p0 == 3") }, evict = { @CacheEvict("secondary") }) - public Object multiConditionalCacheAndEvict(Object arg1) { - return counter.getAndIncrement(); - } - - @Caching(put = { @CachePut("primary"), @CachePut("secondary") }) - public Object multiUpdate(Object arg1) { - return arg1; - } +/* + * Copyright 2010-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache.config; + +import java.util.concurrent.atomic.AtomicLong; + +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; + +/** + * @author Costin Leau + */ +@Cacheable("default") +public class AnnotatedClassCacheableService implements CacheableService { + + private final AtomicLong counter = new AtomicLong(); + public static final AtomicLong nullInvocations = new AtomicLong(); + + public Object cache(Object arg1) { + return counter.getAndIncrement(); + } + + public Object conditional(int field) { + return null; + } + + @CacheEvict("default") + public void invalidate(Object arg1) { + } + + @CacheEvict("default") + public void evictWithException(Object arg1) { + throw new RuntimeException("exception thrown - evict should NOT occur"); + } + + @CacheEvict(value = "default", allEntries = true) + public void evictAll(Object arg1) { + } + + @CacheEvict(value = "default", beforeInvocation = true) + public void evictEarly(Object arg1) { + throw new RuntimeException("exception thrown - evict should still occur"); + } + + @CacheEvict(value = "default", key = "#p0") + public void evict(Object arg1, Object arg2) { + } + + @CacheEvict(value = "default", key = "#p0", beforeInvocation = true) + public void invalidateEarly(Object arg1, Object arg2) { + throw new RuntimeException("exception thrown - evict should still occur"); + } + + @Cacheable(value = "default", key = "#p0") + public Object key(Object arg1, Object arg2) { + return counter.getAndIncrement(); + } + + @Cacheable(value = "default", key = "#root.methodName + #root.caches[0].name") + public Object name(Object arg1) { + return counter.getAndIncrement(); + } + + @Cacheable(value = "default", key = "#root.methodName + #root.method.name + #root.targetClass + #root.target") + public Object rootVars(Object arg1) { + return counter.getAndIncrement(); + } + + @CachePut("default") + public Object update(Object arg1) { + return counter.getAndIncrement(); + } + + @CachePut(value = "default", condition = "#arg.equals(3)") + public Object conditionalUpdate(Object arg) { + return arg; + } + + public Object nullValue(Object arg1) { + nullInvocations.incrementAndGet(); + return null; + } + + public Number nullInvocations() { + return nullInvocations.get(); + } + + public Long throwChecked(Object arg1) throws Exception { + throw new UnsupportedOperationException(arg1.toString()); + } + + public Long throwUnchecked(Object arg1) { + throw new UnsupportedOperationException(); + } + + // multi annotations + + @Caching(cacheable = { @Cacheable("primary"), @Cacheable("secondary") }) + public Object multiCache(Object arg1) { + return counter.getAndIncrement(); + } + + @Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0"), @CacheEvict(value = "primary", key = "#p0 + 'A'") }) + public Object multiEvict(Object arg1) { + return counter.getAndIncrement(); + } + + @Caching(cacheable = { @Cacheable(value = "primary", key = "#root.methodName") }, evict = { @CacheEvict("secondary") }) + public Object multiCacheAndEvict(Object arg1) { + return counter.getAndIncrement(); + } + + @Caching(cacheable = { @Cacheable(value = "primary", condition = "#p0 == 3") }, evict = { @CacheEvict("secondary") }) + public Object multiConditionalCacheAndEvict(Object arg1) { + return counter.getAndIncrement(); + } + + @Caching(put = { @CachePut("primary"), @CachePut("secondary") }) + public Object multiUpdate(Object arg1) { + return arg1; + } } \ No newline at end of file diff --git a/org.springframework.context/src/test/java/org/springframework/cache/config/AnnotationNamespaceDrivenTests.java b/org.springframework.context/src/test/java/org/springframework/cache/config/AnnotationNamespaceDrivenTests.java index 06ec9e8dbd..44b931dfe6 100644 --- a/org.springframework.context/src/test/java/org/springframework/cache/config/AnnotationNamespaceDrivenTests.java +++ b/org.springframework.context/src/test/java/org/springframework/cache/config/AnnotationNamespaceDrivenTests.java @@ -1,44 +1,44 @@ -/* - * Copyright 2010-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cache.config; - -import junit.framework.Assert; - -import org.junit.Test; -import org.springframework.cache.interceptor.CacheInterceptor; -import org.springframework.context.ApplicationContext; -import org.springframework.context.support.GenericXmlApplicationContext; - -/** - * @author Costin Leau - * @author Chris Beams - */ -public class AnnotationNamespaceDrivenTests extends AbstractAnnotationTests { - - @Override - protected ApplicationContext getApplicationContext() { - return new GenericXmlApplicationContext( - "/org/springframework/cache/config/annotationDrivenCacheNamespace.xml"); - } - - @Test - public void testKeyStrategy() throws Exception { - CacheInterceptor ci = ctx.getBean("org.springframework.cache.interceptor.CacheInterceptor#0", - CacheInterceptor.class); - Assert.assertSame(ctx.getBean("keyGenerator"), ci.getKeyGenerator()); - } -} +/* + * Copyright 2010-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache.config; + +import junit.framework.Assert; + +import org.junit.Test; +import org.springframework.cache.interceptor.CacheInterceptor; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.GenericXmlApplicationContext; + +/** + * @author Costin Leau + * @author Chris Beams + */ +public class AnnotationNamespaceDrivenTests extends AbstractAnnotationTests { + + @Override + protected ApplicationContext getApplicationContext() { + return new GenericXmlApplicationContext( + "/org/springframework/cache/config/annotationDrivenCacheNamespace.xml"); + } + + @Test + public void testKeyStrategy() throws Exception { + CacheInterceptor ci = ctx.getBean("org.springframework.cache.interceptor.CacheInterceptor#0", + CacheInterceptor.class); + Assert.assertSame(ctx.getBean("keyGenerator"), ci.getKeyGenerator()); + } +} diff --git a/org.springframework.context/src/test/java/org/springframework/cache/config/AnnotationTests.java b/org.springframework.context/src/test/java/org/springframework/cache/config/AnnotationTests.java index 8de9d7bb52..04c07fd208 100644 --- a/org.springframework.context/src/test/java/org/springframework/cache/config/AnnotationTests.java +++ b/org.springframework.context/src/test/java/org/springframework/cache/config/AnnotationTests.java @@ -1,33 +1,33 @@ -/* - * Copyright 2010-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cache.config; - -import org.springframework.context.ApplicationContext; -import org.springframework.context.support.GenericXmlApplicationContext; - -/** - * @author Costin Leau - * @author Chris Beams - */ -public class AnnotationTests extends AbstractAnnotationTests { - - @Override - protected ApplicationContext getApplicationContext() { - return new GenericXmlApplicationContext( - "/org/springframework/cache/config/annotationDrivenCacheConfig.xml"); - } +/* + * Copyright 2010-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache.config; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.GenericXmlApplicationContext; + +/** + * @author Costin Leau + * @author Chris Beams + */ +public class AnnotationTests extends AbstractAnnotationTests { + + @Override + protected ApplicationContext getApplicationContext() { + return new GenericXmlApplicationContext( + "/org/springframework/cache/config/annotationDrivenCacheConfig.xml"); + } } \ No newline at end of file diff --git a/org.springframework.context/src/test/java/org/springframework/cache/config/CacheAdviceNamespaceTests.java b/org.springframework.context/src/test/java/org/springframework/cache/config/CacheAdviceNamespaceTests.java index 09dcf34607..e91a721b0c 100644 --- a/org.springframework.context/src/test/java/org/springframework/cache/config/CacheAdviceNamespaceTests.java +++ b/org.springframework.context/src/test/java/org/springframework/cache/config/CacheAdviceNamespaceTests.java @@ -1,42 +1,42 @@ -/* - * Copyright 2010-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cache.config; - -import org.junit.Assert; -import org.junit.Test; -import org.springframework.cache.interceptor.CacheInterceptor; -import org.springframework.context.ApplicationContext; -import org.springframework.context.support.GenericXmlApplicationContext; - -/** - * @author Costin Leau - * @author Chris Beams - */ -public class CacheAdviceNamespaceTests extends AbstractAnnotationTests { - - @Override - protected ApplicationContext getApplicationContext() { - return new GenericXmlApplicationContext( - "/org/springframework/cache/config/cache-advice.xml"); - } - - @Test - public void testKeyStrategy() throws Exception { - CacheInterceptor bean = ctx.getBean("cacheAdviceClass", CacheInterceptor.class); - Assert.assertSame(ctx.getBean("keyGenerator"), bean.getKeyGenerator()); - } -} +/* + * Copyright 2010-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache.config; + +import org.junit.Assert; +import org.junit.Test; +import org.springframework.cache.interceptor.CacheInterceptor; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.GenericXmlApplicationContext; + +/** + * @author Costin Leau + * @author Chris Beams + */ +public class CacheAdviceNamespaceTests extends AbstractAnnotationTests { + + @Override + protected ApplicationContext getApplicationContext() { + return new GenericXmlApplicationContext( + "/org/springframework/cache/config/cache-advice.xml"); + } + + @Test + public void testKeyStrategy() throws Exception { + CacheInterceptor bean = ctx.getBean("cacheAdviceClass", CacheInterceptor.class); + Assert.assertSame(ctx.getBean("keyGenerator"), bean.getKeyGenerator()); + } +} diff --git a/org.springframework.context/src/test/java/org/springframework/cache/config/CacheableService.java b/org.springframework.context/src/test/java/org/springframework/cache/config/CacheableService.java index 1d03d9dbc5..870bdde66b 100644 --- a/org.springframework.context/src/test/java/org/springframework/cache/config/CacheableService.java +++ b/org.springframework.context/src/test/java/org/springframework/cache/config/CacheableService.java @@ -1,70 +1,70 @@ -/* - * Copyright 2010-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cache.config; - -/** - * Basic service interface. - * - * @author Costin Leau - */ -public interface CacheableService { - - T cache(Object arg1); - - void invalidate(Object arg1); - - void evictEarly(Object arg1); - - void evictAll(Object arg1); - - void evictWithException(Object arg1); - - void evict(Object arg1, Object arg2); - - void invalidateEarly(Object arg1, Object arg2); - - T conditional(int field); - - T key(Object arg1, Object arg2); - - T name(Object arg1); - - T nullValue(Object arg1); - - T update(Object arg1); - - T conditionalUpdate(Object arg2); - - Number nullInvocations(); - - T rootVars(Object arg1); - - T throwChecked(Object arg1) throws Exception; - - T throwUnchecked(Object arg1); - - // multi annotations - T multiCache(Object arg1); - - T multiEvict(Object arg1); - - T multiCacheAndEvict(Object arg1); - - T multiConditionalCacheAndEvict(Object arg1); - - T multiUpdate(Object arg1); +/* + * Copyright 2010-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache.config; + +/** + * Basic service interface. + * + * @author Costin Leau + */ +public interface CacheableService { + + T cache(Object arg1); + + void invalidate(Object arg1); + + void evictEarly(Object arg1); + + void evictAll(Object arg1); + + void evictWithException(Object arg1); + + void evict(Object arg1, Object arg2); + + void invalidateEarly(Object arg1, Object arg2); + + T conditional(int field); + + T key(Object arg1, Object arg2); + + T name(Object arg1); + + T nullValue(Object arg1); + + T update(Object arg1); + + T conditionalUpdate(Object arg2); + + Number nullInvocations(); + + T rootVars(Object arg1); + + T throwChecked(Object arg1) throws Exception; + + T throwUnchecked(Object arg1); + + // multi annotations + T multiCache(Object arg1); + + T multiEvict(Object arg1); + + T multiCacheAndEvict(Object arg1); + + T multiConditionalCacheAndEvict(Object arg1); + + T multiUpdate(Object arg1); } \ No newline at end of file diff --git a/org.springframework.context/src/test/java/org/springframework/cache/config/DefaultCacheableService.java b/org.springframework.context/src/test/java/org/springframework/cache/config/DefaultCacheableService.java index 0f7493c554..fc754b6c3d 100644 --- a/org.springframework.context/src/test/java/org/springframework/cache/config/DefaultCacheableService.java +++ b/org.springframework.context/src/test/java/org/springframework/cache/config/DefaultCacheableService.java @@ -1,144 +1,144 @@ -/* - * Copyright 2010-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cache.config; - -import java.util.concurrent.atomic.AtomicLong; - -import org.springframework.cache.annotation.CacheEvict; -import org.springframework.cache.annotation.CachePut; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.cache.annotation.Caching; - -/** - * Simple cacheable service - * - * @author Costin Leau - */ -public class DefaultCacheableService implements CacheableService { - - private final AtomicLong counter = new AtomicLong(); - private final AtomicLong nullInvocations = new AtomicLong(); - - @Cacheable("default") - public Long cache(Object arg1) { - return counter.getAndIncrement(); - } - - @CacheEvict("default") - public void invalidate(Object arg1) { - } - - @CacheEvict("default") - public void evictWithException(Object arg1) { - throw new RuntimeException("exception thrown - evict should NOT occur"); - } - - @CacheEvict(value = "default", allEntries = true) - public void evictAll(Object arg1) { - } - - @CacheEvict(value = "default", beforeInvocation = true) - public void evictEarly(Object arg1) { - throw new RuntimeException("exception thrown - evict should still occur"); - } - - @CacheEvict(value = "default", key = "#p0") - public void evict(Object arg1, Object arg2) { - } - - @CacheEvict(value = "default", key = "#p0", beforeInvocation = true) - public void invalidateEarly(Object arg1, Object arg2) { - throw new RuntimeException("exception thrown - evict should still occur"); - } - - @Cacheable(value = "default", condition = "#classField == 3") - public Long conditional(int classField) { - return counter.getAndIncrement(); - } - - @Cacheable(value = "default", key = "#p0") - public Long key(Object arg1, Object arg2) { - return counter.getAndIncrement(); - } - - @Cacheable(value = "default", key = "#root.methodName") - public Long name(Object arg1) { - return counter.getAndIncrement(); - } - - @Cacheable(value = "default", key = "#root.methodName + #root.method.name + #root.targetClass + #root.target") - public Long rootVars(Object arg1) { - return counter.getAndIncrement(); - } - - @CachePut("default") - public Long update(Object arg1) { - return counter.getAndIncrement(); - } - - @CachePut(value = "default", condition = "#arg.equals(3)") - public Long conditionalUpdate(Object arg) { - return Long.valueOf(arg.toString()); - } - - @Cacheable("default") - public Long nullValue(Object arg1) { - nullInvocations.incrementAndGet(); - return null; - } - - public Number nullInvocations() { - return nullInvocations.get(); - } - - @Cacheable("default") - public Long throwChecked(Object arg1) throws Exception { - throw new Exception(arg1.toString()); - } - - @Cacheable("default") - public Long throwUnchecked(Object arg1) { - throw new UnsupportedOperationException(arg1.toString()); - } - - // multi annotations - - @Caching(cacheable = { @Cacheable("primary"), @Cacheable("secondary") }) - public Long multiCache(Object arg1) { - return counter.getAndIncrement(); - } - - @Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0"), @CacheEvict(value = "primary", key = "#p0 + 'A'") }) - public Long multiEvict(Object arg1) { - return counter.getAndIncrement(); - } - - @Caching(cacheable = { @Cacheable(value = "primary", key = "#root.methodName") }, evict = { @CacheEvict("secondary") }) - public Long multiCacheAndEvict(Object arg1) { - return counter.getAndIncrement(); - } - - @Caching(cacheable = { @Cacheable(value = "primary", condition = "#p0 == 3") }, evict = { @CacheEvict("secondary") }) - public Long multiConditionalCacheAndEvict(Object arg1) { - return counter.getAndIncrement(); - } - - @Caching(put = { @CachePut("primary"), @CachePut("secondary") }) - public Long multiUpdate(Object arg1) { - return Long.valueOf(arg1.toString()); - } +/* + * Copyright 2010-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache.config; + +import java.util.concurrent.atomic.AtomicLong; + +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; + +/** + * Simple cacheable service + * + * @author Costin Leau + */ +public class DefaultCacheableService implements CacheableService { + + private final AtomicLong counter = new AtomicLong(); + private final AtomicLong nullInvocations = new AtomicLong(); + + @Cacheable("default") + public Long cache(Object arg1) { + return counter.getAndIncrement(); + } + + @CacheEvict("default") + public void invalidate(Object arg1) { + } + + @CacheEvict("default") + public void evictWithException(Object arg1) { + throw new RuntimeException("exception thrown - evict should NOT occur"); + } + + @CacheEvict(value = "default", allEntries = true) + public void evictAll(Object arg1) { + } + + @CacheEvict(value = "default", beforeInvocation = true) + public void evictEarly(Object arg1) { + throw new RuntimeException("exception thrown - evict should still occur"); + } + + @CacheEvict(value = "default", key = "#p0") + public void evict(Object arg1, Object arg2) { + } + + @CacheEvict(value = "default", key = "#p0", beforeInvocation = true) + public void invalidateEarly(Object arg1, Object arg2) { + throw new RuntimeException("exception thrown - evict should still occur"); + } + + @Cacheable(value = "default", condition = "#classField == 3") + public Long conditional(int classField) { + return counter.getAndIncrement(); + } + + @Cacheable(value = "default", key = "#p0") + public Long key(Object arg1, Object arg2) { + return counter.getAndIncrement(); + } + + @Cacheable(value = "default", key = "#root.methodName") + public Long name(Object arg1) { + return counter.getAndIncrement(); + } + + @Cacheable(value = "default", key = "#root.methodName + #root.method.name + #root.targetClass + #root.target") + public Long rootVars(Object arg1) { + return counter.getAndIncrement(); + } + + @CachePut("default") + public Long update(Object arg1) { + return counter.getAndIncrement(); + } + + @CachePut(value = "default", condition = "#arg.equals(3)") + public Long conditionalUpdate(Object arg) { + return Long.valueOf(arg.toString()); + } + + @Cacheable("default") + public Long nullValue(Object arg1) { + nullInvocations.incrementAndGet(); + return null; + } + + public Number nullInvocations() { + return nullInvocations.get(); + } + + @Cacheable("default") + public Long throwChecked(Object arg1) throws Exception { + throw new Exception(arg1.toString()); + } + + @Cacheable("default") + public Long throwUnchecked(Object arg1) { + throw new UnsupportedOperationException(arg1.toString()); + } + + // multi annotations + + @Caching(cacheable = { @Cacheable("primary"), @Cacheable("secondary") }) + public Long multiCache(Object arg1) { + return counter.getAndIncrement(); + } + + @Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0"), @CacheEvict(value = "primary", key = "#p0 + 'A'") }) + public Long multiEvict(Object arg1) { + return counter.getAndIncrement(); + } + + @Caching(cacheable = { @Cacheable(value = "primary", key = "#root.methodName") }, evict = { @CacheEvict("secondary") }) + public Long multiCacheAndEvict(Object arg1) { + return counter.getAndIncrement(); + } + + @Caching(cacheable = { @Cacheable(value = "primary", condition = "#p0 == 3") }, evict = { @CacheEvict("secondary") }) + public Long multiConditionalCacheAndEvict(Object arg1) { + return counter.getAndIncrement(); + } + + @Caching(put = { @CachePut("primary"), @CachePut("secondary") }) + public Long multiUpdate(Object arg1) { + return Long.valueOf(arg1.toString()); + } } \ No newline at end of file diff --git a/org.springframework.context/src/test/java/org/springframework/cache/config/SomeKeyGenerator.java b/org.springframework.context/src/test/java/org/springframework/cache/config/SomeKeyGenerator.java index fb38a7ea6d..7c1571f39b 100644 --- a/org.springframework.context/src/test/java/org/springframework/cache/config/SomeKeyGenerator.java +++ b/org.springframework.context/src/test/java/org/springframework/cache/config/SomeKeyGenerator.java @@ -1,23 +1,23 @@ -/* - * Copyright 2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cache.config; - -import org.springframework.cache.interceptor.DefaultKeyGenerator; - -public class SomeKeyGenerator extends DefaultKeyGenerator { - -} +/* + * Copyright 2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache.config; + +import org.springframework.cache.interceptor.DefaultKeyGenerator; + +public class SomeKeyGenerator extends DefaultKeyGenerator { + +} diff --git a/org.springframework.context/src/test/java/org/springframework/cache/ehcache/EhCacheCacheTests.java b/org.springframework.context/src/test/java/org/springframework/cache/ehcache/EhCacheCacheTests.java index e007e1f5c6..3b188a585a 100644 --- a/org.springframework.context/src/test/java/org/springframework/cache/ehcache/EhCacheCacheTests.java +++ b/org.springframework.context/src/test/java/org/springframework/cache/ehcache/EhCacheCacheTests.java @@ -1,62 +1,62 @@ -/* - * Copyright 2010-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cache.ehcache; - -import static org.junit.Assert.*; -import net.sf.ehcache.Ehcache; -import net.sf.ehcache.Element; - -import org.junit.Test; -import org.springframework.cache.Cache; -import org.springframework.cache.vendor.AbstractNativeCacheTests; - -/** - * Integration test for EhCache cache. - * - * @author Costin Leau - */ -public class EhCacheCacheTests extends AbstractNativeCacheTests { - - @Override - protected Ehcache createNativeCache() throws Exception { - EhCacheFactoryBean fb = new EhCacheFactoryBean(); - fb.setBeanName(CACHE_NAME); - fb.setCacheName(CACHE_NAME); - fb.afterPropertiesSet(); - return fb.getObject(); - } - - @Override - protected Cache createCache(Ehcache nativeCache) { - return new EhCacheCache(nativeCache); - } - - @Test - public void testExpiredElements() throws Exception { - String key = "brancusi"; - String value = "constantin"; - Element brancusi = new Element(key, value); - // ttl = 10s - brancusi.setTimeToLive(3); - nativeCache.put(brancusi); - - assertEquals(value, cache.get(key).get()); - // wait for the entry to expire - Thread.sleep(5 * 1000); - assertNull(cache.get(key)); - } +/* + * Copyright 2010-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache.ehcache; + +import static org.junit.Assert.*; +import net.sf.ehcache.Ehcache; +import net.sf.ehcache.Element; + +import org.junit.Test; +import org.springframework.cache.Cache; +import org.springframework.cache.vendor.AbstractNativeCacheTests; + +/** + * Integration test for EhCache cache. + * + * @author Costin Leau + */ +public class EhCacheCacheTests extends AbstractNativeCacheTests { + + @Override + protected Ehcache createNativeCache() throws Exception { + EhCacheFactoryBean fb = new EhCacheFactoryBean(); + fb.setBeanName(CACHE_NAME); + fb.setCacheName(CACHE_NAME); + fb.afterPropertiesSet(); + return fb.getObject(); + } + + @Override + protected Cache createCache(Ehcache nativeCache) { + return new EhCacheCache(nativeCache); + } + + @Test + public void testExpiredElements() throws Exception { + String key = "brancusi"; + String value = "constantin"; + Element brancusi = new Element(key, value); + // ttl = 10s + brancusi.setTimeToLive(3); + nativeCache.put(brancusi); + + assertEquals(value, cache.get(key).get()); + // wait for the entry to expire + Thread.sleep(5 * 1000); + assertNull(cache.get(key)); + } } \ No newline at end of file diff --git a/org.springframework.context/src/test/java/org/springframework/cache/vendor/AbstractNativeCacheTests.java b/org.springframework.context/src/test/java/org/springframework/cache/vendor/AbstractNativeCacheTests.java index e4bf138c19..7afc1d1c27 100644 --- a/org.springframework.context/src/test/java/org/springframework/cache/vendor/AbstractNativeCacheTests.java +++ b/org.springframework.context/src/test/java/org/springframework/cache/vendor/AbstractNativeCacheTests.java @@ -1,88 +1,88 @@ -/* - * Copyright 2010-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cache.vendor; - -import static org.junit.Assert.*; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.cache.Cache; - -/** - * Test for native cache implementations. - * - * @author Costin Leau - */ -public abstract class AbstractNativeCacheTests { - - protected T nativeCache; - protected Cache cache; - protected final static String CACHE_NAME = "testCache"; - - @Before - public void setUp() throws Exception { - nativeCache = createNativeCache(); - cache = createCache(nativeCache); - cache.clear(); - } - - - protected abstract T createNativeCache() throws Exception; - - protected abstract Cache createCache(T nativeCache); - - - @Test - public void testCacheName() throws Exception { - assertEquals(CACHE_NAME, cache.getName()); - } - - @Test - public void testNativeCache() throws Exception { - assertSame(nativeCache, cache.getNativeCache()); - } - - @Test - public void testCachePut() throws Exception { - Object key = "enescu"; - Object value = "george"; - - assertNull(cache.get(key)); - cache.put(key, value); - assertEquals(value, cache.get(key).get()); - } - - @Test - public void testCacheRemove() throws Exception { - Object key = "enescu"; - Object value = "george"; - - assertNull(cache.get(key)); - cache.put(key, value); - } - - @Test - public void testCacheClear() throws Exception { - assertNull(cache.get("enescu")); - cache.put("enescu", "george"); - assertNull(cache.get("vlaicu")); - cache.put("vlaicu", "aurel"); - cache.clear(); - assertNull(cache.get("vlaicu")); - assertNull(cache.get("enescu")); - } +/* + * Copyright 2010-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cache.vendor; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.cache.Cache; + +/** + * Test for native cache implementations. + * + * @author Costin Leau + */ +public abstract class AbstractNativeCacheTests { + + protected T nativeCache; + protected Cache cache; + protected final static String CACHE_NAME = "testCache"; + + @Before + public void setUp() throws Exception { + nativeCache = createNativeCache(); + cache = createCache(nativeCache); + cache.clear(); + } + + + protected abstract T createNativeCache() throws Exception; + + protected abstract Cache createCache(T nativeCache); + + + @Test + public void testCacheName() throws Exception { + assertEquals(CACHE_NAME, cache.getName()); + } + + @Test + public void testNativeCache() throws Exception { + assertSame(nativeCache, cache.getNativeCache()); + } + + @Test + public void testCachePut() throws Exception { + Object key = "enescu"; + Object value = "george"; + + assertNull(cache.get(key)); + cache.put(key, value); + assertEquals(value, cache.get(key).get()); + } + + @Test + public void testCacheRemove() throws Exception { + Object key = "enescu"; + Object value = "george"; + + assertNull(cache.get(key)); + cache.put(key, value); + } + + @Test + public void testCacheClear() throws Exception { + assertNull(cache.get("enescu")); + cache.put("enescu", "george"); + assertNull(cache.get("vlaicu")); + cache.put("vlaicu", "aurel"); + cache.clear(); + assertNull(cache.get("vlaicu")); + assertNull(cache.get("enescu")); + } } \ No newline at end of file diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/BeanAge.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/BeanAge.java index 514404b5c8..7d53b3a2cd 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/BeanAge.java +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/BeanAge.java @@ -1,16 +1,16 @@ -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.beans.factory.annotation.Qualifier; - - -@Target({ElementType.METHOD, ElementType.PARAMETER}) -@Retention(RetentionPolicy.RUNTIME) -@Qualifier -public @interface BeanAge { - int value(); -} +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.beans.factory.annotation.Qualifier; + + +@Target({ElementType.METHOD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@Qualifier +public @interface BeanAge { + int value(); +} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/ClassPathFactoryBeanDefinitionScannerTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/ClassPathFactoryBeanDefinitionScannerTests.java index a19fa4ed84..36d950e110 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/ClassPathFactoryBeanDefinitionScannerTests.java +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/ClassPathFactoryBeanDefinitionScannerTests.java @@ -1,95 +1,95 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.annotation; - -import junit.framework.TestCase; - -import org.springframework.aop.scope.ScopedObject; -import org.springframework.aop.support.AopUtils; -import org.springframework.beans.TestBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.config.SimpleMapScope; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.context.annotation4.DependencyBean; -import org.springframework.context.annotation4.FactoryMethodComponent; -import org.springframework.context.support.GenericApplicationContext; -import org.springframework.util.ClassUtils; - -/** - * @author Mark Pollack - * @author Juergen Hoeller - */ -public class ClassPathFactoryBeanDefinitionScannerTests extends TestCase { - - private static final String BASE_PACKAGE = FactoryMethodComponent.class.getPackage().getName(); - - - public void testSingletonScopedFactoryMethod() { - GenericApplicationContext context = new GenericApplicationContext(); - ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); - - context.getBeanFactory().registerScope("request", new SimpleMapScope()); - - scanner.scan(BASE_PACKAGE); - context.registerBeanDefinition("clientBean", new RootBeanDefinition(QualifiedClientBean.class)); - context.refresh(); - - FactoryMethodComponent fmc = context.getBean("factoryMethodComponent", FactoryMethodComponent.class); - assertFalse(fmc.getClass().getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)); - - TestBean tb = (TestBean)context.getBean("publicInstance"); //2 - assertEquals("publicInstance", tb.getName()); - TestBean tb2 = (TestBean)context.getBean("publicInstance"); //2 - assertEquals("publicInstance", tb2.getName()); - assertSame(tb2, tb); - - tb = (TestBean)context.getBean("protectedInstance"); //3 - assertEquals("protectedInstance", tb.getName()); - assertSame(tb, context.getBean("protectedInstance")); - assertEquals("0", tb.getCountry()); - tb2 = context.getBean("protectedInstance", TestBean.class); //3 - assertEquals("protectedInstance", tb2.getName()); - assertSame(tb2, tb); - - tb = context.getBean("privateInstance", TestBean.class); //4 - assertEquals("privateInstance", tb.getName()); - assertEquals(1, tb.getAge()); - tb2 = context.getBean("privateInstance", TestBean.class); //4 - assertEquals(2, tb2.getAge()); - assertNotSame(tb2, tb); - - Object bean = context.getBean("requestScopedInstance"); //5 - assertTrue(AopUtils.isCglibProxy(bean)); - assertTrue(bean instanceof ScopedObject); - - QualifiedClientBean clientBean = context.getBean("clientBean", QualifiedClientBean.class); - assertSame(clientBean.testBean, context.getBean("publicInstance")); - assertSame(clientBean.dependencyBean, context.getBean("dependencyBean")); - } - - - public static class QualifiedClientBean { - - @Autowired @Qualifier("public") - public TestBean testBean; - - @Autowired - public DependencyBean dependencyBean; - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import junit.framework.TestCase; + +import org.springframework.aop.scope.ScopedObject; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.config.SimpleMapScope; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.annotation4.DependencyBean; +import org.springframework.context.annotation4.FactoryMethodComponent; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.util.ClassUtils; + +/** + * @author Mark Pollack + * @author Juergen Hoeller + */ +public class ClassPathFactoryBeanDefinitionScannerTests extends TestCase { + + private static final String BASE_PACKAGE = FactoryMethodComponent.class.getPackage().getName(); + + + public void testSingletonScopedFactoryMethod() { + GenericApplicationContext context = new GenericApplicationContext(); + ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context); + + context.getBeanFactory().registerScope("request", new SimpleMapScope()); + + scanner.scan(BASE_PACKAGE); + context.registerBeanDefinition("clientBean", new RootBeanDefinition(QualifiedClientBean.class)); + context.refresh(); + + FactoryMethodComponent fmc = context.getBean("factoryMethodComponent", FactoryMethodComponent.class); + assertFalse(fmc.getClass().getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)); + + TestBean tb = (TestBean)context.getBean("publicInstance"); //2 + assertEquals("publicInstance", tb.getName()); + TestBean tb2 = (TestBean)context.getBean("publicInstance"); //2 + assertEquals("publicInstance", tb2.getName()); + assertSame(tb2, tb); + + tb = (TestBean)context.getBean("protectedInstance"); //3 + assertEquals("protectedInstance", tb.getName()); + assertSame(tb, context.getBean("protectedInstance")); + assertEquals("0", tb.getCountry()); + tb2 = context.getBean("protectedInstance", TestBean.class); //3 + assertEquals("protectedInstance", tb2.getName()); + assertSame(tb2, tb); + + tb = context.getBean("privateInstance", TestBean.class); //4 + assertEquals("privateInstance", tb.getName()); + assertEquals(1, tb.getAge()); + tb2 = context.getBean("privateInstance", TestBean.class); //4 + assertEquals(2, tb2.getAge()); + assertNotSame(tb2, tb); + + Object bean = context.getBean("requestScopedInstance"); //5 + assertTrue(AopUtils.isCglibProxy(bean)); + assertTrue(bean instanceof ScopedObject); + + QualifiedClientBean clientBean = context.getBean("clientBean", QualifiedClientBean.class); + assertSame(clientBean.testBean, context.getBean("publicInstance")); + assertSame(clientBean.dependencyBean, context.getBean("dependencyBean")); + } + + + public static class QualifiedClientBean { + + @Autowired @Qualifier("public") + public TestBean testBean; + + @Autowired + public DependencyBean dependencyBean; + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/FooServiceDependentConverter.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/FooServiceDependentConverter.java index 16e2773f9f..4546a22de0 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/FooServiceDependentConverter.java +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/FooServiceDependentConverter.java @@ -1,38 +1,38 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.annotation; - -import example.scannable.FooService; - -import org.springframework.core.convert.converter.Converter; - -/** - * @author Juergen Hoeller - */ -public class FooServiceDependentConverter implements Converter { - - private FooService fooService; - - public void setFooService(FooService fooService) { - this.fooService = fooService; - } - - public org.springframework.beans.TestBean convert(String source) { - return new org.springframework.beans.TestBean(source); - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation; + +import example.scannable.FooService; + +import org.springframework.core.convert.converter.Converter; + +/** + * @author Juergen Hoeller + */ +public class FooServiceDependentConverter implements Converter { + + private FooService fooService; + + public void setFooService(FooService fooService) { + this.fooService = fooService; + } + + public org.springframework.beans.TestBean convert(String source) { + return new org.springframework.beans.TestBean(source); + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/jsr330/SpringAtInjectTck.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/jsr330/SpringAtInjectTck.java index 860430c347..80caecf6c5 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/jsr330/SpringAtInjectTck.java +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/jsr330/SpringAtInjectTck.java @@ -1,63 +1,63 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.annotation.jsr330; - -import junit.framework.Test; -import org.atinject.tck.Tck; -import org.atinject.tck.auto.Car; -import org.atinject.tck.auto.Convertible; -import org.atinject.tck.auto.Drivers; -import org.atinject.tck.auto.DriversSeat; -import org.atinject.tck.auto.FuelTank; -import org.atinject.tck.auto.Seat; -import org.atinject.tck.auto.Tire; -import org.atinject.tck.auto.V8Engine; -import org.atinject.tck.auto.accessories.Cupholder; -import org.atinject.tck.auto.accessories.SpareTire; - -import org.springframework.context.annotation.AnnotatedBeanDefinitionReader; -import org.springframework.context.annotation.Jsr330ScopeMetadataResolver; -import org.springframework.context.annotation.Primary; -import org.springframework.context.support.GenericApplicationContext; - -/** - * @author Juergen Hoeller - * @since 3.0 - */ -public class SpringAtInjectTck { - - public static Test suite() { - GenericApplicationContext ac = new GenericApplicationContext(); - AnnotatedBeanDefinitionReader bdr = new AnnotatedBeanDefinitionReader(ac); - bdr.setScopeMetadataResolver(new Jsr330ScopeMetadataResolver()); - - bdr.registerBean(Convertible.class); - bdr.registerBean(DriversSeat.class, Drivers.class); - bdr.registerBean(Seat.class, Primary.class); - bdr.registerBean(V8Engine.class); - bdr.registerBean(SpareTire.class, "spare"); - bdr.registerBean(Cupholder.class); - bdr.registerBean(Tire.class, Primary.class); - bdr.registerBean(FuelTank.class); - - ac.refresh(); - Car car = ac.getBean(Car.class); - - return Tck.testsFor(car, false, true); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation.jsr330; + +import junit.framework.Test; +import org.atinject.tck.Tck; +import org.atinject.tck.auto.Car; +import org.atinject.tck.auto.Convertible; +import org.atinject.tck.auto.Drivers; +import org.atinject.tck.auto.DriversSeat; +import org.atinject.tck.auto.FuelTank; +import org.atinject.tck.auto.Seat; +import org.atinject.tck.auto.Tire; +import org.atinject.tck.auto.V8Engine; +import org.atinject.tck.auto.accessories.Cupholder; +import org.atinject.tck.auto.accessories.SpareTire; + +import org.springframework.context.annotation.AnnotatedBeanDefinitionReader; +import org.springframework.context.annotation.Jsr330ScopeMetadataResolver; +import org.springframework.context.annotation.Primary; +import org.springframework.context.support.GenericApplicationContext; + +/** + * @author Juergen Hoeller + * @since 3.0 + */ +public class SpringAtInjectTck { + + public static Test suite() { + GenericApplicationContext ac = new GenericApplicationContext(); + AnnotatedBeanDefinitionReader bdr = new AnnotatedBeanDefinitionReader(ac); + bdr.setScopeMetadataResolver(new Jsr330ScopeMetadataResolver()); + + bdr.registerBean(Convertible.class); + bdr.registerBean(DriversSeat.class, Drivers.class); + bdr.registerBean(Seat.class, Primary.class); + bdr.registerBean(V8Engine.class); + bdr.registerBean(SpareTire.class, "spare"); + bdr.registerBean(Cupholder.class); + bdr.registerBean(Tire.class, Primary.class); + bdr.registerBean(FuelTank.class); + + ac.refresh(); + Car car = ac.getBean(Car.class); + + return Tck.testsFor(car, false, true); + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation4/DependencyBean.java b/org.springframework.context/src/test/java/org/springframework/context/annotation4/DependencyBean.java index 33f3634dc4..c6e00ee243 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation4/DependencyBean.java +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation4/DependencyBean.java @@ -1,27 +1,27 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.annotation4; - -import org.springframework.stereotype.Component; - -/** - * @author Juergen Hoeller - */ -@Component -public class DependencyBean { - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation4; + +import org.springframework.stereotype.Component; + +/** + * @author Juergen Hoeller + */ +@Component +public class DependencyBean { + +} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation4/FactoryMethodComponent.java b/org.springframework.context/src/test/java/org/springframework/context/annotation4/FactoryMethodComponent.java index fbf5b7e6d6..125c77c636 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation4/FactoryMethodComponent.java +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation4/FactoryMethodComponent.java @@ -1,77 +1,77 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.annotation4; - -import org.springframework.beans.TestBean; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.BeanAge; -import org.springframework.context.annotation.Scope; -import org.springframework.context.annotation.ScopedProxyMode; -import org.springframework.stereotype.Component; - -/** - * Class used to test the functionality of factory method bean definitions - * declared inside a Spring component class. - * - * @author Mark Pollack - * @author Juergen Hoeller - */ -@Component -public final class FactoryMethodComponent { - - private int i; - - public static TestBean nullInstance() { - return null; - } - - @Bean @Qualifier("public") - public TestBean publicInstance() { - return new TestBean("publicInstance"); - } - - // to be ignored - public TestBean publicInstance(boolean doIt) { - return new TestBean("publicInstance"); - } - - @Bean @BeanAge(1) - protected TestBean protectedInstance(@Qualifier("public") TestBean spouse, @Value("#{privateInstance.age}") String country) { - TestBean tb = new TestBean("protectedInstance", 1); - tb.setSpouse(tb); - tb.setCountry(country); - return tb; - } - - @Bean @Scope("prototype") - private TestBean privateInstance() { - return new TestBean("privateInstance", i++); - } - - @Bean @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS) - public TestBean requestScopedInstance() { - return new TestBean("requestScopedInstance", 3); - } - - @Bean - public DependencyBean secondInstance() { - return new DependencyBean(); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation4; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.BeanAge; +import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; +import org.springframework.stereotype.Component; + +/** + * Class used to test the functionality of factory method bean definitions + * declared inside a Spring component class. + * + * @author Mark Pollack + * @author Juergen Hoeller + */ +@Component +public final class FactoryMethodComponent { + + private int i; + + public static TestBean nullInstance() { + return null; + } + + @Bean @Qualifier("public") + public TestBean publicInstance() { + return new TestBean("publicInstance"); + } + + // to be ignored + public TestBean publicInstance(boolean doIt) { + return new TestBean("publicInstance"); + } + + @Bean @BeanAge(1) + protected TestBean protectedInstance(@Qualifier("public") TestBean spouse, @Value("#{privateInstance.age}") String country) { + TestBean tb = new TestBean("protectedInstance", 1); + tb.setSpouse(tb); + tb.setCountry(country); + return tb; + } + + @Bean @Scope("prototype") + private TestBean privateInstance() { + return new TestBean("privateInstance", i++); + } + + @Bean @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS) + public TestBean requestScopedInstance() { + return new TestBean("requestScopedInstance", 3); + } + + @Bean + public DependencyBean secondInstance() { + return new DependencyBean(); + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation4/SimpleBean.java b/org.springframework.context/src/test/java/org/springframework/context/annotation4/SimpleBean.java index e6920157d4..b2cc55fec2 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation4/SimpleBean.java +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation4/SimpleBean.java @@ -1,36 +1,36 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.annotation4; - -import org.springframework.beans.TestBean; -import org.springframework.context.annotation.Bean; - -/** - * Class to test that @FactoryMethods are detected only when inside a class with an @Component - * class annotation. - * - * @author Mark Pollack - */ -public class SimpleBean { - - // This should *not* recognized as a bean since it does not reside inside an @Component - @Bean - public TestBean getPublicInstance() { - return new TestBean("publicInstance"); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation4; + +import org.springframework.beans.TestBean; +import org.springframework.context.annotation.Bean; + +/** + * Class to test that @FactoryMethods are detected only when inside a class with an @Component + * class annotation. + * + * @author Mark Pollack + */ +public class SimpleBean { + + // This should *not* recognized as a bean since it does not reside inside an @Component + @Bean + public TestBean getPublicInstance() { + return new TestBean("publicInstance"); + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation5/MyRepository.java b/org.springframework.context/src/test/java/org/springframework/context/annotation5/MyRepository.java index c7a8094f63..b28fd1a8ea 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation5/MyRepository.java +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation5/MyRepository.java @@ -1,37 +1,37 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.annotation5; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.context.annotation.Lazy; -import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Repository; - -/** - * @author Juergen Hoeller - */ -@Target({ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -@Repository -@Primary -@Lazy -public @interface MyRepository { -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.annotation5; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.context.annotation.Lazy; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Repository; + +/** + * @author Juergen Hoeller + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Repository +@Primary +@Lazy +public @interface MyRepository { +} diff --git a/org.springframework.context/src/test/java/org/springframework/context/expression/ApplicationContextExpressionTests.java b/org.springframework.context/src/test/java/org/springframework/context/expression/ApplicationContextExpressionTests.java index 7149bbca54..5eac00f54e 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/expression/ApplicationContextExpressionTests.java +++ b/org.springframework.context/src/test/java/org/springframework/context/expression/ApplicationContextExpressionTests.java @@ -1,432 +1,432 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.expression; - -import java.io.Serializable; -import java.security.AccessControlException; -import java.security.Permission; -import java.util.Properties; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import static org.junit.Assert.*; -import org.junit.Test; - -import org.springframework.beans.TestBean; -import org.springframework.beans.factory.ObjectFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; -import org.springframework.beans.factory.config.Scope; -import org.springframework.beans.factory.config.TypedStringValue; -import org.springframework.beans.factory.support.AutowireCandidateQualifier; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -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; -import org.springframework.util.SerializationTestUtils; -import org.springframework.util.StopWatch; - -/** - * @author Juergen Hoeller - * @since 3.0 - */ -public class ApplicationContextExpressionTests { - - private static final Log factoryLog = LogFactory.getLog(DefaultListableBeanFactory.class); - - @Test - public void genericApplicationContext() throws Exception { - GenericApplicationContext ac = new GenericApplicationContext(); - AnnotationConfigUtils.registerAnnotationConfigProcessors(ac); - - ac.getBeanFactory().registerScope("myScope", new Scope() { - public Object get(String name, ObjectFactory objectFactory) { - return objectFactory.getObject(); - } - public Object remove(String name) { - return null; - } - public void registerDestructionCallback(String name, Runnable callback) { - } - public Object resolveContextualObject(String key) { - if (key.equals("mySpecialAttr")) { - return "42"; - } - else { - return null; - } - } - public String getConversationId() { - return null; - } - }); - - PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); - Properties placeholders = new Properties(); - placeholders.setProperty("code", "123"); - ppc.setProperties(placeholders); - ac.addBeanFactoryPostProcessor(ppc); - - GenericBeanDefinition bd0 = new GenericBeanDefinition(); - bd0.setBeanClass(TestBean.class); - bd0.getPropertyValues().add("name", "myName"); - bd0.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "original")); - ac.registerBeanDefinition("tb0", bd0); - - GenericBeanDefinition bd1 = new GenericBeanDefinition(); - bd1.setBeanClass(TestBean.class); - bd1.setScope("myScope"); - bd1.getConstructorArgumentValues().addGenericArgumentValue("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ"); - bd1.getConstructorArgumentValues().addGenericArgumentValue("#{mySpecialAttr}"); - ac.registerBeanDefinition("tb1", bd1); - - GenericBeanDefinition bd2 = new GenericBeanDefinition(); - bd2.setBeanClass(TestBean.class); - bd2.setScope("myScope"); - bd2.getPropertyValues().add("name", "{ XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ }"); - bd2.getPropertyValues().add("age", "#{mySpecialAttr}"); - bd2.getPropertyValues().add("country", "${code} #{systemProperties.country}"); - ac.registerBeanDefinition("tb2", bd2); - - GenericBeanDefinition bd3 = new GenericBeanDefinition(); - bd3.setBeanClass(ValueTestBean.class); - bd3.setScope("myScope"); - ac.registerBeanDefinition("tb3", bd3); - - GenericBeanDefinition bd4 = new GenericBeanDefinition(); - bd4.setBeanClass(ConstructorValueTestBean.class); - bd4.setScope("myScope"); - ac.registerBeanDefinition("tb4", bd4); - - GenericBeanDefinition bd5 = new GenericBeanDefinition(); - bd5.setBeanClass(MethodValueTestBean.class); - bd5.setScope("myScope"); - ac.registerBeanDefinition("tb5", bd5); - - GenericBeanDefinition bd6 = new GenericBeanDefinition(); - bd6.setBeanClass(PropertyValueTestBean.class); - bd6.setScope("myScope"); - ac.registerBeanDefinition("tb6", bd6); - - System.getProperties().put("country", "UK"); - try { - ac.refresh(); - - TestBean tb0 = ac.getBean("tb0", TestBean.class); - - TestBean tb1 = ac.getBean("tb1", TestBean.class); - assertEquals("XXXmyNameYYY42ZZZ", tb1.getName()); - assertEquals(42, tb1.getAge()); - - TestBean tb2 = ac.getBean("tb2", TestBean.class); - assertEquals("{ XXXmyNameYYY42ZZZ }", tb2.getName()); - assertEquals(42, tb2.getAge()); - assertEquals("123 UK", tb2.getCountry()); - - ValueTestBean tb3 = ac.getBean("tb3", ValueTestBean.class); - assertEquals("XXXmyNameYYY42ZZZ", tb3.name); - assertEquals(42, tb3.age); - assertEquals("123 UK", tb3.country); - assertEquals("123 UK", tb3.countryFactory.getObject()); - System.getProperties().put("country", "US"); - assertEquals("123 UK", tb3.country); - assertEquals("123 US", tb3.countryFactory.getObject()); - System.getProperties().put("country", "UK"); - assertEquals("123 UK", tb3.country); - assertEquals("123 UK", tb3.countryFactory.getObject()); - assertSame(tb0, tb3.tb); - - tb3 = (ValueTestBean) SerializationTestUtils.serializeAndDeserialize(tb3); - assertEquals("123 UK", tb3.countryFactory.getObject()); - - ConstructorValueTestBean tb4 = ac.getBean("tb4", ConstructorValueTestBean.class); - assertEquals("XXXmyNameYYY42ZZZ", tb4.name); - assertEquals(42, tb4.age); - assertEquals("123 UK", tb4.country); - assertSame(tb0, tb4.tb); - - MethodValueTestBean tb5 = ac.getBean("tb5", MethodValueTestBean.class); - assertEquals("XXXmyNameYYY42ZZZ", tb5.name); - assertEquals(42, tb5.age); - assertEquals("123 UK", tb5.country); - assertSame(tb0, tb5.tb); - - PropertyValueTestBean tb6 = ac.getBean("tb6", PropertyValueTestBean.class); - assertEquals("XXXmyNameYYY42ZZZ", tb6.name); - assertEquals(42, tb6.age); - assertEquals("123 UK", tb6.country); - assertSame(tb0, tb6.tb); - } - finally { - System.getProperties().remove("country"); - } - } - - @Test - public void prototypeCreationReevaluatesExpressions() { - GenericApplicationContext ac = new GenericApplicationContext(); - AnnotationConfigUtils.registerAnnotationConfigProcessors(ac); - RootBeanDefinition rbd = new RootBeanDefinition(PrototypeTestBean.class); - rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); - rbd.getPropertyValues().add("country", "#{systemProperties.country}"); - rbd.getPropertyValues().add("country2", new TypedStringValue("#{systemProperties.country}")); - ac.registerBeanDefinition("test", rbd); - ac.refresh(); - - try { - System.getProperties().put("name", "juergen1"); - System.getProperties().put("country", "UK1"); - PrototypeTestBean tb = (PrototypeTestBean) ac.getBean("test"); - assertEquals("juergen1", tb.getName()); - assertEquals("UK1", tb.getCountry()); - assertEquals("UK1", tb.getCountry2()); - - System.getProperties().put("name", "juergen2"); - System.getProperties().put("country", "UK2"); - tb = (PrototypeTestBean) ac.getBean("test"); - assertEquals("juergen2", tb.getName()); - assertEquals("UK2", tb.getCountry()); - assertEquals("UK2", tb.getCountry2()); - } - finally { - System.getProperties().remove("name"); - System.getProperties().remove("country"); - } - } - - @Test - public void prototypeCreationIsFastEnough() { - if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { - // Skip this test: Trace logging blows the time limit. - return; - } - GenericApplicationContext ac = new GenericApplicationContext(); - RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class); - rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); - rbd.getConstructorArgumentValues().addGenericArgumentValue("#{systemProperties.name}"); - rbd.getPropertyValues().add("country", "#{systemProperties.country}"); - ac.registerBeanDefinition("test", rbd); - ac.refresh(); - StopWatch sw = new StopWatch(); - sw.start("prototype"); - System.getProperties().put("name", "juergen"); - System.getProperties().put("country", "UK"); - try { - for (int i = 0; i < 100000; i++) { - TestBean tb = (TestBean) ac.getBean("test"); - assertEquals("juergen", tb.getName()); - assertEquals("UK", tb.getCountry()); - } - sw.stop(); - } - finally { - System.getProperties().remove("country"); - System.getProperties().remove("name"); - } - assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 6000); - } - - @Test - public void systemPropertiesSecurityManager() { - GenericApplicationContext ac = new GenericApplicationContext(); - AnnotationConfigUtils.registerAnnotationConfigProcessors(ac); - - GenericBeanDefinition bd = new GenericBeanDefinition(); - bd.setBeanClass(TestBean.class); - bd.getPropertyValues().add("country", "#{systemProperties.country}"); - ac.registerBeanDefinition("tb", bd); - - SecurityManager oldSecurityManager = System.getSecurityManager(); - try { - System.setProperty("country", "NL"); - - SecurityManager securityManager = new SecurityManager() { - @Override - public void checkPropertiesAccess() { - throw new AccessControlException("Not Allowed"); - } - @Override - public void checkPermission(Permission perm) { - // allow everything else - } - }; - System.setSecurityManager(securityManager); - ac.refresh(); - - TestBean tb = ac.getBean("tb", TestBean.class); - assertEquals("NL", tb.getCountry()); - - } - finally { - System.setSecurityManager(oldSecurityManager); - System.getProperties().remove("country"); - } - } - - @Test - public void stringConcatenationWithDebugLogging() { - GenericApplicationContext ac = new GenericApplicationContext(); - AnnotationConfigUtils.registerAnnotationConfigProcessors(ac); - - GenericBeanDefinition bd = new GenericBeanDefinition(); - bd.setBeanClass(String.class); - bd.getConstructorArgumentValues().addGenericArgumentValue("test-#{ T(java.lang.System).currentTimeMillis() }"); - ac.registerBeanDefinition("str", bd); - ac.refresh(); - - String str = ac.getBean("str", String.class); - assertTrue(str.startsWith("test-")); - } - - - public static class ValueTestBean implements Serializable { - - @Autowired @Value("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ") - public String name; - - @Autowired @Value("#{mySpecialAttr}") - public int age; - - @Value("${code} #{systemProperties.country}") - public String country; - - @Value("${code} #{systemProperties.country}") - public ObjectFactory countryFactory; - - @Autowired @Qualifier("original") - public transient TestBean tb; - } - - - public static class ConstructorValueTestBean { - - public String name; - - public int age; - - public String country; - - public TestBean tb; - - @Autowired - public ConstructorValueTestBean( - @Value("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ") String name, - @Value("#{mySpecialAttr}") int age, - @Qualifier("original") TestBean tb, - @Value("${code} #{systemProperties.country}") String country) { - this.name = name; - this.age = age; - this.country = country; - this.tb = tb; - } - } - - - public static class MethodValueTestBean { - - public String name; - - public int age; - - public String country; - - public TestBean tb; - - @Autowired - public void configure( - @Qualifier("original") TestBean tb, - @Value("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ") String name, - @Value("#{mySpecialAttr}") int age, - @Value("${code} #{systemProperties.country}") String country) { - this.name = name; - this.age = age; - this.country = country; - this.tb = tb; - } - } - - - public static class PropertyValueTestBean { - - public String name; - - public int age; - - public String country; - - public TestBean tb; - - @Value("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ") - public void setName(String name) { - this.name = name; - } - - @Value("#{mySpecialAttr}") - public void setAge(int age) { - this.age = age; - } - - @Value("${code} #{systemProperties.country}") - public void setCountry(String country) { - this.country = country; - } - - @Autowired @Qualifier("original") - public void setTb(TestBean tb) { - this.tb = tb; - } - } - - - public static class PrototypeTestBean { - - public String name; - - public String country; - - public String country2; - - @Value("#{systemProperties.name}") - public void setName(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public void setCountry(String country) { - this.country = country; - } - - public String getCountry() { - return country; - } - - public void setCountry2(String country2) { - this.country2 = country2; - } - - public String getCountry2() { - return country2; - } - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.expression; + +import java.io.Serializable; +import java.security.AccessControlException; +import java.security.Permission; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import static org.junit.Assert.*; +import org.junit.Test; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.ObjectFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; +import org.springframework.beans.factory.config.Scope; +import org.springframework.beans.factory.config.TypedStringValue; +import org.springframework.beans.factory.support.AutowireCandidateQualifier; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +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; +import org.springframework.util.SerializationTestUtils; +import org.springframework.util.StopWatch; + +/** + * @author Juergen Hoeller + * @since 3.0 + */ +public class ApplicationContextExpressionTests { + + private static final Log factoryLog = LogFactory.getLog(DefaultListableBeanFactory.class); + + @Test + public void genericApplicationContext() throws Exception { + GenericApplicationContext ac = new GenericApplicationContext(); + AnnotationConfigUtils.registerAnnotationConfigProcessors(ac); + + ac.getBeanFactory().registerScope("myScope", new Scope() { + public Object get(String name, ObjectFactory objectFactory) { + return objectFactory.getObject(); + } + public Object remove(String name) { + return null; + } + public void registerDestructionCallback(String name, Runnable callback) { + } + public Object resolveContextualObject(String key) { + if (key.equals("mySpecialAttr")) { + return "42"; + } + else { + return null; + } + } + public String getConversationId() { + return null; + } + }); + + PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer(); + Properties placeholders = new Properties(); + placeholders.setProperty("code", "123"); + ppc.setProperties(placeholders); + ac.addBeanFactoryPostProcessor(ppc); + + GenericBeanDefinition bd0 = new GenericBeanDefinition(); + bd0.setBeanClass(TestBean.class); + bd0.getPropertyValues().add("name", "myName"); + bd0.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "original")); + ac.registerBeanDefinition("tb0", bd0); + + GenericBeanDefinition bd1 = new GenericBeanDefinition(); + bd1.setBeanClass(TestBean.class); + bd1.setScope("myScope"); + bd1.getConstructorArgumentValues().addGenericArgumentValue("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ"); + bd1.getConstructorArgumentValues().addGenericArgumentValue("#{mySpecialAttr}"); + ac.registerBeanDefinition("tb1", bd1); + + GenericBeanDefinition bd2 = new GenericBeanDefinition(); + bd2.setBeanClass(TestBean.class); + bd2.setScope("myScope"); + bd2.getPropertyValues().add("name", "{ XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ }"); + bd2.getPropertyValues().add("age", "#{mySpecialAttr}"); + bd2.getPropertyValues().add("country", "${code} #{systemProperties.country}"); + ac.registerBeanDefinition("tb2", bd2); + + GenericBeanDefinition bd3 = new GenericBeanDefinition(); + bd3.setBeanClass(ValueTestBean.class); + bd3.setScope("myScope"); + ac.registerBeanDefinition("tb3", bd3); + + GenericBeanDefinition bd4 = new GenericBeanDefinition(); + bd4.setBeanClass(ConstructorValueTestBean.class); + bd4.setScope("myScope"); + ac.registerBeanDefinition("tb4", bd4); + + GenericBeanDefinition bd5 = new GenericBeanDefinition(); + bd5.setBeanClass(MethodValueTestBean.class); + bd5.setScope("myScope"); + ac.registerBeanDefinition("tb5", bd5); + + GenericBeanDefinition bd6 = new GenericBeanDefinition(); + bd6.setBeanClass(PropertyValueTestBean.class); + bd6.setScope("myScope"); + ac.registerBeanDefinition("tb6", bd6); + + System.getProperties().put("country", "UK"); + try { + ac.refresh(); + + TestBean tb0 = ac.getBean("tb0", TestBean.class); + + TestBean tb1 = ac.getBean("tb1", TestBean.class); + assertEquals("XXXmyNameYYY42ZZZ", tb1.getName()); + assertEquals(42, tb1.getAge()); + + TestBean tb2 = ac.getBean("tb2", TestBean.class); + assertEquals("{ XXXmyNameYYY42ZZZ }", tb2.getName()); + assertEquals(42, tb2.getAge()); + assertEquals("123 UK", tb2.getCountry()); + + ValueTestBean tb3 = ac.getBean("tb3", ValueTestBean.class); + assertEquals("XXXmyNameYYY42ZZZ", tb3.name); + assertEquals(42, tb3.age); + assertEquals("123 UK", tb3.country); + assertEquals("123 UK", tb3.countryFactory.getObject()); + System.getProperties().put("country", "US"); + assertEquals("123 UK", tb3.country); + assertEquals("123 US", tb3.countryFactory.getObject()); + System.getProperties().put("country", "UK"); + assertEquals("123 UK", tb3.country); + assertEquals("123 UK", tb3.countryFactory.getObject()); + assertSame(tb0, tb3.tb); + + tb3 = (ValueTestBean) SerializationTestUtils.serializeAndDeserialize(tb3); + assertEquals("123 UK", tb3.countryFactory.getObject()); + + ConstructorValueTestBean tb4 = ac.getBean("tb4", ConstructorValueTestBean.class); + assertEquals("XXXmyNameYYY42ZZZ", tb4.name); + assertEquals(42, tb4.age); + assertEquals("123 UK", tb4.country); + assertSame(tb0, tb4.tb); + + MethodValueTestBean tb5 = ac.getBean("tb5", MethodValueTestBean.class); + assertEquals("XXXmyNameYYY42ZZZ", tb5.name); + assertEquals(42, tb5.age); + assertEquals("123 UK", tb5.country); + assertSame(tb0, tb5.tb); + + PropertyValueTestBean tb6 = ac.getBean("tb6", PropertyValueTestBean.class); + assertEquals("XXXmyNameYYY42ZZZ", tb6.name); + assertEquals(42, tb6.age); + assertEquals("123 UK", tb6.country); + assertSame(tb0, tb6.tb); + } + finally { + System.getProperties().remove("country"); + } + } + + @Test + public void prototypeCreationReevaluatesExpressions() { + GenericApplicationContext ac = new GenericApplicationContext(); + AnnotationConfigUtils.registerAnnotationConfigProcessors(ac); + RootBeanDefinition rbd = new RootBeanDefinition(PrototypeTestBean.class); + rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.getPropertyValues().add("country", "#{systemProperties.country}"); + rbd.getPropertyValues().add("country2", new TypedStringValue("#{systemProperties.country}")); + ac.registerBeanDefinition("test", rbd); + ac.refresh(); + + try { + System.getProperties().put("name", "juergen1"); + System.getProperties().put("country", "UK1"); + PrototypeTestBean tb = (PrototypeTestBean) ac.getBean("test"); + assertEquals("juergen1", tb.getName()); + assertEquals("UK1", tb.getCountry()); + assertEquals("UK1", tb.getCountry2()); + + System.getProperties().put("name", "juergen2"); + System.getProperties().put("country", "UK2"); + tb = (PrototypeTestBean) ac.getBean("test"); + assertEquals("juergen2", tb.getName()); + assertEquals("UK2", tb.getCountry()); + assertEquals("UK2", tb.getCountry2()); + } + finally { + System.getProperties().remove("name"); + System.getProperties().remove("country"); + } + } + + @Test + public void prototypeCreationIsFastEnough() { + if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) { + // Skip this test: Trace logging blows the time limit. + return; + } + GenericApplicationContext ac = new GenericApplicationContext(); + RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class); + rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + rbd.getConstructorArgumentValues().addGenericArgumentValue("#{systemProperties.name}"); + rbd.getPropertyValues().add("country", "#{systemProperties.country}"); + ac.registerBeanDefinition("test", rbd); + ac.refresh(); + StopWatch sw = new StopWatch(); + sw.start("prototype"); + System.getProperties().put("name", "juergen"); + System.getProperties().put("country", "UK"); + try { + for (int i = 0; i < 100000; i++) { + TestBean tb = (TestBean) ac.getBean("test"); + assertEquals("juergen", tb.getName()); + assertEquals("UK", tb.getCountry()); + } + sw.stop(); + } + finally { + System.getProperties().remove("country"); + System.getProperties().remove("name"); + } + assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 6000); + } + + @Test + public void systemPropertiesSecurityManager() { + GenericApplicationContext ac = new GenericApplicationContext(); + AnnotationConfigUtils.registerAnnotationConfigProcessors(ac); + + GenericBeanDefinition bd = new GenericBeanDefinition(); + bd.setBeanClass(TestBean.class); + bd.getPropertyValues().add("country", "#{systemProperties.country}"); + ac.registerBeanDefinition("tb", bd); + + SecurityManager oldSecurityManager = System.getSecurityManager(); + try { + System.setProperty("country", "NL"); + + SecurityManager securityManager = new SecurityManager() { + @Override + public void checkPropertiesAccess() { + throw new AccessControlException("Not Allowed"); + } + @Override + public void checkPermission(Permission perm) { + // allow everything else + } + }; + System.setSecurityManager(securityManager); + ac.refresh(); + + TestBean tb = ac.getBean("tb", TestBean.class); + assertEquals("NL", tb.getCountry()); + + } + finally { + System.setSecurityManager(oldSecurityManager); + System.getProperties().remove("country"); + } + } + + @Test + public void stringConcatenationWithDebugLogging() { + GenericApplicationContext ac = new GenericApplicationContext(); + AnnotationConfigUtils.registerAnnotationConfigProcessors(ac); + + GenericBeanDefinition bd = new GenericBeanDefinition(); + bd.setBeanClass(String.class); + bd.getConstructorArgumentValues().addGenericArgumentValue("test-#{ T(java.lang.System).currentTimeMillis() }"); + ac.registerBeanDefinition("str", bd); + ac.refresh(); + + String str = ac.getBean("str", String.class); + assertTrue(str.startsWith("test-")); + } + + + public static class ValueTestBean implements Serializable { + + @Autowired @Value("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ") + public String name; + + @Autowired @Value("#{mySpecialAttr}") + public int age; + + @Value("${code} #{systemProperties.country}") + public String country; + + @Value("${code} #{systemProperties.country}") + public ObjectFactory countryFactory; + + @Autowired @Qualifier("original") + public transient TestBean tb; + } + + + public static class ConstructorValueTestBean { + + public String name; + + public int age; + + public String country; + + public TestBean tb; + + @Autowired + public ConstructorValueTestBean( + @Value("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ") String name, + @Value("#{mySpecialAttr}") int age, + @Qualifier("original") TestBean tb, + @Value("${code} #{systemProperties.country}") String country) { + this.name = name; + this.age = age; + this.country = country; + this.tb = tb; + } + } + + + public static class MethodValueTestBean { + + public String name; + + public int age; + + public String country; + + public TestBean tb; + + @Autowired + public void configure( + @Qualifier("original") TestBean tb, + @Value("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ") String name, + @Value("#{mySpecialAttr}") int age, + @Value("${code} #{systemProperties.country}") String country) { + this.name = name; + this.age = age; + this.country = country; + this.tb = tb; + } + } + + + public static class PropertyValueTestBean { + + public String name; + + public int age; + + public String country; + + public TestBean tb; + + @Value("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ") + public void setName(String name) { + this.name = name; + } + + @Value("#{mySpecialAttr}") + public void setAge(int age) { + this.age = age; + } + + @Value("${code} #{systemProperties.country}") + public void setCountry(String country) { + this.country = country; + } + + @Autowired @Qualifier("original") + public void setTb(TestBean tb) { + this.tb = tb; + } + } + + + public static class PrototypeTestBean { + + public String name; + + public String country; + + public String country2; + + @Value("#{systemProperties.name}") + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getCountry() { + return country; + } + + public void setCountry2(String country2) { + this.country2 = country2; + } + + public String getCountry2() { + return country2; + } + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/context/support/GenericApplicationContextTests.java b/org.springframework.context/src/test/java/org/springframework/context/support/GenericApplicationContextTests.java index 67b3f54c7d..8587ff38ce 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/support/GenericApplicationContextTests.java +++ b/org.springframework.context/src/test/java/org/springframework/context/support/GenericApplicationContextTests.java @@ -1,36 +1,36 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.support; - -import org.junit.Test; - -import org.springframework.beans.factory.support.DefaultListableBeanFactory; - -/** - * @author Juergen Hoeller - * @author Chris Beams - */ -public class GenericApplicationContextTests { - - @Test - public void nullBeanRegistration() { - DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); - bf.registerSingleton("nullBean", null); - new GenericApplicationContext(bf).refresh(); - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.support; + +import org.junit.Test; + +import org.springframework.beans.factory.support.DefaultListableBeanFactory; + +/** + * @author Juergen Hoeller + * @author Chris Beams + */ +public class GenericApplicationContextTests { + + @Test + public void nullBeanRegistration() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerSingleton("nullBean", null); + new GenericApplicationContext(bf).refresh(); + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/context/support/ResourceConverter.java b/org.springframework.context/src/test/java/org/springframework/context/support/ResourceConverter.java index 84236dae1d..f5834e8e6f 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/support/ResourceConverter.java +++ b/org.springframework.context/src/test/java/org/springframework/context/support/ResourceConverter.java @@ -1,32 +1,32 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.support; - -import org.springframework.core.convert.converter.Converter; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; - -/** - * @author Juergen Hoeller - */ -public class ResourceConverter implements Converter { - - public Resource convert(String source) { - return new FileSystemResource(source + ".xml"); - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.support; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; + +/** + * @author Juergen Hoeller + */ +public class ResourceConverter implements Converter { + + public Resource convert(String source) { + return new FileSystemResource(source + ".xml"); + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/context/support/Spr7283Tests.java b/org.springframework.context/src/test/java/org/springframework/context/support/Spr7283Tests.java index c6ecdd4160..40255c0e68 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/support/Spr7283Tests.java +++ b/org.springframework.context/src/test/java/org/springframework/context/support/Spr7283Tests.java @@ -1,48 +1,48 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.support; - -import java.util.List; - -import static org.junit.Assert.*; -import org.junit.Test; - -/** - * @author Scott Andrews - * @author Juergen Hoeller - */ -public class Spr7283Tests { - - @Test - public void testListWithInconsistentElementType() { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spr7283.xml", getClass()); - List list = ctx.getBean("list", List.class); - assertEquals(2, list.size()); - assertTrue(list.get(0) instanceof A); - assertTrue(list.get(1) instanceof B); - } - - - public static class A { - public A() {} - } - - public static class B { - public B() {} - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.context.support; + +import java.util.List; + +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * @author Scott Andrews + * @author Juergen Hoeller + */ +public class Spr7283Tests { + + @Test + public void testListWithInconsistentElementType() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spr7283.xml", getClass()); + List list = ctx.getBean("list", List.class); + assertEquals(2, list.size()); + assertTrue(list.get(0) instanceof A); + assertTrue(list.get(1) instanceof B); + } + + + public static class A { + public A() {} + } + + public static class B { + public B() {} + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/jmx/export/annotation/AnnotationTestBeanFactory.java b/org.springframework.context/src/test/java/org/springframework/jmx/export/annotation/AnnotationTestBeanFactory.java index c8b71e2b61..c94cb07e06 100644 --- a/org.springframework.context/src/test/java/org/springframework/jmx/export/annotation/AnnotationTestBeanFactory.java +++ b/org.springframework.context/src/test/java/org/springframework/jmx/export/annotation/AnnotationTestBeanFactory.java @@ -1,45 +1,45 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.jmx.export.annotation; - -import org.springframework.beans.factory.FactoryBean; -import org.springframework.jmx.IJmxTestBean; - -/** - * @author Juergen Hoeller - */ -public class AnnotationTestBeanFactory implements FactoryBean { - - private final FactoryCreatedAnnotationTestBean instance = new FactoryCreatedAnnotationTestBean(); - - public AnnotationTestBeanFactory() { - this.instance.setName("FACTORY"); - } - - public IJmxTestBean getObject() throws Exception { - return this.instance; - } - - public Class getObjectType() { - return FactoryCreatedAnnotationTestBean.class; - } - - public boolean isSingleton() { - return true; - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jmx.export.annotation; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.jmx.IJmxTestBean; + +/** + * @author Juergen Hoeller + */ +public class AnnotationTestBeanFactory implements FactoryBean { + + private final FactoryCreatedAnnotationTestBean instance = new FactoryCreatedAnnotationTestBean(); + + public AnnotationTestBeanFactory() { + this.instance.setName("FACTORY"); + } + + public IJmxTestBean getObject() throws Exception { + return this.instance; + } + + public Class getObjectType() { + return FactoryCreatedAnnotationTestBean.class; + } + + public boolean isSingleton() { + return true; + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/jmx/export/annotation/FactoryCreatedAnnotationTestBean.java b/org.springframework.context/src/test/java/org/springframework/jmx/export/annotation/FactoryCreatedAnnotationTestBean.java index a8a9b3f670..2741a8b97c 100644 --- a/org.springframework.context/src/test/java/org/springframework/jmx/export/annotation/FactoryCreatedAnnotationTestBean.java +++ b/org.springframework.context/src/test/java/org/springframework/jmx/export/annotation/FactoryCreatedAnnotationTestBean.java @@ -1,25 +1,25 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.jmx.export.annotation; - -/** - * @author Juergen Hoeller - */ -@ManagedResource(objectName = "bean:name=testBean5") -public class FactoryCreatedAnnotationTestBean extends AnnotationTestBean { - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jmx.export.annotation; + +/** + * @author Juergen Hoeller + */ +@ManagedResource(objectName = "bean:name=testBean5") +public class FactoryCreatedAnnotationTestBean extends AnnotationTestBean { + +} diff --git a/org.springframework.context/src/test/java/org/springframework/scheduling/annotation/AsyncExecutionTests.java b/org.springframework.context/src/test/java/org/springframework/scheduling/annotation/AsyncExecutionTests.java index 9dbc91f7e9..da4436b35e 100644 --- a/org.springframework.context/src/test/java/org/springframework/scheduling/annotation/AsyncExecutionTests.java +++ b/org.springframework.context/src/test/java/org/springframework/scheduling/annotation/AsyncExecutionTests.java @@ -1,261 +1,261 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.scheduling.annotation; - -import java.util.concurrent.Future; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import org.junit.Test; - -import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.context.support.GenericApplicationContext; -import org.springframework.scheduling.annotation.AsyncResult; - -/** - * @author Juergen Hoeller - */ -public class AsyncExecutionTests { - - private static String originalThreadName; - - private static int listenerCalled = 0; - - private static int listenerConstructed = 0; - - - @Test - public void asyncMethods() throws Exception { - originalThreadName = Thread.currentThread().getName(); - GenericApplicationContext context = new GenericApplicationContext(); - context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncMethodBean.class)); - context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class)); - context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class)); - context.refresh(); - AsyncMethodBean asyncTest = context.getBean("asyncTest", AsyncMethodBean.class); - asyncTest.doNothing(5); - asyncTest.doSomething(10); - Future future = asyncTest.returnSomething(20); - assertEquals("20", future.get()); - } - - @Test - public void asyncClass() throws Exception { - originalThreadName = Thread.currentThread().getName(); - GenericApplicationContext context = new GenericApplicationContext(); - context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncClassBean.class)); - context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class)); - context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class)); - context.refresh(); - AsyncClassBean asyncTest = context.getBean("asyncTest", AsyncClassBean.class); - asyncTest.doSomething(10); - Future future = asyncTest.returnSomething(20); - assertEquals("20", future.get()); - } - - @Test - public void asyncInterface() throws Exception { - originalThreadName = Thread.currentThread().getName(); - GenericApplicationContext context = new GenericApplicationContext(); - context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncInterfaceBean.class)); - context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class)); - context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class)); - context.refresh(); - AsyncInterface asyncTest = context.getBean("asyncTest", AsyncInterface.class); - asyncTest.doSomething(10); - Future future = asyncTest.returnSomething(20); - assertEquals("20", future.get()); - } - - @Test - public void asyncMethodsInInterface() throws Exception { - originalThreadName = Thread.currentThread().getName(); - GenericApplicationContext context = new GenericApplicationContext(); - context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncMethodsInterfaceBean.class)); - context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class)); - context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class)); - context.refresh(); - AsyncMethodsInterface asyncTest = context.getBean("asyncTest", AsyncMethodsInterface.class); - asyncTest.doNothing(5); - asyncTest.doSomething(10); - Future future = asyncTest.returnSomething(20); - assertEquals("20", future.get()); - } - - @Test - public void asyncMethodListener() throws Exception { - originalThreadName = Thread.currentThread().getName(); - listenerCalled = 0; - GenericApplicationContext context = new GenericApplicationContext(); - context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncMethodListener.class)); - context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class)); - context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class)); - context.refresh(); - Thread.sleep(1000); - assertEquals(1, listenerCalled); - } - - @Test - public void asyncClassListener() throws Exception { - originalThreadName = Thread.currentThread().getName(); - listenerCalled = 0; - listenerConstructed = 0; - GenericApplicationContext context = new GenericApplicationContext(); - context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncClassListener.class)); - context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class)); - context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class)); - context.refresh(); - context.close(); - Thread.sleep(1000); - assertEquals(2, listenerCalled); - assertEquals(1, listenerConstructed); - } - - @Test - public void asyncPrototypeClassListener() throws Exception { - originalThreadName = Thread.currentThread().getName(); - listenerCalled = 0; - listenerConstructed = 0; - GenericApplicationContext context = new GenericApplicationContext(); - RootBeanDefinition listenerDef = new RootBeanDefinition(AsyncClassListener.class); - listenerDef.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); - context.registerBeanDefinition("asyncTest", listenerDef); - context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class)); - context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class)); - context.refresh(); - context.close(); - Thread.sleep(1000); - assertEquals(2, listenerCalled); - assertEquals(2, listenerConstructed); - } - - - public static class AsyncMethodBean { - - public void doNothing(int i) { - assertTrue(Thread.currentThread().getName().equals(originalThreadName)); - } - - @Async - public void doSomething(int i) { - System.out.println(Thread.currentThread().getName() + ": " + i); - assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); - } - - @Async - public Future returnSomething(int i) { - assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); - return new AsyncResult(Integer.toString(i)); - } - } - - - @Async - public static class AsyncClassBean { - - public void doSomething(int i) { - System.out.println(Thread.currentThread().getName() + ": " + i); - assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); - } - - public Future returnSomething(int i) { - assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); - return new AsyncResult(Integer.toString(i)); - } - } - - - @Async - public interface AsyncInterface { - - void doSomething(int i); - - Future returnSomething(int i); - } - - - public static class AsyncInterfaceBean implements AsyncInterface { - - public void doSomething(int i) { - System.out.println(Thread.currentThread().getName() + ": " + i); - assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); - } - - public Future returnSomething(int i) { - assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); - return new AsyncResult(Integer.toString(i)); - } - } - - - public interface AsyncMethodsInterface { - - void doNothing(int i); - - @Async - void doSomething(int i); - - @Async - Future returnSomething(int i); - } - - - public static class AsyncMethodsInterfaceBean implements AsyncMethodsInterface { - - public void doNothing(int i) { - assertTrue(Thread.currentThread().getName().equals(originalThreadName)); - } - - public void doSomething(int i) { - System.out.println(Thread.currentThread().getName() + ": " + i); - assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); - } - - public Future returnSomething(int i) { - assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); - return new AsyncResult(Integer.toString(i)); - } - } - - - public static class AsyncMethodListener implements ApplicationListener { - - @Async - public void onApplicationEvent(ApplicationEvent event) { - listenerCalled++; - assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); - } - } - - - @Async - public static class AsyncClassListener implements ApplicationListener { - - public AsyncClassListener() { - listenerConstructed++; - } - - public void onApplicationEvent(ApplicationEvent event) { - listenerCalled++; - assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); - } - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.scheduling.annotation; + +import java.util.concurrent.Future; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Test; + +import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.scheduling.annotation.AsyncResult; + +/** + * @author Juergen Hoeller + */ +public class AsyncExecutionTests { + + private static String originalThreadName; + + private static int listenerCalled = 0; + + private static int listenerConstructed = 0; + + + @Test + public void asyncMethods() throws Exception { + originalThreadName = Thread.currentThread().getName(); + GenericApplicationContext context = new GenericApplicationContext(); + context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncMethodBean.class)); + context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class)); + context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class)); + context.refresh(); + AsyncMethodBean asyncTest = context.getBean("asyncTest", AsyncMethodBean.class); + asyncTest.doNothing(5); + asyncTest.doSomething(10); + Future future = asyncTest.returnSomething(20); + assertEquals("20", future.get()); + } + + @Test + public void asyncClass() throws Exception { + originalThreadName = Thread.currentThread().getName(); + GenericApplicationContext context = new GenericApplicationContext(); + context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncClassBean.class)); + context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class)); + context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class)); + context.refresh(); + AsyncClassBean asyncTest = context.getBean("asyncTest", AsyncClassBean.class); + asyncTest.doSomething(10); + Future future = asyncTest.returnSomething(20); + assertEquals("20", future.get()); + } + + @Test + public void asyncInterface() throws Exception { + originalThreadName = Thread.currentThread().getName(); + GenericApplicationContext context = new GenericApplicationContext(); + context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncInterfaceBean.class)); + context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class)); + context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class)); + context.refresh(); + AsyncInterface asyncTest = context.getBean("asyncTest", AsyncInterface.class); + asyncTest.doSomething(10); + Future future = asyncTest.returnSomething(20); + assertEquals("20", future.get()); + } + + @Test + public void asyncMethodsInInterface() throws Exception { + originalThreadName = Thread.currentThread().getName(); + GenericApplicationContext context = new GenericApplicationContext(); + context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncMethodsInterfaceBean.class)); + context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class)); + context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class)); + context.refresh(); + AsyncMethodsInterface asyncTest = context.getBean("asyncTest", AsyncMethodsInterface.class); + asyncTest.doNothing(5); + asyncTest.doSomething(10); + Future future = asyncTest.returnSomething(20); + assertEquals("20", future.get()); + } + + @Test + public void asyncMethodListener() throws Exception { + originalThreadName = Thread.currentThread().getName(); + listenerCalled = 0; + GenericApplicationContext context = new GenericApplicationContext(); + context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncMethodListener.class)); + context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class)); + context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class)); + context.refresh(); + Thread.sleep(1000); + assertEquals(1, listenerCalled); + } + + @Test + public void asyncClassListener() throws Exception { + originalThreadName = Thread.currentThread().getName(); + listenerCalled = 0; + listenerConstructed = 0; + GenericApplicationContext context = new GenericApplicationContext(); + context.registerBeanDefinition("asyncTest", new RootBeanDefinition(AsyncClassListener.class)); + context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class)); + context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class)); + context.refresh(); + context.close(); + Thread.sleep(1000); + assertEquals(2, listenerCalled); + assertEquals(1, listenerConstructed); + } + + @Test + public void asyncPrototypeClassListener() throws Exception { + originalThreadName = Thread.currentThread().getName(); + listenerCalled = 0; + listenerConstructed = 0; + GenericApplicationContext context = new GenericApplicationContext(); + RootBeanDefinition listenerDef = new RootBeanDefinition(AsyncClassListener.class); + listenerDef.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + context.registerBeanDefinition("asyncTest", listenerDef); + context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class)); + context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class)); + context.refresh(); + context.close(); + Thread.sleep(1000); + assertEquals(2, listenerCalled); + assertEquals(2, listenerConstructed); + } + + + public static class AsyncMethodBean { + + public void doNothing(int i) { + assertTrue(Thread.currentThread().getName().equals(originalThreadName)); + } + + @Async + public void doSomething(int i) { + System.out.println(Thread.currentThread().getName() + ": " + i); + assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); + } + + @Async + public Future returnSomething(int i) { + assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); + return new AsyncResult(Integer.toString(i)); + } + } + + + @Async + public static class AsyncClassBean { + + public void doSomething(int i) { + System.out.println(Thread.currentThread().getName() + ": " + i); + assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); + } + + public Future returnSomething(int i) { + assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); + return new AsyncResult(Integer.toString(i)); + } + } + + + @Async + public interface AsyncInterface { + + void doSomething(int i); + + Future returnSomething(int i); + } + + + public static class AsyncInterfaceBean implements AsyncInterface { + + public void doSomething(int i) { + System.out.println(Thread.currentThread().getName() + ": " + i); + assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); + } + + public Future returnSomething(int i) { + assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); + return new AsyncResult(Integer.toString(i)); + } + } + + + public interface AsyncMethodsInterface { + + void doNothing(int i); + + @Async + void doSomething(int i); + + @Async + Future returnSomething(int i); + } + + + public static class AsyncMethodsInterfaceBean implements AsyncMethodsInterface { + + public void doNothing(int i) { + assertTrue(Thread.currentThread().getName().equals(originalThreadName)); + } + + public void doSomething(int i) { + System.out.println(Thread.currentThread().getName() + ": " + i); + assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); + } + + public Future returnSomething(int i) { + assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); + return new AsyncResult(Integer.toString(i)); + } + } + + + public static class AsyncMethodListener implements ApplicationListener { + + @Async + public void onApplicationEvent(ApplicationEvent event) { + listenerCalled++; + assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); + } + } + + + @Async + public static class AsyncClassListener implements ApplicationListener { + + public AsyncClassListener() { + listenerConstructed++; + } + + public void onApplicationEvent(ApplicationEvent event) { + listenerCalled++; + assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); + } + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/scripting/groovy/GroovyAspectIntegrationTests.java b/org.springframework.context/src/test/java/org/springframework/scripting/groovy/GroovyAspectIntegrationTests.java index 4bcc10e1a6..62f2d3223c 100644 --- a/org.springframework.context/src/test/java/org/springframework/scripting/groovy/GroovyAspectIntegrationTests.java +++ b/org.springframework.context/src/test/java/org/springframework/scripting/groovy/GroovyAspectIntegrationTests.java @@ -1,100 +1,100 @@ -package org.springframework.scripting.groovy; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import org.junit.After; -import org.junit.Test; -import org.springframework.context.support.GenericXmlApplicationContext; - -/** - * @author Dave Syer - */ -public class GroovyAspectIntegrationTests { - - private GenericXmlApplicationContext context; - - @After - public void close() { - if (context != null) { - context.close(); - } - } - - @Test - public void testJavaBean() { - - context = new GenericXmlApplicationContext(getClass(), getClass().getSimpleName()+"-java-context.xml"); - - TestService bean = context.getBean("javaBean", TestService.class); - LogUserAdvice logAdvice = context.getBean(LogUserAdvice.class); - - assertEquals(0, logAdvice.getCountThrows()); - try { - bean.sayHello(); - fail("Expected exception"); - } catch (RuntimeException e) { - assertEquals("TestServiceImpl", e.getMessage()); - } - assertEquals(1, logAdvice.getCountThrows()); - - } - - @Test - public void testGroovyBeanInterface() { - context = new GenericXmlApplicationContext(getClass(), getClass().getSimpleName()+"-groovy-interface-context.xml"); - - TestService bean = context.getBean("groovyBean", TestService.class); - LogUserAdvice logAdvice = context.getBean(LogUserAdvice.class); - - assertEquals(0, logAdvice.getCountThrows()); - try { - bean.sayHello(); - fail("Expected exception"); - } catch (RuntimeException e) { - assertEquals("GroovyServiceImpl", e.getMessage()); - } - assertEquals(1, logAdvice.getCountThrows()); - } - - - @Test - public void testGroovyBeanDynamic() { - - context = new GenericXmlApplicationContext(getClass(), getClass().getSimpleName()+"-groovy-dynamic-context.xml"); - - TestService bean = context.getBean("groovyBean", TestService.class); - LogUserAdvice logAdvice = context.getBean(LogUserAdvice.class); - - assertEquals(0, logAdvice.getCountThrows()); - try { - bean.sayHello(); - fail("Expected exception"); - } catch (RuntimeException e) { - assertEquals("GroovyServiceImpl", e.getMessage()); - } - // No proxy here because the pointcut only applies to the concrete class, not the interface - assertEquals(0, logAdvice.getCountThrows()); - assertEquals(0, logAdvice.getCountBefore()); - } - - @Test - public void testGroovyBeanProxyTargetClass() { - - context = new GenericXmlApplicationContext(getClass(), getClass().getSimpleName()+"-groovy-proxy-target-class-context.xml"); - - TestService bean = context.getBean("groovyBean", TestService.class); - LogUserAdvice logAdvice = context.getBean(LogUserAdvice.class); - - assertEquals(0, logAdvice.getCountThrows()); - try { - bean.sayHello(); - fail("Expected exception"); - } catch (TestException e) { - assertEquals("GroovyServiceImpl", e.getMessage()); - } - assertEquals(1, logAdvice.getCountBefore()); - assertEquals(1, logAdvice.getCountThrows()); - } - -} +package org.springframework.scripting.groovy; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.After; +import org.junit.Test; +import org.springframework.context.support.GenericXmlApplicationContext; + +/** + * @author Dave Syer + */ +public class GroovyAspectIntegrationTests { + + private GenericXmlApplicationContext context; + + @After + public void close() { + if (context != null) { + context.close(); + } + } + + @Test + public void testJavaBean() { + + context = new GenericXmlApplicationContext(getClass(), getClass().getSimpleName()+"-java-context.xml"); + + TestService bean = context.getBean("javaBean", TestService.class); + LogUserAdvice logAdvice = context.getBean(LogUserAdvice.class); + + assertEquals(0, logAdvice.getCountThrows()); + try { + bean.sayHello(); + fail("Expected exception"); + } catch (RuntimeException e) { + assertEquals("TestServiceImpl", e.getMessage()); + } + assertEquals(1, logAdvice.getCountThrows()); + + } + + @Test + public void testGroovyBeanInterface() { + context = new GenericXmlApplicationContext(getClass(), getClass().getSimpleName()+"-groovy-interface-context.xml"); + + TestService bean = context.getBean("groovyBean", TestService.class); + LogUserAdvice logAdvice = context.getBean(LogUserAdvice.class); + + assertEquals(0, logAdvice.getCountThrows()); + try { + bean.sayHello(); + fail("Expected exception"); + } catch (RuntimeException e) { + assertEquals("GroovyServiceImpl", e.getMessage()); + } + assertEquals(1, logAdvice.getCountThrows()); + } + + + @Test + public void testGroovyBeanDynamic() { + + context = new GenericXmlApplicationContext(getClass(), getClass().getSimpleName()+"-groovy-dynamic-context.xml"); + + TestService bean = context.getBean("groovyBean", TestService.class); + LogUserAdvice logAdvice = context.getBean(LogUserAdvice.class); + + assertEquals(0, logAdvice.getCountThrows()); + try { + bean.sayHello(); + fail("Expected exception"); + } catch (RuntimeException e) { + assertEquals("GroovyServiceImpl", e.getMessage()); + } + // No proxy here because the pointcut only applies to the concrete class, not the interface + assertEquals(0, logAdvice.getCountThrows()); + assertEquals(0, logAdvice.getCountBefore()); + } + + @Test + public void testGroovyBeanProxyTargetClass() { + + context = new GenericXmlApplicationContext(getClass(), getClass().getSimpleName()+"-groovy-proxy-target-class-context.xml"); + + TestService bean = context.getBean("groovyBean", TestService.class); + LogUserAdvice logAdvice = context.getBean(LogUserAdvice.class); + + assertEquals(0, logAdvice.getCountThrows()); + try { + bean.sayHello(); + fail("Expected exception"); + } catch (TestException e) { + assertEquals("GroovyServiceImpl", e.getMessage()); + } + assertEquals(1, logAdvice.getCountBefore()); + assertEquals(1, logAdvice.getCountThrows()); + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/scripting/groovy/GroovyAspectTests.java b/org.springframework.context/src/test/java/org/springframework/scripting/groovy/GroovyAspectTests.java index 124842916b..fa15ef7bfd 100644 --- a/org.springframework.context/src/test/java/org/springframework/scripting/groovy/GroovyAspectTests.java +++ b/org.springframework.context/src/test/java/org/springframework/scripting/groovy/GroovyAspectTests.java @@ -1,101 +1,101 @@ -package org.springframework.scripting.groovy; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -import org.junit.Test; -import org.springframework.aop.Advisor; -import org.springframework.aop.aspectj.AspectJExpressionPointcut; -import org.springframework.aop.framework.ProxyFactory; -import org.springframework.aop.support.DefaultPointcutAdvisor; -import org.springframework.core.io.ClassPathResource; -import org.springframework.scripting.groovy.GroovyScriptFactory; -import org.springframework.scripting.support.ResourceScriptSource; -import org.springframework.util.ClassUtils; - -/** - * @author Dave Syer - */ -public class GroovyAspectTests { - - @Test - public void testManualGroovyBeanWithUnconditionalPointcut() throws Exception { - - LogUserAdvice logAdvice = new LogUserAdvice(); - - GroovyScriptFactory scriptFactory = new GroovyScriptFactory("GroovyServiceImpl.grv"); - TestService target = (TestService) scriptFactory.getScriptedObject(new ResourceScriptSource( - new ClassPathResource("GroovyServiceImpl.grv", getClass())), null); - - testAdvice(new DefaultPointcutAdvisor(logAdvice), logAdvice, target, "GroovyServiceImpl"); - - } - - @Test - public void testManualGroovyBeanWithStaticPointcut() throws Exception { - LogUserAdvice logAdvice = new LogUserAdvice(); - - GroovyScriptFactory scriptFactory = new GroovyScriptFactory("GroovyServiceImpl.grv"); - TestService target = (TestService) scriptFactory.getScriptedObject(new ResourceScriptSource( - new ClassPathResource("GroovyServiceImpl.grv", getClass())), null); - - AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); - pointcut.setExpression(String.format("execution(* %s.TestService+.*(..))", ClassUtils.getPackageName(getClass()))); - testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "GroovyServiceImpl", true); - } - - @Test - public void testManualGroovyBeanWithDynamicPointcut() throws Exception { - - LogUserAdvice logAdvice = new LogUserAdvice(); - - GroovyScriptFactory scriptFactory = new GroovyScriptFactory("GroovyServiceImpl.grv"); - TestService target = (TestService) scriptFactory.getScriptedObject(new ResourceScriptSource( - new ClassPathResource("GroovyServiceImpl.grv", getClass())), null); - - AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); - pointcut.setExpression(String.format("@within(%s.Log)", ClassUtils.getPackageName(getClass()))); - testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "GroovyServiceImpl", false); - - } - - @Test - public void testManualGroovyBeanWithDynamicPointcutProxyTargetClass() throws Exception { - - LogUserAdvice logAdvice = new LogUserAdvice(); - - GroovyScriptFactory scriptFactory = new GroovyScriptFactory("GroovyServiceImpl.grv"); - TestService target = (TestService) scriptFactory.getScriptedObject(new ResourceScriptSource( - new ClassPathResource("GroovyServiceImpl.grv", getClass())), null); - - AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); - pointcut.setExpression(String.format("@within(%s.Log)", ClassUtils.getPackageName(getClass()))); - testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "GroovyServiceImpl", true); - - } - - private void testAdvice(Advisor advisor, LogUserAdvice logAdvice, TestService target, String message) - throws Exception { - testAdvice(advisor, logAdvice, target, message, false); - } - - private void testAdvice(Advisor advisor, LogUserAdvice logAdvice, TestService target, String message, - boolean proxyTargetClass) throws Exception { - - logAdvice.reset(); - - ProxyFactory factory = new ProxyFactory(target); - factory.setProxyTargetClass(proxyTargetClass); - factory.addAdvisor(advisor); - TestService bean = (TestService) factory.getProxy(); - - assertEquals(0, logAdvice.getCountThrows()); - try { - bean.sayHello(); - fail("Expected exception"); - } catch (TestException e) { - assertEquals(message, e.getMessage()); - } - assertEquals(1, logAdvice.getCountThrows()); - } -} +package org.springframework.scripting.groovy; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import org.junit.Test; +import org.springframework.aop.Advisor; +import org.springframework.aop.aspectj.AspectJExpressionPointcut; +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.support.DefaultPointcutAdvisor; +import org.springframework.core.io.ClassPathResource; +import org.springframework.scripting.groovy.GroovyScriptFactory; +import org.springframework.scripting.support.ResourceScriptSource; +import org.springframework.util.ClassUtils; + +/** + * @author Dave Syer + */ +public class GroovyAspectTests { + + @Test + public void testManualGroovyBeanWithUnconditionalPointcut() throws Exception { + + LogUserAdvice logAdvice = new LogUserAdvice(); + + GroovyScriptFactory scriptFactory = new GroovyScriptFactory("GroovyServiceImpl.grv"); + TestService target = (TestService) scriptFactory.getScriptedObject(new ResourceScriptSource( + new ClassPathResource("GroovyServiceImpl.grv", getClass())), null); + + testAdvice(new DefaultPointcutAdvisor(logAdvice), logAdvice, target, "GroovyServiceImpl"); + + } + + @Test + public void testManualGroovyBeanWithStaticPointcut() throws Exception { + LogUserAdvice logAdvice = new LogUserAdvice(); + + GroovyScriptFactory scriptFactory = new GroovyScriptFactory("GroovyServiceImpl.grv"); + TestService target = (TestService) scriptFactory.getScriptedObject(new ResourceScriptSource( + new ClassPathResource("GroovyServiceImpl.grv", getClass())), null); + + AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); + pointcut.setExpression(String.format("execution(* %s.TestService+.*(..))", ClassUtils.getPackageName(getClass()))); + testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "GroovyServiceImpl", true); + } + + @Test + public void testManualGroovyBeanWithDynamicPointcut() throws Exception { + + LogUserAdvice logAdvice = new LogUserAdvice(); + + GroovyScriptFactory scriptFactory = new GroovyScriptFactory("GroovyServiceImpl.grv"); + TestService target = (TestService) scriptFactory.getScriptedObject(new ResourceScriptSource( + new ClassPathResource("GroovyServiceImpl.grv", getClass())), null); + + AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); + pointcut.setExpression(String.format("@within(%s.Log)", ClassUtils.getPackageName(getClass()))); + testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "GroovyServiceImpl", false); + + } + + @Test + public void testManualGroovyBeanWithDynamicPointcutProxyTargetClass() throws Exception { + + LogUserAdvice logAdvice = new LogUserAdvice(); + + GroovyScriptFactory scriptFactory = new GroovyScriptFactory("GroovyServiceImpl.grv"); + TestService target = (TestService) scriptFactory.getScriptedObject(new ResourceScriptSource( + new ClassPathResource("GroovyServiceImpl.grv", getClass())), null); + + AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); + pointcut.setExpression(String.format("@within(%s.Log)", ClassUtils.getPackageName(getClass()))); + testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "GroovyServiceImpl", true); + + } + + private void testAdvice(Advisor advisor, LogUserAdvice logAdvice, TestService target, String message) + throws Exception { + testAdvice(advisor, logAdvice, target, message, false); + } + + private void testAdvice(Advisor advisor, LogUserAdvice logAdvice, TestService target, String message, + boolean proxyTargetClass) throws Exception { + + logAdvice.reset(); + + ProxyFactory factory = new ProxyFactory(target); + factory.setProxyTargetClass(proxyTargetClass); + factory.addAdvisor(advisor); + TestService bean = (TestService) factory.getProxy(); + + assertEquals(0, logAdvice.getCountThrows()); + try { + bean.sayHello(); + fail("Expected exception"); + } catch (TestException e) { + assertEquals(message, e.getMessage()); + } + assertEquals(1, logAdvice.getCountThrows()); + } +} diff --git a/org.springframework.context/src/test/java/org/springframework/scripting/groovy/GroovyServiceImpl.grv b/org.springframework.context/src/test/java/org/springframework/scripting/groovy/GroovyServiceImpl.grv index ba7a1e1511..dadb2bc950 100644 --- a/org.springframework.context/src/test/java/org/springframework/scripting/groovy/GroovyServiceImpl.grv +++ b/org.springframework.context/src/test/java/org/springframework/scripting/groovy/GroovyServiceImpl.grv @@ -1,11 +1,11 @@ -package org.springframework.scripting.groovy; - -@Log -public class GroovyServiceImpl implements TestService { - - public String sayHello() { - throw new TestException("GroovyServiceImpl"); - } - - +package org.springframework.scripting.groovy; + +@Log +public class GroovyServiceImpl implements TestService { + + public String sayHello() { + throw new TestException("GroovyServiceImpl"); + } + + } \ No newline at end of file diff --git a/org.springframework.context/src/test/java/org/springframework/scripting/groovy/Log.java b/org.springframework.context/src/test/java/org/springframework/scripting/groovy/Log.java index 2d23dfc682..08b6b543c4 100644 --- a/org.springframework.context/src/test/java/org/springframework/scripting/groovy/Log.java +++ b/org.springframework.context/src/test/java/org/springframework/scripting/groovy/Log.java @@ -1,15 +1,15 @@ -package org.springframework.scripting.groovy; - -import java.lang.annotation.Inherited; -import java.lang.annotation.Target; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Documented; - -@Target({ ElementType.METHOD, ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Inherited -public @interface Log { -} +package org.springframework.scripting.groovy; + +import java.lang.annotation.Inherited; +import java.lang.annotation.Target; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Documented; + +@Target({ ElementType.METHOD, ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +public @interface Log { +} diff --git a/org.springframework.context/src/test/java/org/springframework/scripting/groovy/LogUserAdvice.java b/org.springframework.context/src/test/java/org/springframework/scripting/groovy/LogUserAdvice.java index 2a553c504e..53ade22775 100644 --- a/org.springframework.context/src/test/java/org/springframework/scripting/groovy/LogUserAdvice.java +++ b/org.springframework.context/src/test/java/org/springframework/scripting/groovy/LogUserAdvice.java @@ -1,41 +1,41 @@ -package org.springframework.scripting.groovy; - -import java.lang.reflect.Method; - -import org.springframework.aop.MethodBeforeAdvice; -import org.springframework.aop.ThrowsAdvice; - -public class LogUserAdvice implements MethodBeforeAdvice, ThrowsAdvice { - - private int countBefore = 0; - - private int countThrows = 0; - - public void before(Method method, Object[] objects, Object o) throws Throwable { - countBefore++; - System.out.println("Method:"+method.getName()); - } - - public void afterThrowing(Exception e) throws Throwable { - countThrows++; - System.out.println("***********************************************************************************"); - System.out.println("Exception caught:"); - System.out.println("***********************************************************************************"); - e.printStackTrace(); - throw e; - } - - public int getCountBefore() { - return countBefore; - } - - public int getCountThrows() { - return countThrows; - } - - public void reset() { - countThrows = 0; - countBefore = 0; - } - -} +package org.springframework.scripting.groovy; + +import java.lang.reflect.Method; + +import org.springframework.aop.MethodBeforeAdvice; +import org.springframework.aop.ThrowsAdvice; + +public class LogUserAdvice implements MethodBeforeAdvice, ThrowsAdvice { + + private int countBefore = 0; + + private int countThrows = 0; + + public void before(Method method, Object[] objects, Object o) throws Throwable { + countBefore++; + System.out.println("Method:"+method.getName()); + } + + public void afterThrowing(Exception e) throws Throwable { + countThrows++; + System.out.println("***********************************************************************************"); + System.out.println("Exception caught:"); + System.out.println("***********************************************************************************"); + e.printStackTrace(); + throw e; + } + + public int getCountBefore() { + return countBefore; + } + + public int getCountThrows() { + return countThrows; + } + + public void reset() { + countThrows = 0; + countBefore = 0; + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/scripting/groovy/TestService.java b/org.springframework.context/src/test/java/org/springframework/scripting/groovy/TestService.java index 33db91aaa7..5c123d1183 100644 --- a/org.springframework.context/src/test/java/org/springframework/scripting/groovy/TestService.java +++ b/org.springframework.context/src/test/java/org/springframework/scripting/groovy/TestService.java @@ -1,5 +1,5 @@ -package org.springframework.scripting.groovy; - -public interface TestService { - public String sayHello(); -} +package org.springframework.scripting.groovy; + +public interface TestService { + public String sayHello(); +} diff --git a/org.springframework.context/src/test/java/org/springframework/scripting/groovy/TestServiceImpl.java b/org.springframework.context/src/test/java/org/springframework/scripting/groovy/TestServiceImpl.java index f51a623836..749fc42fde 100644 --- a/org.springframework.context/src/test/java/org/springframework/scripting/groovy/TestServiceImpl.java +++ b/org.springframework.context/src/test/java/org/springframework/scripting/groovy/TestServiceImpl.java @@ -1,8 +1,8 @@ -package org.springframework.scripting.groovy; - -@Log -public class TestServiceImpl implements TestService{ - public String sayHello() { - throw new TestException("TestServiceImpl"); - } -} +package org.springframework.scripting.groovy; + +@Log +public class TestServiceImpl implements TestService{ + public String sayHello() { + throw new TestException("TestServiceImpl"); + } +} diff --git a/org.springframework.context/src/test/java/org/springframework/validation/beanvalidation/BeanValidationPostProcessorTests.java b/org.springframework.context/src/test/java/org/springframework/validation/beanvalidation/BeanValidationPostProcessorTests.java index 42ca119e73..b98fb42007 100644 --- a/org.springframework.context/src/test/java/org/springframework/validation/beanvalidation/BeanValidationPostProcessorTests.java +++ b/org.springframework.context/src/test/java/org/springframework/validation/beanvalidation/BeanValidationPostProcessorTests.java @@ -1,156 +1,156 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.validation.beanvalidation; - -import javax.annotation.PostConstruct; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - -import static org.junit.Assert.*; -import org.junit.Test; - -import org.springframework.beans.TestBean; -import org.springframework.beans.factory.BeanCreationException; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor; -import org.springframework.context.support.GenericApplicationContext; - -/** - * @author Juergen Hoeller - * @since 3.0 - */ -public class BeanValidationPostProcessorTests { - - @Test - public void testNotNullConstraint() { - GenericApplicationContext ac = new GenericApplicationContext(); - ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class)); - ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class)); - ac.registerBeanDefinition("bean", new RootBeanDefinition(NotNullConstrainedBean.class)); - try { - ac.refresh(); - fail("Should have thrown BeanCreationException"); - } - catch (BeanCreationException ex) { - assertTrue(ex.getRootCause().getMessage().contains("testBean")); - assertTrue(ex.getRootCause().getMessage().contains("invalid")); - } - } - - @Test - public void testNotNullConstraintSatisfied() { - GenericApplicationContext ac = new GenericApplicationContext(); - ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class)); - ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class)); - RootBeanDefinition bd = new RootBeanDefinition(NotNullConstrainedBean.class); - bd.getPropertyValues().add("testBean", new TestBean()); - ac.registerBeanDefinition("bean", bd); - ac.refresh(); - } - - @Test - public void testNotNullConstraintAfterInitialization() { - GenericApplicationContext ac = new GenericApplicationContext(); - RootBeanDefinition bvpp = new RootBeanDefinition(BeanValidationPostProcessor.class); - bvpp.getPropertyValues().add("afterInitialization", true); - ac.registerBeanDefinition("bvpp", bvpp); - ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class)); - ac.registerBeanDefinition("bean", new RootBeanDefinition(AfterInitConstraintBean.class)); - ac.refresh(); - } - - @Test - public void testSizeConstraint() { - GenericApplicationContext ac = new GenericApplicationContext(); - ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class)); - RootBeanDefinition bd = new RootBeanDefinition(NotNullConstrainedBean.class); - bd.getPropertyValues().add("testBean", new TestBean()); - bd.getPropertyValues().add("stringValue", "s"); - ac.registerBeanDefinition("bean", bd); - try { - ac.refresh(); - fail("Should have thrown BeanCreationException"); - } - catch (BeanCreationException ex) { - assertTrue(ex.getRootCause().getMessage().contains("stringValue")); - assertTrue(ex.getRootCause().getMessage().contains("invalid")); - } - } - - @Test - public void testSizeConstraintSatisfied() { - GenericApplicationContext ac = new GenericApplicationContext(); - ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class)); - RootBeanDefinition bd = new RootBeanDefinition(NotNullConstrainedBean.class); - bd.getPropertyValues().add("testBean", new TestBean()); - bd.getPropertyValues().add("stringValue", "ss"); - ac.registerBeanDefinition("bean", bd); - ac.refresh(); - } - - - public static class NotNullConstrainedBean { - - @NotNull - private TestBean testBean; - - @Size(min = 2) - private String stringValue; - - public TestBean getTestBean() { - return testBean; - } - - public void setTestBean(TestBean testBean) { - this.testBean = testBean; - } - - public String getStringValue() { - return stringValue; - } - - public void setStringValue(String stringValue) { - this.stringValue = stringValue; - } - - @PostConstruct - public void init() { - assertNotNull("Shouldn't be here after constraint checking", this.testBean); - } - } - - - public static class AfterInitConstraintBean { - - @NotNull - private TestBean testBean; - - public TestBean getTestBean() { - return testBean; - } - - public void setTestBean(TestBean testBean) { - this.testBean = testBean; - } - - @PostConstruct - public void init() { - this.testBean = new TestBean(); - } - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.validation.beanvalidation; + +import javax.annotation.PostConstruct; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import static org.junit.Assert.*; +import org.junit.Test; + +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor; +import org.springframework.context.support.GenericApplicationContext; + +/** + * @author Juergen Hoeller + * @since 3.0 + */ +public class BeanValidationPostProcessorTests { + + @Test + public void testNotNullConstraint() { + GenericApplicationContext ac = new GenericApplicationContext(); + ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class)); + ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class)); + ac.registerBeanDefinition("bean", new RootBeanDefinition(NotNullConstrainedBean.class)); + try { + ac.refresh(); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + assertTrue(ex.getRootCause().getMessage().contains("testBean")); + assertTrue(ex.getRootCause().getMessage().contains("invalid")); + } + } + + @Test + public void testNotNullConstraintSatisfied() { + GenericApplicationContext ac = new GenericApplicationContext(); + ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class)); + ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class)); + RootBeanDefinition bd = new RootBeanDefinition(NotNullConstrainedBean.class); + bd.getPropertyValues().add("testBean", new TestBean()); + ac.registerBeanDefinition("bean", bd); + ac.refresh(); + } + + @Test + public void testNotNullConstraintAfterInitialization() { + GenericApplicationContext ac = new GenericApplicationContext(); + RootBeanDefinition bvpp = new RootBeanDefinition(BeanValidationPostProcessor.class); + bvpp.getPropertyValues().add("afterInitialization", true); + ac.registerBeanDefinition("bvpp", bvpp); + ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class)); + ac.registerBeanDefinition("bean", new RootBeanDefinition(AfterInitConstraintBean.class)); + ac.refresh(); + } + + @Test + public void testSizeConstraint() { + GenericApplicationContext ac = new GenericApplicationContext(); + ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class)); + RootBeanDefinition bd = new RootBeanDefinition(NotNullConstrainedBean.class); + bd.getPropertyValues().add("testBean", new TestBean()); + bd.getPropertyValues().add("stringValue", "s"); + ac.registerBeanDefinition("bean", bd); + try { + ac.refresh(); + fail("Should have thrown BeanCreationException"); + } + catch (BeanCreationException ex) { + assertTrue(ex.getRootCause().getMessage().contains("stringValue")); + assertTrue(ex.getRootCause().getMessage().contains("invalid")); + } + } + + @Test + public void testSizeConstraintSatisfied() { + GenericApplicationContext ac = new GenericApplicationContext(); + ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class)); + RootBeanDefinition bd = new RootBeanDefinition(NotNullConstrainedBean.class); + bd.getPropertyValues().add("testBean", new TestBean()); + bd.getPropertyValues().add("stringValue", "ss"); + ac.registerBeanDefinition("bean", bd); + ac.refresh(); + } + + + public static class NotNullConstrainedBean { + + @NotNull + private TestBean testBean; + + @Size(min = 2) + private String stringValue; + + public TestBean getTestBean() { + return testBean; + } + + public void setTestBean(TestBean testBean) { + this.testBean = testBean; + } + + public String getStringValue() { + return stringValue; + } + + public void setStringValue(String stringValue) { + this.stringValue = stringValue; + } + + @PostConstruct + public void init() { + assertNotNull("Shouldn't be here after constraint checking", this.testBean); + } + } + + + public static class AfterInitConstraintBean { + + @NotNull + private TestBean testBean; + + public TestBean getTestBean() { + return testBean; + } + + public void setTestBean(TestBean testBean) { + this.testBean = testBean; + } + + @PostConstruct + public void init() { + this.testBean = new TestBean(); + } + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/validation/beanvalidation/ValidatorFactoryTests.java b/org.springframework.context/src/test/java/org/springframework/validation/beanvalidation/ValidatorFactoryTests.java index c6fc15faf7..4e69535108 100644 --- a/org.springframework.context/src/test/java/org/springframework/validation/beanvalidation/ValidatorFactoryTests.java +++ b/org.springframework.context/src/test/java/org/springframework/validation/beanvalidation/ValidatorFactoryTests.java @@ -1,270 +1,270 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.validation.beanvalidation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.Arrays; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; -import javax.validation.Constraint; -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import javax.validation.ConstraintViolation; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - -import org.hibernate.validator.HibernateValidator; -import org.junit.Test; - -import org.springframework.validation.BeanPropertyBindingResult; -import org.springframework.validation.FieldError; -import org.springframework.validation.ObjectError; - -import static org.junit.Assert.*; - -/** - * @author Juergen Hoeller - * @since 3.0 - */ -public class ValidatorFactoryTests { - - @Test - public void testSimpleValidation() throws Exception { - LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); - validator.afterPropertiesSet(); - ValidPerson person = new ValidPerson(); - Set> result = validator.validate(person); - assertEquals(2, result.size()); - for (ConstraintViolation cv : result) { - String path = cv.getPropertyPath().toString(); - if ("name".equals(path) || "address.street".equals(path)) { - assertTrue(cv.getConstraintDescriptor().getAnnotation() instanceof NotNull); - } - else { - fail("Invalid constraint violation with path '" + path + "'"); - } - } - } - - @Test - public void testSimpleValidationWithCustomProvider() throws Exception { - LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); - validator.setProviderClass(HibernateValidator.class); - validator.afterPropertiesSet(); - ValidPerson person = new ValidPerson(); - Set> result = validator.validate(person); - assertEquals(2, result.size()); - for (ConstraintViolation cv : result) { - String path = cv.getPropertyPath().toString(); - if ("name".equals(path) || "address.street".equals(path)) { - assertTrue(cv.getConstraintDescriptor().getAnnotation() instanceof NotNull); - } - else { - fail("Invalid constraint violation with path '" + path + "'"); - } - } - } - - @Test - public void testSimpleValidationWithClassLevel() throws Exception { - LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); - validator.afterPropertiesSet(); - ValidPerson person = new ValidPerson(); - person.setName("Juergen"); - person.getAddress().setStreet("Juergen's Street"); - Set> result = validator.validate(person); - assertEquals(1, result.size()); - Iterator> iterator = result.iterator(); - ConstraintViolation cv = iterator.next(); - assertEquals("", cv.getPropertyPath().toString()); - assertTrue(cv.getConstraintDescriptor().getAnnotation() instanceof NameAddressValid); - } - - @Test - public void testSpringValidation() throws Exception { - LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); - validator.afterPropertiesSet(); - ValidPerson person = new ValidPerson(); - BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person"); - validator.validate(person, result); - assertEquals(2, result.getErrorCount()); - FieldError fieldError = result.getFieldError("name"); - assertEquals("name", fieldError.getField()); - System.out.println(Arrays.asList(fieldError.getCodes())); - System.out.println(fieldError.getDefaultMessage()); - fieldError = result.getFieldError("address.street"); - assertEquals("address.street", fieldError.getField()); - System.out.println(Arrays.asList(fieldError.getCodes())); - System.out.println(fieldError.getDefaultMessage()); - } - - @Test - public void testSpringValidationWithClassLevel() throws Exception { - LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); - validator.afterPropertiesSet(); - ValidPerson person = new ValidPerson(); - person.setName("Juergen"); - person.getAddress().setStreet("Juergen's Street"); - BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person"); - validator.validate(person, result); - assertEquals(1, result.getErrorCount()); - ObjectError globalError = result.getGlobalError(); - System.out.println(Arrays.asList(globalError.getCodes())); - System.out.println(globalError.getDefaultMessage()); - } - - @Test - public void testSpringValidationWithErrorInListElement() throws Exception { - LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); - validator.afterPropertiesSet(); - ValidPerson person = new ValidPerson(); - person.getAddressList().add(new ValidAddress()); - BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person"); - validator.validate(person, result); - assertEquals(3, result.getErrorCount()); - FieldError fieldError = result.getFieldError("name"); - assertEquals("name", fieldError.getField()); - System.out.println(Arrays.asList(fieldError.getCodes())); - System.out.println(fieldError.getDefaultMessage()); - fieldError = result.getFieldError("address.street"); - assertEquals("address.street", fieldError.getField()); - System.out.println(Arrays.asList(fieldError.getCodes())); - System.out.println(fieldError.getDefaultMessage()); - fieldError = result.getFieldError("addressList[0].street"); - assertEquals("addressList[0].street", fieldError.getField()); - System.out.println(Arrays.asList(fieldError.getCodes())); - System.out.println(fieldError.getDefaultMessage()); - } - - @Test - public void testSpringValidationWithErrorInSetElement() throws Exception { - LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); - validator.afterPropertiesSet(); - ValidPerson person = new ValidPerson(); - person.getAddressSet().add(new ValidAddress()); - BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person"); - validator.validate(person, result); - assertEquals(3, result.getErrorCount()); - FieldError fieldError = result.getFieldError("name"); - assertEquals("name", fieldError.getField()); - System.out.println(Arrays.asList(fieldError.getCodes())); - System.out.println(fieldError.getDefaultMessage()); - fieldError = result.getFieldError("address.street"); - assertEquals("address.street", fieldError.getField()); - System.out.println(Arrays.asList(fieldError.getCodes())); - System.out.println(fieldError.getDefaultMessage()); - fieldError = result.getFieldError("addressSet[].street"); - assertEquals("addressSet[].street", fieldError.getField()); - System.out.println(Arrays.asList(fieldError.getCodes())); - System.out.println(fieldError.getDefaultMessage()); - } - - - @NameAddressValid - public static class ValidPerson { - - @NotNull - private String name; - - @Valid - private ValidAddress address = new ValidAddress(); - - @Valid - private List addressList = new LinkedList(); - - @Valid - private Set addressSet = new LinkedHashSet(); - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public ValidAddress getAddress() { - return address; - } - - public void setAddress(ValidAddress address) { - this.address = address; - } - - public List getAddressList() { - return addressList; - } - - public void setAddressList(List addressList) { - this.addressList = addressList; - } - - public Set getAddressSet() { - return addressSet; - } - - public void setAddressSet(Set addressSet) { - this.addressSet = addressSet; - } - } - - - public static class ValidAddress { - - @NotNull - private String street; - - public String getStreet() { - return street; - } - - public void setStreet(String street) { - this.street = street; - } - } - - - @Target(ElementType.TYPE) - @Retention(RetentionPolicy.RUNTIME) - @Constraint(validatedBy = NameAddressValidator.class) - public @interface NameAddressValid { - - String message() default "Street must not contain name"; - - Class[] groups() default {}; - - Class[] payload() default {}; - } - - - public static class NameAddressValidator implements ConstraintValidator { - - public void initialize(NameAddressValid constraintAnnotation) { - } - - public boolean isValid(ValidPerson value, ConstraintValidatorContext constraintValidatorContext) { - return (value.name == null || !value.address.street.contains(value.name)); - } - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.validation.beanvalidation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import javax.validation.Constraint; +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import javax.validation.ConstraintViolation; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +import org.hibernate.validator.HibernateValidator; +import org.junit.Test; + +import org.springframework.validation.BeanPropertyBindingResult; +import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; + +import static org.junit.Assert.*; + +/** + * @author Juergen Hoeller + * @since 3.0 + */ +public class ValidatorFactoryTests { + + @Test + public void testSimpleValidation() throws Exception { + LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); + validator.afterPropertiesSet(); + ValidPerson person = new ValidPerson(); + Set> result = validator.validate(person); + assertEquals(2, result.size()); + for (ConstraintViolation cv : result) { + String path = cv.getPropertyPath().toString(); + if ("name".equals(path) || "address.street".equals(path)) { + assertTrue(cv.getConstraintDescriptor().getAnnotation() instanceof NotNull); + } + else { + fail("Invalid constraint violation with path '" + path + "'"); + } + } + } + + @Test + public void testSimpleValidationWithCustomProvider() throws Exception { + LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); + validator.setProviderClass(HibernateValidator.class); + validator.afterPropertiesSet(); + ValidPerson person = new ValidPerson(); + Set> result = validator.validate(person); + assertEquals(2, result.size()); + for (ConstraintViolation cv : result) { + String path = cv.getPropertyPath().toString(); + if ("name".equals(path) || "address.street".equals(path)) { + assertTrue(cv.getConstraintDescriptor().getAnnotation() instanceof NotNull); + } + else { + fail("Invalid constraint violation with path '" + path + "'"); + } + } + } + + @Test + public void testSimpleValidationWithClassLevel() throws Exception { + LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); + validator.afterPropertiesSet(); + ValidPerson person = new ValidPerson(); + person.setName("Juergen"); + person.getAddress().setStreet("Juergen's Street"); + Set> result = validator.validate(person); + assertEquals(1, result.size()); + Iterator> iterator = result.iterator(); + ConstraintViolation cv = iterator.next(); + assertEquals("", cv.getPropertyPath().toString()); + assertTrue(cv.getConstraintDescriptor().getAnnotation() instanceof NameAddressValid); + } + + @Test + public void testSpringValidation() throws Exception { + LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); + validator.afterPropertiesSet(); + ValidPerson person = new ValidPerson(); + BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person"); + validator.validate(person, result); + assertEquals(2, result.getErrorCount()); + FieldError fieldError = result.getFieldError("name"); + assertEquals("name", fieldError.getField()); + System.out.println(Arrays.asList(fieldError.getCodes())); + System.out.println(fieldError.getDefaultMessage()); + fieldError = result.getFieldError("address.street"); + assertEquals("address.street", fieldError.getField()); + System.out.println(Arrays.asList(fieldError.getCodes())); + System.out.println(fieldError.getDefaultMessage()); + } + + @Test + public void testSpringValidationWithClassLevel() throws Exception { + LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); + validator.afterPropertiesSet(); + ValidPerson person = new ValidPerson(); + person.setName("Juergen"); + person.getAddress().setStreet("Juergen's Street"); + BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person"); + validator.validate(person, result); + assertEquals(1, result.getErrorCount()); + ObjectError globalError = result.getGlobalError(); + System.out.println(Arrays.asList(globalError.getCodes())); + System.out.println(globalError.getDefaultMessage()); + } + + @Test + public void testSpringValidationWithErrorInListElement() throws Exception { + LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); + validator.afterPropertiesSet(); + ValidPerson person = new ValidPerson(); + person.getAddressList().add(new ValidAddress()); + BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person"); + validator.validate(person, result); + assertEquals(3, result.getErrorCount()); + FieldError fieldError = result.getFieldError("name"); + assertEquals("name", fieldError.getField()); + System.out.println(Arrays.asList(fieldError.getCodes())); + System.out.println(fieldError.getDefaultMessage()); + fieldError = result.getFieldError("address.street"); + assertEquals("address.street", fieldError.getField()); + System.out.println(Arrays.asList(fieldError.getCodes())); + System.out.println(fieldError.getDefaultMessage()); + fieldError = result.getFieldError("addressList[0].street"); + assertEquals("addressList[0].street", fieldError.getField()); + System.out.println(Arrays.asList(fieldError.getCodes())); + System.out.println(fieldError.getDefaultMessage()); + } + + @Test + public void testSpringValidationWithErrorInSetElement() throws Exception { + LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); + validator.afterPropertiesSet(); + ValidPerson person = new ValidPerson(); + person.getAddressSet().add(new ValidAddress()); + BeanPropertyBindingResult result = new BeanPropertyBindingResult(person, "person"); + validator.validate(person, result); + assertEquals(3, result.getErrorCount()); + FieldError fieldError = result.getFieldError("name"); + assertEquals("name", fieldError.getField()); + System.out.println(Arrays.asList(fieldError.getCodes())); + System.out.println(fieldError.getDefaultMessage()); + fieldError = result.getFieldError("address.street"); + assertEquals("address.street", fieldError.getField()); + System.out.println(Arrays.asList(fieldError.getCodes())); + System.out.println(fieldError.getDefaultMessage()); + fieldError = result.getFieldError("addressSet[].street"); + assertEquals("addressSet[].street", fieldError.getField()); + System.out.println(Arrays.asList(fieldError.getCodes())); + System.out.println(fieldError.getDefaultMessage()); + } + + + @NameAddressValid + public static class ValidPerson { + + @NotNull + private String name; + + @Valid + private ValidAddress address = new ValidAddress(); + + @Valid + private List addressList = new LinkedList(); + + @Valid + private Set addressSet = new LinkedHashSet(); + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ValidAddress getAddress() { + return address; + } + + public void setAddress(ValidAddress address) { + this.address = address; + } + + public List getAddressList() { + return addressList; + } + + public void setAddressList(List addressList) { + this.addressList = addressList; + } + + public Set getAddressSet() { + return addressSet; + } + + public void setAddressSet(Set addressSet) { + this.addressSet = addressSet; + } + } + + + public static class ValidAddress { + + @NotNull + private String street; + + public String getStreet() { + return street; + } + + public void setStreet(String street) { + this.street = street; + } + } + + + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.RUNTIME) + @Constraint(validatedBy = NameAddressValidator.class) + public @interface NameAddressValid { + + String message() default "Street must not contain name"; + + Class[] groups() default {}; + + Class[] payload() default {}; + } + + + public static class NameAddressValidator implements ConstraintValidator { + + public void initialize(NameAddressValid constraintAnnotation) { + } + + public boolean isValid(ValidPerson value, ConstraintValidatorContext constraintValidatorContext) { + return (value.name == null || !value.address.street.contains(value.name)); + } + } + +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/ExceptionDepthComparator.java b/org.springframework.core/src/main/java/org/springframework/core/ExceptionDepthComparator.java index c856b86a03..53e3425f36 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/ExceptionDepthComparator.java +++ b/org.springframework.core/src/main/java/org/springframework/core/ExceptionDepthComparator.java @@ -1,96 +1,96 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import org.springframework.util.Assert; - -/** - * Comparator capable of sorting exceptions based on their depth from the thrown exception type. - * - * @author Juergen Hoeller - * @author Arjen Poutsma - * @since 3.0.3 - */ -public class ExceptionDepthComparator implements Comparator> { - - private final Class targetException; - - - /** - * Create a new ExceptionDepthComparator for the given exception. - * @param exception the target exception to compare to when sorting by depth - */ - public ExceptionDepthComparator(Throwable exception) { - Assert.notNull(exception, "Target exception must not be null"); - this.targetException = exception.getClass(); - } - - /** - * Create a new ExceptionDepthComparator for the given exception type. - * @param exceptionType the target exception type to compare to when sorting by depth - */ - public ExceptionDepthComparator(Class exceptionType) { - Assert.notNull(exceptionType, "Target exception type must not be null"); - this.targetException = exceptionType; - } - - - public int compare(Class o1, Class o2) { - int depth1 = getDepth(o1, this.targetException, 0); - int depth2 = getDepth(o2, this.targetException, 0); - return (depth1 - depth2); - } - - private int getDepth(Class declaredException, Class exceptionToMatch, int depth) { - if (declaredException.equals(exceptionToMatch)) { - // Found it! - return depth; - } - // If we've gone as far as we can go and haven't found it... - if (Throwable.class.equals(exceptionToMatch)) { - return Integer.MAX_VALUE; - } - return getDepth(declaredException, exceptionToMatch.getSuperclass(), depth + 1); - } - - - /** - * Obtain the closest match from the given exception types for the given target exception. - * @param exceptionTypes the collection of exception types - * @param targetException the target exception to find a match for - * @return the closest matching exception type from the given collection - */ - public static Class findClosestMatch( - Collection> exceptionTypes, Throwable targetException) { - - Assert.notEmpty(exceptionTypes, "Exception types must not be empty"); - if (exceptionTypes.size() == 1) { - return exceptionTypes.iterator().next(); - } - List> handledExceptions = - new ArrayList>(exceptionTypes); - Collections.sort(handledExceptions, new ExceptionDepthComparator(targetException)); - return handledExceptions.get(0); - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import org.springframework.util.Assert; + +/** + * Comparator capable of sorting exceptions based on their depth from the thrown exception type. + * + * @author Juergen Hoeller + * @author Arjen Poutsma + * @since 3.0.3 + */ +public class ExceptionDepthComparator implements Comparator> { + + private final Class targetException; + + + /** + * Create a new ExceptionDepthComparator for the given exception. + * @param exception the target exception to compare to when sorting by depth + */ + public ExceptionDepthComparator(Throwable exception) { + Assert.notNull(exception, "Target exception must not be null"); + this.targetException = exception.getClass(); + } + + /** + * Create a new ExceptionDepthComparator for the given exception type. + * @param exceptionType the target exception type to compare to when sorting by depth + */ + public ExceptionDepthComparator(Class exceptionType) { + Assert.notNull(exceptionType, "Target exception type must not be null"); + this.targetException = exceptionType; + } + + + public int compare(Class o1, Class o2) { + int depth1 = getDepth(o1, this.targetException, 0); + int depth2 = getDepth(o2, this.targetException, 0); + return (depth1 - depth2); + } + + private int getDepth(Class declaredException, Class exceptionToMatch, int depth) { + if (declaredException.equals(exceptionToMatch)) { + // Found it! + return depth; + } + // If we've gone as far as we can go and haven't found it... + if (Throwable.class.equals(exceptionToMatch)) { + return Integer.MAX_VALUE; + } + return getDepth(declaredException, exceptionToMatch.getSuperclass(), depth + 1); + } + + + /** + * Obtain the closest match from the given exception types for the given target exception. + * @param exceptionTypes the collection of exception types + * @param targetException the target exception to find a match for + * @return the closest matching exception type from the given collection + */ + public static Class findClosestMatch( + Collection> exceptionTypes, Throwable targetException) { + + Assert.notEmpty(exceptionTypes, "Exception types must not be empty"); + if (exceptionTypes.size() == 1) { + return exceptionTypes.iterator().next(); + } + List> handledExceptions = + new ArrayList>(exceptionTypes); + Collections.sort(handledExceptions, new ExceptionDepthComparator(targetException)); + return handledExceptions.get(0); + } + +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConvertingPropertyEditorAdapter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConvertingPropertyEditorAdapter.java index 777861061c..47cadd667d 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConvertingPropertyEditorAdapter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ConvertingPropertyEditorAdapter.java @@ -1,72 +1,72 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.convert.support; - -import java.beans.PropertyEditorSupport; - -import org.springframework.core.convert.ConversionService; -import org.springframework.core.convert.TypeDescriptor; -import org.springframework.util.Assert; - -/** - * Adapter that exposes a {@link java.beans.PropertyEditor} for any given - * {@link org.springframework.core.convert.ConversionService} and specific target type. - * - * @author Juergen Hoeller - * @since 3.0 - */ -public class ConvertingPropertyEditorAdapter extends PropertyEditorSupport { - - private final ConversionService conversionService; - - private final TypeDescriptor targetDescriptor; - - private final boolean canConvertToString; - - - /** - * Create a new ConvertingPropertyEditorAdapter for a given - * {@link org.springframework.core.convert.ConversionService} - * and the given target type. - * @param conversionService the ConversionService to delegate to - * @param targetDescriptor the target type to convert to - */ - public ConvertingPropertyEditorAdapter(ConversionService conversionService, TypeDescriptor targetDescriptor) { - Assert.notNull(conversionService, "ConversionService must not be null"); - Assert.notNull(targetDescriptor, "TypeDescriptor must not be null"); - this.conversionService = conversionService; - this.targetDescriptor = targetDescriptor; - this.canConvertToString = conversionService.canConvert(this.targetDescriptor, TypeDescriptor.valueOf(String.class)); - } - - - @Override - public void setAsText(String text) throws IllegalArgumentException { - setValue(this.conversionService.convert(text, TypeDescriptor.valueOf(String.class), this.targetDescriptor)); - } - - @Override - public String getAsText() { - if (this.canConvertToString) { - return (String) this.conversionService.convert(getValue(), this.targetDescriptor, TypeDescriptor.valueOf(String.class)); - } - else { - return null; - } - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.convert.support; + +import java.beans.PropertyEditorSupport; + +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.util.Assert; + +/** + * Adapter that exposes a {@link java.beans.PropertyEditor} for any given + * {@link org.springframework.core.convert.ConversionService} and specific target type. + * + * @author Juergen Hoeller + * @since 3.0 + */ +public class ConvertingPropertyEditorAdapter extends PropertyEditorSupport { + + private final ConversionService conversionService; + + private final TypeDescriptor targetDescriptor; + + private final boolean canConvertToString; + + + /** + * Create a new ConvertingPropertyEditorAdapter for a given + * {@link org.springframework.core.convert.ConversionService} + * and the given target type. + * @param conversionService the ConversionService to delegate to + * @param targetDescriptor the target type to convert to + */ + public ConvertingPropertyEditorAdapter(ConversionService conversionService, TypeDescriptor targetDescriptor) { + Assert.notNull(conversionService, "ConversionService must not be null"); + Assert.notNull(targetDescriptor, "TypeDescriptor must not be null"); + this.conversionService = conversionService; + this.targetDescriptor = targetDescriptor; + this.canConvertToString = conversionService.canConvert(this.targetDescriptor, TypeDescriptor.valueOf(String.class)); + } + + + @Override + public void setAsText(String text) throws IllegalArgumentException { + setValue(this.conversionService.convert(text, TypeDescriptor.valueOf(String.class), this.targetDescriptor)); + } + + @Override + public String getAsText() { + if (this.canConvertToString) { + return (String) this.conversionService.convert(getValue(), this.targetDescriptor, TypeDescriptor.valueOf(String.class)); + } + else { + return null; + } + } + +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java b/org.springframework.core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java index fd00f909f0..f5c5f18034 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java +++ b/org.springframework.core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java @@ -1,201 +1,201 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.core.io; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URI; -import java.net.URL; -import java.net.URLConnection; - -import org.springframework.util.ResourceUtils; - -/** - * Abstract base class for resources which resolve URLs into File references, - * such as {@link UrlResource} or {@link ClassPathResource}. - * - *

Detects the "file" protocol as well as the JBoss "vfs" protocol in URLs, - * resolving file system references accordingly. - * - * @author Juergen Hoeller - * @since 3.0 - */ -public abstract class AbstractFileResolvingResource extends AbstractResource { - - /** - * This implementation returns a File reference for the underlying class path - * resource, provided that it refers to a file in the file system. - * @see org.springframework.util.ResourceUtils#getFile(java.net.URL, String) - */ - @Override - public File getFile() throws IOException { - URL url = getURL(); - if (url.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) { - return VfsResourceDelegate.getResource(url).getFile(); - } - return ResourceUtils.getFile(url, getDescription()); - } - - /** - * This implementation determines the underlying File - * (or jar file, in case of a resource in a jar/zip). - */ - @Override - protected File getFileForLastModifiedCheck() throws IOException { - URL url = getURL(); - if (ResourceUtils.isJarURL(url)) { - URL actualUrl = ResourceUtils.extractJarFileURL(url); - if (actualUrl.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) { - return VfsResourceDelegate.getResource(actualUrl).getFile(); - } - return ResourceUtils.getFile(actualUrl, "Jar URL"); - } - else { - return getFile(); - } - } - - /** - * This implementation returns a File reference for the underlying class path - * resource, provided that it refers to a file in the file system. - * @see org.springframework.util.ResourceUtils#getFile(java.net.URI, String) - */ - protected File getFile(URI uri) throws IOException { - if (uri.getScheme().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) { - return VfsResourceDelegate.getResource(uri).getFile(); - } - return ResourceUtils.getFile(uri, getDescription()); - } - - - @Override - public boolean exists() { - try { - URL url = getURL(); - if (ResourceUtils.isFileURL(url)) { - // Proceed with file system resolution... - return getFile().exists(); - } - else { - // Try a URL connection content-length header... - URLConnection con = url.openConnection(); - con.setUseCaches(false); - HttpURLConnection httpCon = - (con instanceof HttpURLConnection ? (HttpURLConnection) con : null); - if (httpCon != null) { - httpCon.setRequestMethod("HEAD"); - int code = httpCon.getResponseCode(); - if (code == HttpURLConnection.HTTP_OK) { - return true; - } - else if (code == HttpURLConnection.HTTP_NOT_FOUND) { - return false; - } - } - if (con.getContentLength() >= 0) { - return true; - } - if (httpCon != null) { - // no HTTP OK status, and no content-length header: give up - httpCon.disconnect(); - return false; - } - else { - // Fall back to stream existence: can we open the stream? - InputStream is = getInputStream(); - is.close(); - return true; - } - } - } - catch (IOException ex) { - return false; - } - } - - @Override - public boolean isReadable() { - try { - URL url = getURL(); - if (ResourceUtils.isFileURL(url)) { - // Proceed with file system resolution... - File file = getFile(); - return (file.canRead() && !file.isDirectory()); - } - else { - return true; - } - } - catch (IOException ex) { - return false; - } - } - - @Override - public long contentLength() throws IOException { - URL url = getURL(); - if (ResourceUtils.isFileURL(url)) { - // Proceed with file system resolution... - return super.contentLength(); - } - else { - // Try a URL connection content-length header... - URLConnection con = url.openConnection(); - con.setUseCaches(false); - if (con instanceof HttpURLConnection) { - ((HttpURLConnection) con).setRequestMethod("HEAD"); - } - return con.getContentLength(); - } - } - - @Override - public long lastModified() throws IOException { - URL url = getURL(); - if (ResourceUtils.isFileURL(url) || ResourceUtils.isJarURL(url)) { - // Proceed with file system resolution... - return super.lastModified(); - } - else { - // Try a URL connection last-modified header... - URLConnection con = url.openConnection(); - con.setUseCaches(false); - if (con instanceof HttpURLConnection) { - ((HttpURLConnection) con).setRequestMethod("HEAD"); - } - return con.getLastModified(); - } - } - - - /** - * Inner delegate class, avoiding a hard JBoss VFS API dependency at runtime. - */ - private static class VfsResourceDelegate { - - public static Resource getResource(URL url) throws IOException { - return new VfsResource(VfsUtils.getRoot(url)); - } - - public static Resource getResource(URI uri) throws IOException { - return new VfsResource(VfsUtils.getRoot(uri)); - } - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.io; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; + +import org.springframework.util.ResourceUtils; + +/** + * Abstract base class for resources which resolve URLs into File references, + * such as {@link UrlResource} or {@link ClassPathResource}. + * + *

Detects the "file" protocol as well as the JBoss "vfs" protocol in URLs, + * resolving file system references accordingly. + * + * @author Juergen Hoeller + * @since 3.0 + */ +public abstract class AbstractFileResolvingResource extends AbstractResource { + + /** + * This implementation returns a File reference for the underlying class path + * resource, provided that it refers to a file in the file system. + * @see org.springframework.util.ResourceUtils#getFile(java.net.URL, String) + */ + @Override + public File getFile() throws IOException { + URL url = getURL(); + if (url.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) { + return VfsResourceDelegate.getResource(url).getFile(); + } + return ResourceUtils.getFile(url, getDescription()); + } + + /** + * This implementation determines the underlying File + * (or jar file, in case of a resource in a jar/zip). + */ + @Override + protected File getFileForLastModifiedCheck() throws IOException { + URL url = getURL(); + if (ResourceUtils.isJarURL(url)) { + URL actualUrl = ResourceUtils.extractJarFileURL(url); + if (actualUrl.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) { + return VfsResourceDelegate.getResource(actualUrl).getFile(); + } + return ResourceUtils.getFile(actualUrl, "Jar URL"); + } + else { + return getFile(); + } + } + + /** + * This implementation returns a File reference for the underlying class path + * resource, provided that it refers to a file in the file system. + * @see org.springframework.util.ResourceUtils#getFile(java.net.URI, String) + */ + protected File getFile(URI uri) throws IOException { + if (uri.getScheme().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) { + return VfsResourceDelegate.getResource(uri).getFile(); + } + return ResourceUtils.getFile(uri, getDescription()); + } + + + @Override + public boolean exists() { + try { + URL url = getURL(); + if (ResourceUtils.isFileURL(url)) { + // Proceed with file system resolution... + return getFile().exists(); + } + else { + // Try a URL connection content-length header... + URLConnection con = url.openConnection(); + con.setUseCaches(false); + HttpURLConnection httpCon = + (con instanceof HttpURLConnection ? (HttpURLConnection) con : null); + if (httpCon != null) { + httpCon.setRequestMethod("HEAD"); + int code = httpCon.getResponseCode(); + if (code == HttpURLConnection.HTTP_OK) { + return true; + } + else if (code == HttpURLConnection.HTTP_NOT_FOUND) { + return false; + } + } + if (con.getContentLength() >= 0) { + return true; + } + if (httpCon != null) { + // no HTTP OK status, and no content-length header: give up + httpCon.disconnect(); + return false; + } + else { + // Fall back to stream existence: can we open the stream? + InputStream is = getInputStream(); + is.close(); + return true; + } + } + } + catch (IOException ex) { + return false; + } + } + + @Override + public boolean isReadable() { + try { + URL url = getURL(); + if (ResourceUtils.isFileURL(url)) { + // Proceed with file system resolution... + File file = getFile(); + return (file.canRead() && !file.isDirectory()); + } + else { + return true; + } + } + catch (IOException ex) { + return false; + } + } + + @Override + public long contentLength() throws IOException { + URL url = getURL(); + if (ResourceUtils.isFileURL(url)) { + // Proceed with file system resolution... + return super.contentLength(); + } + else { + // Try a URL connection content-length header... + URLConnection con = url.openConnection(); + con.setUseCaches(false); + if (con instanceof HttpURLConnection) { + ((HttpURLConnection) con).setRequestMethod("HEAD"); + } + return con.getContentLength(); + } + } + + @Override + public long lastModified() throws IOException { + URL url = getURL(); + if (ResourceUtils.isFileURL(url) || ResourceUtils.isJarURL(url)) { + // Proceed with file system resolution... + return super.lastModified(); + } + else { + // Try a URL connection last-modified header... + URLConnection con = url.openConnection(); + con.setUseCaches(false); + if (con instanceof HttpURLConnection) { + ((HttpURLConnection) con).setRequestMethod("HEAD"); + } + return con.getLastModified(); + } + } + + + /** + * Inner delegate class, avoiding a hard JBoss VFS API dependency at runtime. + */ + private static class VfsResourceDelegate { + + public static Resource getResource(URL url) throws IOException { + return new VfsResource(VfsUtils.getRoot(url)); + } + + public static Resource getResource(URI uri) throws IOException { + return new VfsResource(VfsUtils.getRoot(uri)); + } + } + +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/io/ClassRelativeResourceLoader.java b/org.springframework.core/src/main/java/org/springframework/core/io/ClassRelativeResourceLoader.java index dc20e6747f..d014939b22 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/io/ClassRelativeResourceLoader.java +++ b/org.springframework.core/src/main/java/org/springframework/core/io/ClassRelativeResourceLoader.java @@ -1,75 +1,75 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.core.io; - -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -/** - * {@link ResourceLoader} implementation that interprets plain resource paths - * as relative to a given java.lang.Class. - * - * @author Juergen Hoeller - * @since 3.0 - * @see java.lang.Class#getResource(String) - * @see ClassPathResource#ClassPathResource(String, Class) - */ -public class ClassRelativeResourceLoader extends DefaultResourceLoader { - - private final Class clazz; - - - /** - * Create a new ClassRelativeResourceLoader for the given class. - * @param clazz the class to load resources through - */ - public ClassRelativeResourceLoader(Class clazz) { - Assert.notNull(clazz, "Class must not be null"); - this.clazz = clazz; - setClassLoader(clazz.getClassLoader()); - } - - protected Resource getResourceByPath(String path) { - return new ClassRelativeContextResource(path, this.clazz); - } - - - /** - * ClassPathResource that explicitly expresses a context-relative path - * through implementing the ContextResource interface. - */ - private static class ClassRelativeContextResource extends ClassPathResource implements ContextResource { - - private final Class clazz; - - public ClassRelativeContextResource(String path, Class clazz) { - super(path, clazz); - this.clazz = clazz; - } - - public String getPathWithinContext() { - return getPath(); - } - - @Override - public Resource createRelative(String relativePath) { - String pathToUse = StringUtils.applyRelativePath(getPath(), relativePath); - return new ClassRelativeContextResource(pathToUse, this.clazz); - } - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.io; + +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * {@link ResourceLoader} implementation that interprets plain resource paths + * as relative to a given java.lang.Class. + * + * @author Juergen Hoeller + * @since 3.0 + * @see java.lang.Class#getResource(String) + * @see ClassPathResource#ClassPathResource(String, Class) + */ +public class ClassRelativeResourceLoader extends DefaultResourceLoader { + + private final Class clazz; + + + /** + * Create a new ClassRelativeResourceLoader for the given class. + * @param clazz the class to load resources through + */ + public ClassRelativeResourceLoader(Class clazz) { + Assert.notNull(clazz, "Class must not be null"); + this.clazz = clazz; + setClassLoader(clazz.getClassLoader()); + } + + protected Resource getResourceByPath(String path) { + return new ClassRelativeContextResource(path, this.clazz); + } + + + /** + * ClassPathResource that explicitly expresses a context-relative path + * through implementing the ContextResource interface. + */ + private static class ClassRelativeContextResource extends ClassPathResource implements ContextResource { + + private final Class clazz; + + public ClassRelativeContextResource(String path, Class clazz) { + super(path, clazz); + this.clazz = clazz; + } + + public String getPathWithinContext() { + return getPath(); + } + + @Override + public Resource createRelative(String relativePath) { + String pathToUse = StringUtils.applyRelativePath(getPath(), relativePath); + return new ClassRelativeContextResource(pathToUse, this.clazz); + } + } + +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/io/VfsUtils.java b/org.springframework.core/src/main/java/org/springframework/core/io/VfsUtils.java index 5596803b51..a0e268ce70 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/io/VfsUtils.java +++ b/org.springframework.core/src/main/java/org/springframework/core/io/VfsUtils.java @@ -1,253 +1,253 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.core.io; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.URI; -import java.net.URL; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.core.NestedIOException; -import org.springframework.util.ReflectionUtils; - -/** - * Utility for detecting the JBoss VFS version available in the classpath. - * JBoss AS 5+ uses VFS 2.x (package org.jboss.virtual) while - * JBoss AS 6+ uses VFS 3.x (package org.jboss.vfs). - * - *

Thanks go to Marius Bogoevici for the initial patch. - * - * Note: This is an internal class and should not be used outside the framework. - * - * @author Costin Leau - * @since 3.0.3 - */ -public abstract class VfsUtils { - - private static final Log logger = LogFactory.getLog(VfsUtils.class); - - private static final String VFS2_PKG = "org.jboss.virtual."; - private static final String VFS3_PKG = "org.jboss.vfs."; - private static final String VFS_NAME = "VFS"; - - private static enum VFS_VER { V2, V3 } - - private static VFS_VER version; - - private static Method VFS_METHOD_GET_ROOT_URL = null; - private static Method VFS_METHOD_GET_ROOT_URI = null; - - private static Method VIRTUAL_FILE_METHOD_EXISTS = null; - private static Method VIRTUAL_FILE_METHOD_GET_SIZE; - private static Method VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED; - private static Method VIRTUAL_FILE_METHOD_GET_CHILD; - private static Method VIRTUAL_FILE_METHOD_GET_INPUT_STREAM; - private static Method VIRTUAL_FILE_METHOD_TO_URL; - private static Method VIRTUAL_FILE_METHOD_TO_URI; - private static Method VIRTUAL_FILE_METHOD_GET_NAME; - private static Method VIRTUAL_FILE_METHOD_GET_PATH_NAME; - protected static Class VIRTUAL_FILE_VISITOR_INTERFACE; - protected static Method VIRTUAL_FILE_METHOD_VISIT; - - private static Method VFS_UTILS_METHOD_IS_NESTED_FILE = null; - private static Method VFS_UTILS_METHOD_GET_COMPATIBLE_URI = null; - private static Field VISITOR_ATTRIBUTES_FIELD_RECURSE = null; - private static Method GET_PHYSICAL_FILE = null; - - static { - ClassLoader loader = VfsUtils.class.getClassLoader(); - String pkg; - Class vfsClass; - - // check for JBoss 6 - try { - vfsClass = loader.loadClass(VFS3_PKG + VFS_NAME); - version = VFS_VER.V3; - pkg = VFS3_PKG; - - if (logger.isDebugEnabled()) { - logger.debug("JBoss VFS packages for JBoss AS 6 found"); - } - } - catch (ClassNotFoundException ex) { - // fallback to JBoss 5 - if (logger.isDebugEnabled()) - logger.debug("JBoss VFS packages for JBoss AS 6 not found; falling back to JBoss AS 5 packages"); - try { - vfsClass = loader.loadClass(VFS2_PKG + VFS_NAME); - - version = VFS_VER.V2; - pkg = VFS2_PKG; - - if (logger.isDebugEnabled()) - logger.debug("JBoss VFS packages for JBoss AS 5 found"); - } catch (ClassNotFoundException ex1) { - logger.error("JBoss VFS packages (for both JBoss AS 5 and 6) were not found - JBoss VFS support disabled"); - throw new IllegalStateException("Cannot detect JBoss VFS packages", ex1); - } - } - - // cache reflective information - try { - String methodName = (VFS_VER.V3.equals(version) ? "getChild" : "getRoot"); - - VFS_METHOD_GET_ROOT_URL = ReflectionUtils.findMethod(vfsClass, methodName, URL.class); - VFS_METHOD_GET_ROOT_URI = ReflectionUtils.findMethod(vfsClass, methodName, URI.class); - - Class virtualFile = loader.loadClass(pkg + "VirtualFile"); - - VIRTUAL_FILE_METHOD_EXISTS = ReflectionUtils.findMethod(virtualFile, "exists"); - VIRTUAL_FILE_METHOD_GET_SIZE = ReflectionUtils.findMethod(virtualFile, "getSize"); - VIRTUAL_FILE_METHOD_GET_INPUT_STREAM = ReflectionUtils.findMethod(virtualFile, "openStream"); - VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED = ReflectionUtils.findMethod(virtualFile, "getLastModified"); - VIRTUAL_FILE_METHOD_TO_URI = ReflectionUtils.findMethod(virtualFile, "toURI"); - VIRTUAL_FILE_METHOD_TO_URL = ReflectionUtils.findMethod(virtualFile, "toURL"); - VIRTUAL_FILE_METHOD_GET_NAME = ReflectionUtils.findMethod(virtualFile, "getName"); - VIRTUAL_FILE_METHOD_GET_PATH_NAME = ReflectionUtils.findMethod(virtualFile, "getPathName"); - GET_PHYSICAL_FILE = ReflectionUtils.findMethod(virtualFile, "getPhysicalFile"); - - methodName = (VFS_VER.V3.equals(version) ? "getChild" : "findChild"); - - VIRTUAL_FILE_METHOD_GET_CHILD = ReflectionUtils.findMethod(virtualFile, methodName, String.class); - - Class utilsClass = loader.loadClass(pkg + "VFSUtils"); - - VFS_UTILS_METHOD_GET_COMPATIBLE_URI = ReflectionUtils.findMethod(utilsClass, "getCompatibleURI", - virtualFile); - VFS_UTILS_METHOD_IS_NESTED_FILE = ReflectionUtils.findMethod(utilsClass, "isNestedFile", virtualFile); - - VIRTUAL_FILE_VISITOR_INTERFACE = loader.loadClass(pkg + "VirtualFileVisitor"); - VIRTUAL_FILE_METHOD_VISIT = ReflectionUtils.findMethod(virtualFile, "visit", VIRTUAL_FILE_VISITOR_INTERFACE); - - Class visitorAttributesClass = loader.loadClass(pkg + "VisitorAttributes"); - VISITOR_ATTRIBUTES_FIELD_RECURSE = ReflectionUtils.findField(visitorAttributesClass, "RECURSE"); - } - catch (ClassNotFoundException ex) { - throw new IllegalStateException("Could not detect the JBoss VFS infrastructure", ex); - } - } - - protected static Object invokeVfsMethod(Method method, Object target, Object... args) throws IOException { - try { - return method.invoke(target, args); - } - catch (InvocationTargetException ex) { - Throwable targetEx = ex.getTargetException(); - if (targetEx instanceof IOException) { - throw (IOException) targetEx; - } - ReflectionUtils.handleInvocationTargetException(ex); - } - catch (Exception ex) { - ReflectionUtils.handleReflectionException(ex); - } - - throw new IllegalStateException("Invalid code path reached"); - } - - static boolean exists(Object vfsResource) { - try { - return (Boolean) invokeVfsMethod(VIRTUAL_FILE_METHOD_EXISTS, vfsResource); - } - catch (IOException ex) { - return false; - } - } - - static boolean isReadable(Object vfsResource) { - try { - return ((Long) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_SIZE, vfsResource) > 0); - } - catch (IOException ex) { - return false; - } - } - - static long getLastModified(Object vfsResource) throws IOException { - return (Long) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED, vfsResource); - } - - static InputStream getInputStream(Object vfsResource) throws IOException { - return (InputStream) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_INPUT_STREAM, vfsResource); - } - - static URL getURL(Object vfsResource) throws IOException { - return (URL) invokeVfsMethod(VIRTUAL_FILE_METHOD_TO_URL, vfsResource); - } - - static URI getURI(Object vfsResource) throws IOException { - return (URI) invokeVfsMethod(VIRTUAL_FILE_METHOD_TO_URI, vfsResource); - } - - static String getName(Object vfsResource) { - try { - return (String) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_NAME, vfsResource); - } - catch (IOException ex) { - throw new IllegalStateException("Cannot get resource name", ex); - } - } - - static Object getRelative(URL url) throws IOException { - return invokeVfsMethod(VFS_METHOD_GET_ROOT_URL, null, url); - } - - static Object getChild(Object vfsResource, String path) throws IOException { - return invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_CHILD, vfsResource, path); - } - - static File getFile(Object vfsResource) throws IOException { - if (VFS_VER.V2.equals(version)) { - if ((Boolean) invokeVfsMethod(VFS_UTILS_METHOD_IS_NESTED_FILE, null, vfsResource)) { - throw new IOException("File resolution not supported for nested resource: " + vfsResource); - } - try { - return new File((URI) invokeVfsMethod(VFS_UTILS_METHOD_GET_COMPATIBLE_URI, null, vfsResource)); - } - catch (Exception ex) { - throw new NestedIOException("Failed to obtain File reference for " + vfsResource, ex); - } - } - else { - return (File) invokeVfsMethod(GET_PHYSICAL_FILE, vfsResource); - } - } - - static Object getRoot(URI url) throws IOException { - return invokeVfsMethod(VFS_METHOD_GET_ROOT_URI, null, url); - } - - // protected methods used by the support sub-package - - protected static Object getRoot(URL url) throws IOException { - return invokeVfsMethod(VFS_METHOD_GET_ROOT_URL, null, url); - } - - protected static Object doGetVisitorAttribute() { - return ReflectionUtils.getField(VISITOR_ATTRIBUTES_FIELD_RECURSE, null); - } - - protected static String doGetPath(Object resource) { - return (String) ReflectionUtils.invokeMethod(VIRTUAL_FILE_METHOD_GET_PATH_NAME, resource); - } +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.io; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URI; +import java.net.URL; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.core.NestedIOException; +import org.springframework.util.ReflectionUtils; + +/** + * Utility for detecting the JBoss VFS version available in the classpath. + * JBoss AS 5+ uses VFS 2.x (package org.jboss.virtual) while + * JBoss AS 6+ uses VFS 3.x (package org.jboss.vfs). + * + *

Thanks go to Marius Bogoevici for the initial patch. + * + * Note: This is an internal class and should not be used outside the framework. + * + * @author Costin Leau + * @since 3.0.3 + */ +public abstract class VfsUtils { + + private static final Log logger = LogFactory.getLog(VfsUtils.class); + + private static final String VFS2_PKG = "org.jboss.virtual."; + private static final String VFS3_PKG = "org.jboss.vfs."; + private static final String VFS_NAME = "VFS"; + + private static enum VFS_VER { V2, V3 } + + private static VFS_VER version; + + private static Method VFS_METHOD_GET_ROOT_URL = null; + private static Method VFS_METHOD_GET_ROOT_URI = null; + + private static Method VIRTUAL_FILE_METHOD_EXISTS = null; + private static Method VIRTUAL_FILE_METHOD_GET_SIZE; + private static Method VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED; + private static Method VIRTUAL_FILE_METHOD_GET_CHILD; + private static Method VIRTUAL_FILE_METHOD_GET_INPUT_STREAM; + private static Method VIRTUAL_FILE_METHOD_TO_URL; + private static Method VIRTUAL_FILE_METHOD_TO_URI; + private static Method VIRTUAL_FILE_METHOD_GET_NAME; + private static Method VIRTUAL_FILE_METHOD_GET_PATH_NAME; + protected static Class VIRTUAL_FILE_VISITOR_INTERFACE; + protected static Method VIRTUAL_FILE_METHOD_VISIT; + + private static Method VFS_UTILS_METHOD_IS_NESTED_FILE = null; + private static Method VFS_UTILS_METHOD_GET_COMPATIBLE_URI = null; + private static Field VISITOR_ATTRIBUTES_FIELD_RECURSE = null; + private static Method GET_PHYSICAL_FILE = null; + + static { + ClassLoader loader = VfsUtils.class.getClassLoader(); + String pkg; + Class vfsClass; + + // check for JBoss 6 + try { + vfsClass = loader.loadClass(VFS3_PKG + VFS_NAME); + version = VFS_VER.V3; + pkg = VFS3_PKG; + + if (logger.isDebugEnabled()) { + logger.debug("JBoss VFS packages for JBoss AS 6 found"); + } + } + catch (ClassNotFoundException ex) { + // fallback to JBoss 5 + if (logger.isDebugEnabled()) + logger.debug("JBoss VFS packages for JBoss AS 6 not found; falling back to JBoss AS 5 packages"); + try { + vfsClass = loader.loadClass(VFS2_PKG + VFS_NAME); + + version = VFS_VER.V2; + pkg = VFS2_PKG; + + if (logger.isDebugEnabled()) + logger.debug("JBoss VFS packages for JBoss AS 5 found"); + } catch (ClassNotFoundException ex1) { + logger.error("JBoss VFS packages (for both JBoss AS 5 and 6) were not found - JBoss VFS support disabled"); + throw new IllegalStateException("Cannot detect JBoss VFS packages", ex1); + } + } + + // cache reflective information + try { + String methodName = (VFS_VER.V3.equals(version) ? "getChild" : "getRoot"); + + VFS_METHOD_GET_ROOT_URL = ReflectionUtils.findMethod(vfsClass, methodName, URL.class); + VFS_METHOD_GET_ROOT_URI = ReflectionUtils.findMethod(vfsClass, methodName, URI.class); + + Class virtualFile = loader.loadClass(pkg + "VirtualFile"); + + VIRTUAL_FILE_METHOD_EXISTS = ReflectionUtils.findMethod(virtualFile, "exists"); + VIRTUAL_FILE_METHOD_GET_SIZE = ReflectionUtils.findMethod(virtualFile, "getSize"); + VIRTUAL_FILE_METHOD_GET_INPUT_STREAM = ReflectionUtils.findMethod(virtualFile, "openStream"); + VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED = ReflectionUtils.findMethod(virtualFile, "getLastModified"); + VIRTUAL_FILE_METHOD_TO_URI = ReflectionUtils.findMethod(virtualFile, "toURI"); + VIRTUAL_FILE_METHOD_TO_URL = ReflectionUtils.findMethod(virtualFile, "toURL"); + VIRTUAL_FILE_METHOD_GET_NAME = ReflectionUtils.findMethod(virtualFile, "getName"); + VIRTUAL_FILE_METHOD_GET_PATH_NAME = ReflectionUtils.findMethod(virtualFile, "getPathName"); + GET_PHYSICAL_FILE = ReflectionUtils.findMethod(virtualFile, "getPhysicalFile"); + + methodName = (VFS_VER.V3.equals(version) ? "getChild" : "findChild"); + + VIRTUAL_FILE_METHOD_GET_CHILD = ReflectionUtils.findMethod(virtualFile, methodName, String.class); + + Class utilsClass = loader.loadClass(pkg + "VFSUtils"); + + VFS_UTILS_METHOD_GET_COMPATIBLE_URI = ReflectionUtils.findMethod(utilsClass, "getCompatibleURI", + virtualFile); + VFS_UTILS_METHOD_IS_NESTED_FILE = ReflectionUtils.findMethod(utilsClass, "isNestedFile", virtualFile); + + VIRTUAL_FILE_VISITOR_INTERFACE = loader.loadClass(pkg + "VirtualFileVisitor"); + VIRTUAL_FILE_METHOD_VISIT = ReflectionUtils.findMethod(virtualFile, "visit", VIRTUAL_FILE_VISITOR_INTERFACE); + + Class visitorAttributesClass = loader.loadClass(pkg + "VisitorAttributes"); + VISITOR_ATTRIBUTES_FIELD_RECURSE = ReflectionUtils.findField(visitorAttributesClass, "RECURSE"); + } + catch (ClassNotFoundException ex) { + throw new IllegalStateException("Could not detect the JBoss VFS infrastructure", ex); + } + } + + protected static Object invokeVfsMethod(Method method, Object target, Object... args) throws IOException { + try { + return method.invoke(target, args); + } + catch (InvocationTargetException ex) { + Throwable targetEx = ex.getTargetException(); + if (targetEx instanceof IOException) { + throw (IOException) targetEx; + } + ReflectionUtils.handleInvocationTargetException(ex); + } + catch (Exception ex) { + ReflectionUtils.handleReflectionException(ex); + } + + throw new IllegalStateException("Invalid code path reached"); + } + + static boolean exists(Object vfsResource) { + try { + return (Boolean) invokeVfsMethod(VIRTUAL_FILE_METHOD_EXISTS, vfsResource); + } + catch (IOException ex) { + return false; + } + } + + static boolean isReadable(Object vfsResource) { + try { + return ((Long) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_SIZE, vfsResource) > 0); + } + catch (IOException ex) { + return false; + } + } + + static long getLastModified(Object vfsResource) throws IOException { + return (Long) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_LAST_MODIFIED, vfsResource); + } + + static InputStream getInputStream(Object vfsResource) throws IOException { + return (InputStream) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_INPUT_STREAM, vfsResource); + } + + static URL getURL(Object vfsResource) throws IOException { + return (URL) invokeVfsMethod(VIRTUAL_FILE_METHOD_TO_URL, vfsResource); + } + + static URI getURI(Object vfsResource) throws IOException { + return (URI) invokeVfsMethod(VIRTUAL_FILE_METHOD_TO_URI, vfsResource); + } + + static String getName(Object vfsResource) { + try { + return (String) invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_NAME, vfsResource); + } + catch (IOException ex) { + throw new IllegalStateException("Cannot get resource name", ex); + } + } + + static Object getRelative(URL url) throws IOException { + return invokeVfsMethod(VFS_METHOD_GET_ROOT_URL, null, url); + } + + static Object getChild(Object vfsResource, String path) throws IOException { + return invokeVfsMethod(VIRTUAL_FILE_METHOD_GET_CHILD, vfsResource, path); + } + + static File getFile(Object vfsResource) throws IOException { + if (VFS_VER.V2.equals(version)) { + if ((Boolean) invokeVfsMethod(VFS_UTILS_METHOD_IS_NESTED_FILE, null, vfsResource)) { + throw new IOException("File resolution not supported for nested resource: " + vfsResource); + } + try { + return new File((URI) invokeVfsMethod(VFS_UTILS_METHOD_GET_COMPATIBLE_URI, null, vfsResource)); + } + catch (Exception ex) { + throw new NestedIOException("Failed to obtain File reference for " + vfsResource, ex); + } + } + else { + return (File) invokeVfsMethod(GET_PHYSICAL_FILE, vfsResource); + } + } + + static Object getRoot(URI url) throws IOException { + return invokeVfsMethod(VFS_METHOD_GET_ROOT_URI, null, url); + } + + // protected methods used by the support sub-package + + protected static Object getRoot(URL url) throws IOException { + return invokeVfsMethod(VFS_METHOD_GET_ROOT_URL, null, url); + } + + protected static Object doGetVisitorAttribute() { + return ReflectionUtils.getField(VISITOR_ATTRIBUTES_FIELD_RECURSE, null); + } + + protected static String doGetPath(Object resource) { + return (String) ReflectionUtils.invokeMethod(VIRTUAL_FILE_METHOD_GET_PATH_NAME, resource); + } } \ No newline at end of file diff --git a/org.springframework.core/src/main/java/org/springframework/core/io/WritableResource.java b/org.springframework.core/src/main/java/org/springframework/core/io/WritableResource.java index c7ec3722c0..1f44c5163e 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/io/WritableResource.java +++ b/org.springframework.core/src/main/java/org/springframework/core/io/WritableResource.java @@ -1,52 +1,52 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.core.io; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Extended interface for a resource that supports writing to it. - * Provides an {@link #getOutputStream() OutputStream accessor}. - * - * @author Juergen Hoeller - * @since 3.1 - * @see java.io.OutputStream - */ -public interface WritableResource extends Resource { - - /** - * Return whether the contents of this resource can be modified, - * e.g. via {@link #getOutputStream()} or {@link #getFile()}. - *

Will be true for typical resource descriptors; - * note that actual content writing may still fail when attempted. - * However, a value of false is a definitive indication - * that the resource content cannot be modified. - * @see #getOutputStream() - * @see #isReadable() - */ - boolean isWritable(); - - /** - * Return an {@link OutputStream} for the underlying resource, - * allowing to (over-)write its content. - * @throws IOException if the stream could not be opened - * @see #getInputStream() - */ - OutputStream getOutputStream() throws IOException; - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.io; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Extended interface for a resource that supports writing to it. + * Provides an {@link #getOutputStream() OutputStream accessor}. + * + * @author Juergen Hoeller + * @since 3.1 + * @see java.io.OutputStream + */ +public interface WritableResource extends Resource { + + /** + * Return whether the contents of this resource can be modified, + * e.g. via {@link #getOutputStream()} or {@link #getFile()}. + *

Will be true for typical resource descriptors; + * note that actual content writing may still fail when attempted. + * However, a value of false is a definitive indication + * that the resource content cannot be modified. + * @see #getOutputStream() + * @see #isReadable() + */ + boolean isWritable(); + + /** + * Return an {@link OutputStream} for the underlying resource, + * allowing to (over-)write its content. + * @throws IOException if the stream could not be opened + * @see #getInputStream() + */ + OutputStream getOutputStream() throws IOException; + +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/io/support/VfsPatternUtils.java b/org.springframework.core/src/main/java/org/springframework/core/io/support/VfsPatternUtils.java index 44adbf2197..f6e523ea58 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/io/support/VfsPatternUtils.java +++ b/org.springframework.core/src/main/java/org/springframework/core/io/support/VfsPatternUtils.java @@ -1,53 +1,53 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.core.io.support; - -import java.io.IOException; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Proxy; -import java.net.URL; - -import org.springframework.core.io.VfsUtils; - -/** - * Artificial class used for accessing the {@link VfsUtils} methods - * without exposing them to the entire world. - * - * @author Costin Leau - * @since 3.0.3 - */ -abstract class VfsPatternUtils extends VfsUtils { - - static Object getVisitorAttribute() { - return doGetVisitorAttribute(); - } - - static String getPath(Object resource) { - return doGetPath(resource); - } - - static Object findRoot(URL url) throws IOException { - return getRoot(url); - } - - static void visit(Object resource, InvocationHandler visitor) throws IOException { - Object visitorProxy = Proxy.newProxyInstance(VIRTUAL_FILE_VISITOR_INTERFACE.getClassLoader(), - new Class[] { VIRTUAL_FILE_VISITOR_INTERFACE }, visitor); - invokeVfsMethod(VIRTUAL_FILE_METHOD_VISIT, resource, visitorProxy); - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.io.support; + +import java.io.IOException; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.net.URL; + +import org.springframework.core.io.VfsUtils; + +/** + * Artificial class used for accessing the {@link VfsUtils} methods + * without exposing them to the entire world. + * + * @author Costin Leau + * @since 3.0.3 + */ +abstract class VfsPatternUtils extends VfsUtils { + + static Object getVisitorAttribute() { + return doGetVisitorAttribute(); + } + + static String getPath(Object resource) { + return doGetPath(resource); + } + + static Object findRoot(URL url) throws IOException { + return getRoot(url); + } + + static void visit(Object resource, InvocationHandler visitor) throws IOException { + Object visitorProxy = Proxy.newProxyInstance(VIRTUAL_FILE_VISITOR_INTERFACE.getClassLoader(), + new Class[] { VIRTUAL_FILE_VISITOR_INTERFACE }, visitor); + invokeVfsMethod(VIRTUAL_FILE_METHOD_VISIT, resource, visitorProxy); + } + +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/serializer/support/package-info.java b/org.springframework.core/src/main/java/org/springframework/core/serializer/support/package-info.java index 22c3c03a8f..33f7365ffb 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/serializer/support/package-info.java +++ b/org.springframework.core/src/main/java/org/springframework/core/serializer/support/package-info.java @@ -1,9 +1,9 @@ - -/** - * - * Support classes for Spring's serializer abstraction. - * Includes adapters to the Converter SPI. - * - */ -package org.springframework.core.serializer.support; - + +/** + * + * Support classes for Spring's serializer abstraction. + * Includes adapters to the Converter SPI. + * + */ +package org.springframework.core.serializer.support; + diff --git a/org.springframework.core/src/main/java/org/springframework/core/task/support/ExecutorServiceAdapter.java b/org.springframework.core/src/main/java/org/springframework/core/task/support/ExecutorServiceAdapter.java index 323df6eede..91d5122d84 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/task/support/ExecutorServiceAdapter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/task/support/ExecutorServiceAdapter.java @@ -1,87 +1,87 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.core.task.support; - -import java.util.List; -import java.util.concurrent.AbstractExecutorService; -import java.util.concurrent.TimeUnit; - -import org.springframework.core.task.TaskExecutor; -import org.springframework.util.Assert; - -/** - * Adapter that takes a Spring {@link org.springframework.core.task.TaskExecutor}) - * and exposes a full java.util.concurrent.ExecutorService for it. - * - *

This is primarily for adapting to client components that communicate via the - * java.util.concurrent.ExecutorService API. It can also be used as - * common ground between a local Spring TaskExecutor backend and a - * JNDI-located ManagedExecutorService in a Java EE 6 environment. - * - *

NOTE: This ExecutorService adapter does not support the - * lifecycle methods in the java.util.concurrent.ExecutorService API - * ("shutdown()" etc), similar to a server-wide ManagedExecutorService - * in a Java EE 6 environment. The lifecycle is always up to the backend pool, - * with this adapter acting as an access-only proxy for that target pool. - * - * @author Juergen Hoeller - * @since 3.0 - * @see java.util.concurrent.ExecutorService - */ -public class ExecutorServiceAdapter extends AbstractExecutorService { - - private final TaskExecutor taskExecutor; - - - /** - * Create a new ExecutorServiceAdapter, using the given target executor. - * @param concurrentExecutor the target executor to delegate to - */ - public ExecutorServiceAdapter(TaskExecutor taskExecutor) { - Assert.notNull(taskExecutor, "TaskExecutor must not be null"); - this.taskExecutor = taskExecutor; - } - - - public void execute(Runnable task) { - this.taskExecutor.execute(task); - } - - public void shutdown() { - throw new IllegalStateException( - "Manual shutdown not supported - ExecutorServiceAdapter is dependent on an external lifecycle"); - } - - public List shutdownNow() { - throw new IllegalStateException( - "Manual shutdown not supported - ExecutorServiceAdapter is dependent on an external lifecycle"); - } - - public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { - throw new IllegalStateException( - "Manual shutdown not supported - ExecutorServiceAdapter is dependent on an external lifecycle"); - } - - public boolean isShutdown() { - return false; - } - - public boolean isTerminated() { - return false; - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.task.support; + +import java.util.List; +import java.util.concurrent.AbstractExecutorService; +import java.util.concurrent.TimeUnit; + +import org.springframework.core.task.TaskExecutor; +import org.springframework.util.Assert; + +/** + * Adapter that takes a Spring {@link org.springframework.core.task.TaskExecutor}) + * and exposes a full java.util.concurrent.ExecutorService for it. + * + *

This is primarily for adapting to client components that communicate via the + * java.util.concurrent.ExecutorService API. It can also be used as + * common ground between a local Spring TaskExecutor backend and a + * JNDI-located ManagedExecutorService in a Java EE 6 environment. + * + *

NOTE: This ExecutorService adapter does not support the + * lifecycle methods in the java.util.concurrent.ExecutorService API + * ("shutdown()" etc), similar to a server-wide ManagedExecutorService + * in a Java EE 6 environment. The lifecycle is always up to the backend pool, + * with this adapter acting as an access-only proxy for that target pool. + * + * @author Juergen Hoeller + * @since 3.0 + * @see java.util.concurrent.ExecutorService + */ +public class ExecutorServiceAdapter extends AbstractExecutorService { + + private final TaskExecutor taskExecutor; + + + /** + * Create a new ExecutorServiceAdapter, using the given target executor. + * @param concurrentExecutor the target executor to delegate to + */ + public ExecutorServiceAdapter(TaskExecutor taskExecutor) { + Assert.notNull(taskExecutor, "TaskExecutor must not be null"); + this.taskExecutor = taskExecutor; + } + + + public void execute(Runnable task) { + this.taskExecutor.execute(task); + } + + public void shutdown() { + throw new IllegalStateException( + "Manual shutdown not supported - ExecutorServiceAdapter is dependent on an external lifecycle"); + } + + public List shutdownNow() { + throw new IllegalStateException( + "Manual shutdown not supported - ExecutorServiceAdapter is dependent on an external lifecycle"); + } + + public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { + throw new IllegalStateException( + "Manual shutdown not supported - ExecutorServiceAdapter is dependent on an external lifecycle"); + } + + public boolean isShutdown() { + return false; + } + + public boolean isTerminated() { + return false; + } + +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/type/MethodMetadata.java b/org.springframework.core/src/main/java/org/springframework/core/type/MethodMetadata.java index b9417e8873..21f715e764 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/type/MethodMetadata.java +++ b/org.springframework.core/src/main/java/org/springframework/core/type/MethodMetadata.java @@ -1,79 +1,79 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.core.type; - -import java.util.Map; - -/** - * Interface that defines abstract access to the annotations of a specific - * class, in a form that does not require that class to be loaded yet. - * - * @author Juergen Hoeller - * @author Mark Pollack - * @author Chris Beams - * @since 3.0 - * @see StandardMethodMetadata - * @see AnnotationMetadata#getAnnotatedMethods - */ -public interface MethodMetadata { - - /** - * Return the name of the method. - */ - String getMethodName(); - - /** - * Return the fully-qualified name of the class that declares this method. - */ - public String getDeclaringClassName(); - - /** - * Return whether the underlying method is declared as 'static'. - */ - boolean isStatic(); - - /** - * Return whether the underlying method is marked as 'final'. - */ - boolean isFinal(); - - /** - * Return whether the underlying method is overridable, - * i.e. not marked as static, final or private. - */ - boolean isOverridable(); - - /** - * Determine whether the underlying method has an annotation or - * meta-annotation of the given type defined. - * @param annotationType the annotation type to look for - * @return whether a matching annotation is defined - */ - boolean isAnnotated(String annotationType); - - /** - * Retrieve the attributes of the annotation of the given type, - * if any (i.e. if defined on the underlying method, as direct - * annotation or as meta-annotation). - * @param annotationType the annotation type to look for - * @return a Map of attributes, with the attribute name as key (e.g. "value") - * and the defined attribute value as Map value. This return value will be - * null if no matching annotation is defined. - */ - Map getAnnotationAttributes(String annotationType); - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.type; + +import java.util.Map; + +/** + * Interface that defines abstract access to the annotations of a specific + * class, in a form that does not require that class to be loaded yet. + * + * @author Juergen Hoeller + * @author Mark Pollack + * @author Chris Beams + * @since 3.0 + * @see StandardMethodMetadata + * @see AnnotationMetadata#getAnnotatedMethods + */ +public interface MethodMetadata { + + /** + * Return the name of the method. + */ + String getMethodName(); + + /** + * Return the fully-qualified name of the class that declares this method. + */ + public String getDeclaringClassName(); + + /** + * Return whether the underlying method is declared as 'static'. + */ + boolean isStatic(); + + /** + * Return whether the underlying method is marked as 'final'. + */ + boolean isFinal(); + + /** + * Return whether the underlying method is overridable, + * i.e. not marked as static, final or private. + */ + boolean isOverridable(); + + /** + * Determine whether the underlying method has an annotation or + * meta-annotation of the given type defined. + * @param annotationType the annotation type to look for + * @return whether a matching annotation is defined + */ + boolean isAnnotated(String annotationType); + + /** + * Retrieve the attributes of the annotation of the given type, + * if any (i.e. if defined on the underlying method, as direct + * annotation or as meta-annotation). + * @param annotationType the annotation type to look for + * @return a Map of attributes, with the attribute name as key (e.g. "value") + * and the defined attribute value as Map value. This return value will be + * null if no matching annotation is defined. + */ + Map getAnnotationAttributes(String annotationType); + +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/type/StandardMethodMetadata.java b/org.springframework.core/src/main/java/org/springframework/core/type/StandardMethodMetadata.java index c6c8f28f80..ead840cc21 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/type/StandardMethodMetadata.java +++ b/org.springframework.core/src/main/java/org/springframework/core/type/StandardMethodMetadata.java @@ -1,108 +1,108 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.core.type; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.Map; - -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.util.Assert; - -/** - * {@link MethodMetadata} implementation that uses standard reflection - * to introspect a given Method. - * - * @author Juergen Hoeller - * @author Mark Pollack - * @author Chris Beams - * @since 3.0 - */ -public class StandardMethodMetadata implements MethodMetadata { - - private final Method introspectedMethod; - - - /** - * Create a new StandardMethodMetadata wrapper for the given Method. - * @param introspectedMethod the Method to introspect - */ - public StandardMethodMetadata(Method introspectedMethod) { - Assert.notNull(introspectedMethod, "Method must not be null"); - this.introspectedMethod = introspectedMethod; - } - - /** - * Return the underlying Method. - */ - public final Method getIntrospectedMethod() { - return this.introspectedMethod; - } - - - public String getMethodName() { - return this.introspectedMethod.getName(); - } - - public String getDeclaringClassName() { - return this.introspectedMethod.getDeclaringClass().getName(); - } - - public boolean isStatic() { - return Modifier.isStatic(this.introspectedMethod.getModifiers()); - } - - public boolean isFinal() { - return Modifier.isFinal(this.introspectedMethod.getModifiers()); - } - - public boolean isOverridable() { - return (!isStatic() && !isFinal() && !Modifier.isPrivate(this.introspectedMethod.getModifiers())); - } - - public boolean isAnnotated(String annotationType) { - Annotation[] anns = this.introspectedMethod.getAnnotations(); - for (Annotation ann : anns) { - if (ann.annotationType().getName().equals(annotationType)) { - return true; - } - for (Annotation metaAnn : ann.annotationType().getAnnotations()) { - if (metaAnn.annotationType().getName().equals(annotationType)) { - return true; - } - } - } - return false; - } - - public Map getAnnotationAttributes(String annotationType) { - Annotation[] anns = this.introspectedMethod.getAnnotations(); - for (Annotation ann : anns) { - if (ann.annotationType().getName().equals(annotationType)) { - return AnnotationUtils.getAnnotationAttributes(ann, true); - } - for (Annotation metaAnn : ann.annotationType().getAnnotations()) { - if (metaAnn.annotationType().getName().equals(annotationType)) { - return AnnotationUtils.getAnnotationAttributes(metaAnn, true); - } - } - } - return null; - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.type; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Map; + +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.util.Assert; + +/** + * {@link MethodMetadata} implementation that uses standard reflection + * to introspect a given Method. + * + * @author Juergen Hoeller + * @author Mark Pollack + * @author Chris Beams + * @since 3.0 + */ +public class StandardMethodMetadata implements MethodMetadata { + + private final Method introspectedMethod; + + + /** + * Create a new StandardMethodMetadata wrapper for the given Method. + * @param introspectedMethod the Method to introspect + */ + public StandardMethodMetadata(Method introspectedMethod) { + Assert.notNull(introspectedMethod, "Method must not be null"); + this.introspectedMethod = introspectedMethod; + } + + /** + * Return the underlying Method. + */ + public final Method getIntrospectedMethod() { + return this.introspectedMethod; + } + + + public String getMethodName() { + return this.introspectedMethod.getName(); + } + + public String getDeclaringClassName() { + return this.introspectedMethod.getDeclaringClass().getName(); + } + + public boolean isStatic() { + return Modifier.isStatic(this.introspectedMethod.getModifiers()); + } + + public boolean isFinal() { + return Modifier.isFinal(this.introspectedMethod.getModifiers()); + } + + public boolean isOverridable() { + return (!isStatic() && !isFinal() && !Modifier.isPrivate(this.introspectedMethod.getModifiers())); + } + + public boolean isAnnotated(String annotationType) { + Annotation[] anns = this.introspectedMethod.getAnnotations(); + for (Annotation ann : anns) { + if (ann.annotationType().getName().equals(annotationType)) { + return true; + } + for (Annotation metaAnn : ann.annotationType().getAnnotations()) { + if (metaAnn.annotationType().getName().equals(annotationType)) { + return true; + } + } + } + return false; + } + + public Map getAnnotationAttributes(String annotationType) { + Annotation[] anns = this.introspectedMethod.getAnnotations(); + for (Annotation ann : anns) { + if (ann.annotationType().getName().equals(annotationType)) { + return AnnotationUtils.getAnnotationAttributes(ann, true); + } + for (Annotation metaAnn : ann.annotationType().getAnnotations()) { + if (metaAnn.annotationType().getName().equals(annotationType)) { + return AnnotationUtils.getAnnotationAttributes(metaAnn, true); + } + } + } + return null; + } + +} diff --git a/org.springframework.core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java b/org.springframework.core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java index 267dc6c5d6..244808b323 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java +++ b/org.springframework.core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java @@ -1,150 +1,150 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.core.type.classreading; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Array; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; - -import org.springframework.asm.AnnotationVisitor; -import org.springframework.asm.Type; -import org.springframework.asm.commons.EmptyVisitor; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.util.ObjectUtils; -import org.springframework.util.ReflectionUtils; - -/** - * ASM visitor which looks for the annotations defined on a class or method. - * - * @author Juergen Hoeller - * @since 3.0 - */ -final class AnnotationAttributesReadingVisitor implements AnnotationVisitor { - - private final String annotationType; - - private final Map> attributesMap; - - private final Map> metaAnnotationMap; - - private final ClassLoader classLoader; - - private final Map localAttributes = new LinkedHashMap(); - - - public AnnotationAttributesReadingVisitor( - String annotationType, Map> attributesMap, - Map> metaAnnotationMap, ClassLoader classLoader) { - - this.annotationType = annotationType; - this.attributesMap = attributesMap; - this.metaAnnotationMap = metaAnnotationMap; - this.classLoader = classLoader; - } - - - public void visit(String name, Object value) { - this.localAttributes.put(name, value); - } - - public void visitEnum(String name, String desc, String value) { - Object valueToUse = value; - try { - Class enumType = this.classLoader.loadClass(Type.getType(desc).getClassName()); - Field enumConstant = ReflectionUtils.findField(enumType, value); - if (enumConstant != null) { - valueToUse = enumConstant.get(null); - } - } - catch (Exception ex) { - // Class not found - can't resolve class reference in annotation attribute. - } - this.localAttributes.put(name, valueToUse); - } - - public AnnotationVisitor visitAnnotation(String name, String desc) { - return new EmptyVisitor(); - } - - public AnnotationVisitor visitArray(final String attrName) { - return new AnnotationVisitor() { - public void visit(String name, Object value) { - Object newValue = value; - Object existingValue = localAttributes.get(attrName); - if (existingValue != null) { - newValue = ObjectUtils.addObjectToArray((Object[]) existingValue, newValue); - } - else { - Object[] newArray = (Object[]) Array.newInstance(newValue.getClass(), 1); - newArray[0] = newValue; - newValue = newArray; - } - localAttributes.put(attrName, newValue); - } - public void visitEnum(String name, String desc, String value) { - } - public AnnotationVisitor visitAnnotation(String name, String desc) { - return new EmptyVisitor(); - } - public AnnotationVisitor visitArray(String name) { - return new EmptyVisitor(); - } - public void visitEnd() { - } - }; - } - - public void visitEnd() { - this.attributesMap.put(this.annotationType, this.localAttributes); - try { - Class annotationClass = this.classLoader.loadClass(this.annotationType); - // Check declared default values of attributes in the annotation type. - Method[] annotationAttributes = annotationClass.getMethods(); - for (Method annotationAttribute : annotationAttributes) { - String attributeName = annotationAttribute.getName(); - Object defaultValue = annotationAttribute.getDefaultValue(); - if (defaultValue != null && !this.localAttributes.containsKey(attributeName)) { - this.localAttributes.put(attributeName, defaultValue); - } - } - // Register annotations that the annotation type is annotated with. - Set metaAnnotationTypeNames = new LinkedHashSet(); - for (Annotation metaAnnotation : annotationClass.getAnnotations()) { - metaAnnotationTypeNames.add(metaAnnotation.annotationType().getName()); - if (!this.attributesMap.containsKey(metaAnnotation.annotationType().getName())) { - this.attributesMap.put(metaAnnotation.annotationType().getName(), - AnnotationUtils.getAnnotationAttributes(metaAnnotation, true)); - } - for (Annotation metaMetaAnnotation : metaAnnotation.annotationType().getAnnotations()) { - metaAnnotationTypeNames.add(metaMetaAnnotation.annotationType().getName()); - } - } - if (this.metaAnnotationMap != null) { - this.metaAnnotationMap.put(this.annotationType, metaAnnotationTypeNames); - } - } - catch (ClassNotFoundException ex) { - // Class not found - can't determine meta-annotations. - } - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.type.classreading; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +import org.springframework.asm.AnnotationVisitor; +import org.springframework.asm.Type; +import org.springframework.asm.commons.EmptyVisitor; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.util.ReflectionUtils; + +/** + * ASM visitor which looks for the annotations defined on a class or method. + * + * @author Juergen Hoeller + * @since 3.0 + */ +final class AnnotationAttributesReadingVisitor implements AnnotationVisitor { + + private final String annotationType; + + private final Map> attributesMap; + + private final Map> metaAnnotationMap; + + private final ClassLoader classLoader; + + private final Map localAttributes = new LinkedHashMap(); + + + public AnnotationAttributesReadingVisitor( + String annotationType, Map> attributesMap, + Map> metaAnnotationMap, ClassLoader classLoader) { + + this.annotationType = annotationType; + this.attributesMap = attributesMap; + this.metaAnnotationMap = metaAnnotationMap; + this.classLoader = classLoader; + } + + + public void visit(String name, Object value) { + this.localAttributes.put(name, value); + } + + public void visitEnum(String name, String desc, String value) { + Object valueToUse = value; + try { + Class enumType = this.classLoader.loadClass(Type.getType(desc).getClassName()); + Field enumConstant = ReflectionUtils.findField(enumType, value); + if (enumConstant != null) { + valueToUse = enumConstant.get(null); + } + } + catch (Exception ex) { + // Class not found - can't resolve class reference in annotation attribute. + } + this.localAttributes.put(name, valueToUse); + } + + public AnnotationVisitor visitAnnotation(String name, String desc) { + return new EmptyVisitor(); + } + + public AnnotationVisitor visitArray(final String attrName) { + return new AnnotationVisitor() { + public void visit(String name, Object value) { + Object newValue = value; + Object existingValue = localAttributes.get(attrName); + if (existingValue != null) { + newValue = ObjectUtils.addObjectToArray((Object[]) existingValue, newValue); + } + else { + Object[] newArray = (Object[]) Array.newInstance(newValue.getClass(), 1); + newArray[0] = newValue; + newValue = newArray; + } + localAttributes.put(attrName, newValue); + } + public void visitEnum(String name, String desc, String value) { + } + public AnnotationVisitor visitAnnotation(String name, String desc) { + return new EmptyVisitor(); + } + public AnnotationVisitor visitArray(String name) { + return new EmptyVisitor(); + } + public void visitEnd() { + } + }; + } + + public void visitEnd() { + this.attributesMap.put(this.annotationType, this.localAttributes); + try { + Class annotationClass = this.classLoader.loadClass(this.annotationType); + // Check declared default values of attributes in the annotation type. + Method[] annotationAttributes = annotationClass.getMethods(); + for (Method annotationAttribute : annotationAttributes) { + String attributeName = annotationAttribute.getName(); + Object defaultValue = annotationAttribute.getDefaultValue(); + if (defaultValue != null && !this.localAttributes.containsKey(attributeName)) { + this.localAttributes.put(attributeName, defaultValue); + } + } + // Register annotations that the annotation type is annotated with. + Set metaAnnotationTypeNames = new LinkedHashSet(); + for (Annotation metaAnnotation : annotationClass.getAnnotations()) { + metaAnnotationTypeNames.add(metaAnnotation.annotationType().getName()); + if (!this.attributesMap.containsKey(metaAnnotation.annotationType().getName())) { + this.attributesMap.put(metaAnnotation.annotationType().getName(), + AnnotationUtils.getAnnotationAttributes(metaAnnotation, true)); + } + for (Annotation metaMetaAnnotation : metaAnnotation.annotationType().getAnnotations()) { + metaAnnotationTypeNames.add(metaMetaAnnotation.annotationType().getName()); + } + } + if (this.metaAnnotationMap != null) { + this.metaAnnotationMap.put(this.annotationType, metaAnnotationTypeNames); + } + } + catch (ClassNotFoundException ex) { + // Class not found - can't determine meta-annotations. + } + } + +} diff --git a/org.springframework.core/src/main/java/org/springframework/util/CompositeIterator.java b/org.springframework.core/src/main/java/org/springframework/util/CompositeIterator.java index 67935ae6b4..1e70018f5c 100644 --- a/org.springframework.core/src/main/java/org/springframework/util/CompositeIterator.java +++ b/org.springframework.core/src/main/java/org/springframework/util/CompositeIterator.java @@ -1,75 +1,75 @@ -/* - * Copyright 2004-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.util; - -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.NoSuchElementException; - -/** - * Iterator that combines multiple other iterators. - * This implementation maintains a list of iterators which are invoked in sequence until all iterators are exhausted. - * @author Erwin Vervaet - */ -public class CompositeIterator implements Iterator { - - private List> iterators = new LinkedList>(); - - private boolean inUse = false; - - /** - * Create a new composite iterator. Add iterators using the {@link #add(Iterator)} method. - */ - public CompositeIterator() { - } - - /** - * Add given iterator to this composite. - */ - public void add(Iterator iterator) { - Assert.state(!inUse, "You can no longer add iterator to a composite iterator that's already in use"); - if (iterators.contains(iterator)) { - throw new IllegalArgumentException("You cannot add the same iterator twice"); - } - iterators.add(iterator); - } - - public boolean hasNext() { - inUse = true; - for (Iterator> it = iterators.iterator(); it.hasNext();) { - if (it.next().hasNext()) { - return true; - } - } - return false; - } - - public E next() { - inUse = true; - for (Iterator> it = iterators.iterator(); it.hasNext();) { - Iterator iterator = it.next(); - if (iterator.hasNext()) { - return iterator.next(); - } - } - throw new NoSuchElementException("Exhaused all iterators"); - } - - public void remove() { - throw new UnsupportedOperationException("Remove is not supported"); - } +/* + * Copyright 2004-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.util; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.NoSuchElementException; + +/** + * Iterator that combines multiple other iterators. + * This implementation maintains a list of iterators which are invoked in sequence until all iterators are exhausted. + * @author Erwin Vervaet + */ +public class CompositeIterator implements Iterator { + + private List> iterators = new LinkedList>(); + + private boolean inUse = false; + + /** + * Create a new composite iterator. Add iterators using the {@link #add(Iterator)} method. + */ + public CompositeIterator() { + } + + /** + * Add given iterator to this composite. + */ + public void add(Iterator iterator) { + Assert.state(!inUse, "You can no longer add iterator to a composite iterator that's already in use"); + if (iterators.contains(iterator)) { + throw new IllegalArgumentException("You cannot add the same iterator twice"); + } + iterators.add(iterator); + } + + public boolean hasNext() { + inUse = true; + for (Iterator> it = iterators.iterator(); it.hasNext();) { + if (it.next().hasNext()) { + return true; + } + } + return false; + } + + public E next() { + inUse = true; + for (Iterator> it = iterators.iterator(); it.hasNext();) { + Iterator iterator = it.next(); + if (iterator.hasNext()) { + return iterator.next(); + } + } + throw new NoSuchElementException("Exhaused all iterators"); + } + + public void remove() { + throw new UnsupportedOperationException("Remove is not supported"); + } } \ No newline at end of file diff --git a/org.springframework.core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java b/org.springframework.core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java index e5df7256ec..a756f3d34a 100644 --- a/org.springframework.core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java +++ b/org.springframework.core/src/main/java/org/springframework/util/LinkedCaseInsensitiveMap.java @@ -1,149 +1,149 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Locale; -import java.util.Map; - -/** - * {@link LinkedHashMap} variant that stores String keys in a case-insensitive - * manner, for example for key-based access in a results table. - * - *

Preserves the original order as well as the original casing of keys, - * while allowing for contains, get and remove calls with any case of key. - * - *

Does not support null keys. - * - * @author Juergen Hoeller - * @since 3.0 - */ -public class LinkedCaseInsensitiveMap extends LinkedHashMap { - - private final Map caseInsensitiveKeys; - - private final Locale locale; - - - /** - * Create a new LinkedCaseInsensitiveMap for the default Locale. - * @see java.lang.String#toLowerCase() - */ - public LinkedCaseInsensitiveMap() { - this(null); - } - - /** - * Create a new LinkedCaseInsensitiveMap that stores lower-case keys - * according to the given Locale. - * @param locale the Locale to use for lower-case conversion - * @see java.lang.String#toLowerCase(java.util.Locale) - */ - public LinkedCaseInsensitiveMap(Locale locale) { - super(); - this.caseInsensitiveKeys = new HashMap(); - this.locale = (locale != null ? locale : Locale.getDefault()); - } - - /** - * Create a new LinkedCaseInsensitiveMap that wraps a {@link LinkedHashMap} - * with the given initial capacity and stores lower-case keys according - * to the default Locale. - * @param initialCapacity the initial capacity - * @see java.lang.String#toLowerCase() - */ - public LinkedCaseInsensitiveMap(int initialCapacity) { - this(initialCapacity, null); - } - - /** - * Create a new LinkedCaseInsensitiveMap that wraps a {@link LinkedHashMap} - * with the given initial capacity and stores lower-case keys according - * to the given Locale. - * @param initialCapacity the initial capacity - * @param locale the Locale to use for lower-case conversion - * @see java.lang.String#toLowerCase(java.util.Locale) - */ - public LinkedCaseInsensitiveMap(int initialCapacity, Locale locale) { - super(initialCapacity); - this.caseInsensitiveKeys = new HashMap(initialCapacity); - this.locale = (locale != null ? locale : Locale.getDefault()); - } - - - @Override - public V put(String key, V value) { - this.caseInsensitiveKeys.put(convertKey(key), key); - return super.put(key, value); - } - - @Override - public void putAll(Map map) { - if (map.isEmpty()) { - return; - } - for (Map.Entry entry : map.entrySet()) { - put(entry.getKey(), entry.getValue()); - } - } - - @Override - public boolean containsKey(Object key) { - return (key instanceof String && this.caseInsensitiveKeys.containsKey(convertKey((String) key))); - } - - @Override - public V get(Object key) { - if (key instanceof String) { - return super.get(this.caseInsensitiveKeys.get(convertKey((String) key))); - } - else { - return null; - } - } - - @Override - public V remove(Object key) { - if (key instanceof String ) { - return super.remove(this.caseInsensitiveKeys.remove(convertKey((String) key))); - } - else { - return null; - } - } - - @Override - public void clear() { - this.caseInsensitiveKeys.clear(); - super.clear(); - } - - - /** - * Convert the given key to a case-insensitive key. - *

The default implementation converts the key - * to lower-case according to this Map's Locale. - * @param key the user-specified key - * @return the key to use for storing - * @see java.lang.String#toLowerCase(java.util.Locale) - */ - protected String convertKey(String key) { - return key.toLowerCase(this.locale); - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; + +/** + * {@link LinkedHashMap} variant that stores String keys in a case-insensitive + * manner, for example for key-based access in a results table. + * + *

Preserves the original order as well as the original casing of keys, + * while allowing for contains, get and remove calls with any case of key. + * + *

Does not support null keys. + * + * @author Juergen Hoeller + * @since 3.0 + */ +public class LinkedCaseInsensitiveMap extends LinkedHashMap { + + private final Map caseInsensitiveKeys; + + private final Locale locale; + + + /** + * Create a new LinkedCaseInsensitiveMap for the default Locale. + * @see java.lang.String#toLowerCase() + */ + public LinkedCaseInsensitiveMap() { + this(null); + } + + /** + * Create a new LinkedCaseInsensitiveMap that stores lower-case keys + * according to the given Locale. + * @param locale the Locale to use for lower-case conversion + * @see java.lang.String#toLowerCase(java.util.Locale) + */ + public LinkedCaseInsensitiveMap(Locale locale) { + super(); + this.caseInsensitiveKeys = new HashMap(); + this.locale = (locale != null ? locale : Locale.getDefault()); + } + + /** + * Create a new LinkedCaseInsensitiveMap that wraps a {@link LinkedHashMap} + * with the given initial capacity and stores lower-case keys according + * to the default Locale. + * @param initialCapacity the initial capacity + * @see java.lang.String#toLowerCase() + */ + public LinkedCaseInsensitiveMap(int initialCapacity) { + this(initialCapacity, null); + } + + /** + * Create a new LinkedCaseInsensitiveMap that wraps a {@link LinkedHashMap} + * with the given initial capacity and stores lower-case keys according + * to the given Locale. + * @param initialCapacity the initial capacity + * @param locale the Locale to use for lower-case conversion + * @see java.lang.String#toLowerCase(java.util.Locale) + */ + public LinkedCaseInsensitiveMap(int initialCapacity, Locale locale) { + super(initialCapacity); + this.caseInsensitiveKeys = new HashMap(initialCapacity); + this.locale = (locale != null ? locale : Locale.getDefault()); + } + + + @Override + public V put(String key, V value) { + this.caseInsensitiveKeys.put(convertKey(key), key); + return super.put(key, value); + } + + @Override + public void putAll(Map map) { + if (map.isEmpty()) { + return; + } + for (Map.Entry entry : map.entrySet()) { + put(entry.getKey(), entry.getValue()); + } + } + + @Override + public boolean containsKey(Object key) { + return (key instanceof String && this.caseInsensitiveKeys.containsKey(convertKey((String) key))); + } + + @Override + public V get(Object key) { + if (key instanceof String) { + return super.get(this.caseInsensitiveKeys.get(convertKey((String) key))); + } + else { + return null; + } + } + + @Override + public V remove(Object key) { + if (key instanceof String ) { + return super.remove(this.caseInsensitiveKeys.remove(convertKey((String) key))); + } + else { + return null; + } + } + + @Override + public void clear() { + this.caseInsensitiveKeys.clear(); + super.clear(); + } + + + /** + * Convert the given key to a case-insensitive key. + *

The default implementation converts the key + * to lower-case according to this Map's Locale. + * @param key the user-specified key + * @return the key to use for storing + * @see java.lang.String#toLowerCase(java.util.Locale) + */ + protected String convertKey(String key) { + return key.toLowerCase(this.locale); + } + +} diff --git a/org.springframework.core/src/test/java/org/springframework/core/ExceptionDepthComparatorTests.java b/org.springframework.core/src/test/java/org/springframework/core/ExceptionDepthComparatorTests.java index 33176f7114..0e18a067db 100644 --- a/org.springframework.core/src/test/java/org/springframework/core/ExceptionDepthComparatorTests.java +++ b/org.springframework.core/src/test/java/org/springframework/core/ExceptionDepthComparatorTests.java @@ -1,105 +1,105 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.util.Arrays; - -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * @author Juergen Hoeller - * @author Chris Shepperd - */ -public class ExceptionDepthComparatorTests { - - @Test - public void targetBeforeSameDepth() throws Exception { - Class foundClass = findClosestMatch(TargetException.class, SameDepthException.class); - assertEquals(TargetException.class, foundClass); - } - - @Test - public void sameDepthBeforeTarget() throws Exception { - Class foundClass = findClosestMatch(SameDepthException.class, TargetException.class); - assertEquals(TargetException.class, foundClass); - } - - @Test - public void lowestDepthBeforeTarget() throws Exception { - Class foundClass = findClosestMatch(LowestDepthException.class, TargetException.class); - assertEquals(TargetException.class, foundClass); - } - - @Test - public void targetBeforeLowestDepth() throws Exception { - Class foundClass = findClosestMatch(TargetException.class, LowestDepthException.class); - assertEquals(TargetException.class, foundClass); - } - - @Test - public void noDepthBeforeTarget() throws Exception { - Class foundClass = findClosestMatch(NoDepthException.class, TargetException.class); - assertEquals(TargetException.class, foundClass); - } - - @Test - public void noDepthBeforeHighestDepth() throws Exception { - Class foundClass = findClosestMatch(NoDepthException.class, HighestDepthException.class); - assertEquals(HighestDepthException.class, foundClass); - } - - @Test - public void highestDepthBeforeNoDepth() throws Exception { - Class foundClass = findClosestMatch(HighestDepthException.class, NoDepthException.class); - assertEquals(HighestDepthException.class, foundClass); - } - - @Test - public void highestDepthBeforeLowestDepth() throws Exception { - Class foundClass = findClosestMatch(HighestDepthException.class, LowestDepthException.class); - assertEquals(LowestDepthException.class, foundClass); - } - - @Test - public void lowestDepthBeforeHighestDepth() throws Exception { - Class foundClass = findClosestMatch(LowestDepthException.class, HighestDepthException.class); - assertEquals(LowestDepthException.class, foundClass); - } - - private Class findClosestMatch(Class... classes) { - return ExceptionDepthComparator.findClosestMatch(Arrays.asList(classes), new TargetException()); - } - - - public class HighestDepthException extends Throwable { - } - - public class LowestDepthException extends HighestDepthException { - } - - public class TargetException extends LowestDepthException { - } - - public class SameDepthException extends LowestDepthException { - } - - public class NoDepthException extends TargetException { - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.util.Arrays; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * @author Juergen Hoeller + * @author Chris Shepperd + */ +public class ExceptionDepthComparatorTests { + + @Test + public void targetBeforeSameDepth() throws Exception { + Class foundClass = findClosestMatch(TargetException.class, SameDepthException.class); + assertEquals(TargetException.class, foundClass); + } + + @Test + public void sameDepthBeforeTarget() throws Exception { + Class foundClass = findClosestMatch(SameDepthException.class, TargetException.class); + assertEquals(TargetException.class, foundClass); + } + + @Test + public void lowestDepthBeforeTarget() throws Exception { + Class foundClass = findClosestMatch(LowestDepthException.class, TargetException.class); + assertEquals(TargetException.class, foundClass); + } + + @Test + public void targetBeforeLowestDepth() throws Exception { + Class foundClass = findClosestMatch(TargetException.class, LowestDepthException.class); + assertEquals(TargetException.class, foundClass); + } + + @Test + public void noDepthBeforeTarget() throws Exception { + Class foundClass = findClosestMatch(NoDepthException.class, TargetException.class); + assertEquals(TargetException.class, foundClass); + } + + @Test + public void noDepthBeforeHighestDepth() throws Exception { + Class foundClass = findClosestMatch(NoDepthException.class, HighestDepthException.class); + assertEquals(HighestDepthException.class, foundClass); + } + + @Test + public void highestDepthBeforeNoDepth() throws Exception { + Class foundClass = findClosestMatch(HighestDepthException.class, NoDepthException.class); + assertEquals(HighestDepthException.class, foundClass); + } + + @Test + public void highestDepthBeforeLowestDepth() throws Exception { + Class foundClass = findClosestMatch(HighestDepthException.class, LowestDepthException.class); + assertEquals(LowestDepthException.class, foundClass); + } + + @Test + public void lowestDepthBeforeHighestDepth() throws Exception { + Class foundClass = findClosestMatch(LowestDepthException.class, HighestDepthException.class); + assertEquals(LowestDepthException.class, foundClass); + } + + private Class findClosestMatch(Class... classes) { + return ExceptionDepthComparator.findClosestMatch(Arrays.asList(classes), new TargetException()); + } + + + public class HighestDepthException extends Throwable { + } + + public class LowestDepthException extends HighestDepthException { + } + + public class TargetException extends LowestDepthException { + } + + public class SameDepthException extends LowestDepthException { + } + + public class NoDepthException extends TargetException { + } + +} diff --git a/org.springframework.core/src/test/java/org/springframework/core/GenericTypeResolverTests.java b/org.springframework.core/src/test/java/org/springframework/core/GenericTypeResolverTests.java index c1568ff8cd..5514e0376c 100644 --- a/org.springframework.core/src/test/java/org/springframework/core/GenericTypeResolverTests.java +++ b/org.springframework.core/src/test/java/org/springframework/core/GenericTypeResolverTests.java @@ -1,97 +1,97 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.util.Collection; - -import org.junit.Test; - -import org.springframework.util.ReflectionUtils; - -import static org.junit.Assert.*; - -/** - * @author Juergen Hoeller - */ -public class GenericTypeResolverTests { - - @Test - public void testSimpleInterfaceType() { - assertEquals(String.class, GenericTypeResolver.resolveTypeArgument(MySimpleInterfaceType.class, MyInterfaceType.class)); - } - - @Test - public void testSimpleCollectionInterfaceType() { - assertEquals(Collection.class, GenericTypeResolver.resolveTypeArgument(MyCollectionInterfaceType.class, MyInterfaceType.class)); - } - - @Test - public void testSimpleSuperclassType() { - assertEquals(String.class, GenericTypeResolver.resolveTypeArgument(MySimpleSuperclassType.class, MySuperclassType.class)); - } - - @Test - public void testSimpleCollectionSuperclassType() { - assertEquals(Collection.class, GenericTypeResolver.resolveTypeArgument(MyCollectionSuperclassType.class, MySuperclassType.class)); - } - - @Test - public void testMethodReturnType() { - assertEquals(Integer.class, GenericTypeResolver.resolveReturnTypeArgument(ReflectionUtils.findMethod(MyTypeWithMethods.class, "integer"), MyInterfaceType.class)); - assertEquals(String.class, GenericTypeResolver.resolveReturnTypeArgument(ReflectionUtils.findMethod(MyTypeWithMethods.class, "string"), MyInterfaceType.class)); - assertEquals(null, GenericTypeResolver.resolveReturnTypeArgument(ReflectionUtils.findMethod(MyTypeWithMethods.class, "raw"), MyInterfaceType.class)); - assertEquals(null, GenericTypeResolver.resolveReturnTypeArgument(ReflectionUtils.findMethod(MyTypeWithMethods.class, "object"), MyInterfaceType.class)); - } - - @Test - public void testNullIfNotResolvable() { - GenericClass obj = new GenericClass(); - assertNull(GenericTypeResolver.resolveTypeArgument(obj.getClass(), GenericClass.class)); - } - - - public interface MyInterfaceType { - } - - public class MySimpleInterfaceType implements MyInterfaceType { - } - - public class MyCollectionInterfaceType implements MyInterfaceType> { - } - - - public abstract class MySuperclassType { - } - - public class MySimpleSuperclassType extends MySuperclassType { - } - - public class MyCollectionSuperclassType extends MySuperclassType> { - } - - public class MyTypeWithMethods { - public MyInterfaceType integer() { return null; } - public MySimpleInterfaceType string() { return null; } - public Object object() { return null; } - @SuppressWarnings("rawtypes") - public MyInterfaceType raw() { return null; } - } - - static class GenericClass { - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.util.Collection; + +import org.junit.Test; + +import org.springframework.util.ReflectionUtils; + +import static org.junit.Assert.*; + +/** + * @author Juergen Hoeller + */ +public class GenericTypeResolverTests { + + @Test + public void testSimpleInterfaceType() { + assertEquals(String.class, GenericTypeResolver.resolveTypeArgument(MySimpleInterfaceType.class, MyInterfaceType.class)); + } + + @Test + public void testSimpleCollectionInterfaceType() { + assertEquals(Collection.class, GenericTypeResolver.resolveTypeArgument(MyCollectionInterfaceType.class, MyInterfaceType.class)); + } + + @Test + public void testSimpleSuperclassType() { + assertEquals(String.class, GenericTypeResolver.resolveTypeArgument(MySimpleSuperclassType.class, MySuperclassType.class)); + } + + @Test + public void testSimpleCollectionSuperclassType() { + assertEquals(Collection.class, GenericTypeResolver.resolveTypeArgument(MyCollectionSuperclassType.class, MySuperclassType.class)); + } + + @Test + public void testMethodReturnType() { + assertEquals(Integer.class, GenericTypeResolver.resolveReturnTypeArgument(ReflectionUtils.findMethod(MyTypeWithMethods.class, "integer"), MyInterfaceType.class)); + assertEquals(String.class, GenericTypeResolver.resolveReturnTypeArgument(ReflectionUtils.findMethod(MyTypeWithMethods.class, "string"), MyInterfaceType.class)); + assertEquals(null, GenericTypeResolver.resolveReturnTypeArgument(ReflectionUtils.findMethod(MyTypeWithMethods.class, "raw"), MyInterfaceType.class)); + assertEquals(null, GenericTypeResolver.resolveReturnTypeArgument(ReflectionUtils.findMethod(MyTypeWithMethods.class, "object"), MyInterfaceType.class)); + } + + @Test + public void testNullIfNotResolvable() { + GenericClass obj = new GenericClass(); + assertNull(GenericTypeResolver.resolveTypeArgument(obj.getClass(), GenericClass.class)); + } + + + public interface MyInterfaceType { + } + + public class MySimpleInterfaceType implements MyInterfaceType { + } + + public class MyCollectionInterfaceType implements MyInterfaceType> { + } + + + public abstract class MySuperclassType { + } + + public class MySimpleSuperclassType extends MySuperclassType { + } + + public class MyCollectionSuperclassType extends MySuperclassType> { + } + + public class MyTypeWithMethods { + public MyInterfaceType integer() { return null; } + public MySimpleInterfaceType string() { return null; } + public Object object() { return null; } + @SuppressWarnings("rawtypes") + public MyInterfaceType raw() { return null; } + } + + static class GenericClass { + } + +} diff --git a/org.springframework.core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java b/org.springframework.core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java index 4e5dd880ea..5241788c3a 100644 --- a/org.springframework.core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java +++ b/org.springframework.core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java @@ -1,801 +1,801 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.convert; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.junit.Test; - -import org.springframework.core.MethodParameter; - -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertTrue; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -/** - * @author Keith Donald - * @author Andy Clement - */ -@SuppressWarnings("rawtypes") -public class TypeDescriptorTests { - - public List listOfString; - - public List> listOfListOfString = new ArrayList>(); - - public List listOfListOfUnknown = new ArrayList(); - - public int[] intArray; - - public List[] arrayOfListOfString; - - public List listField = new ArrayList(); - - public Map mapField = new HashMap(); - - public Map> nestedMapField = new HashMap>(); - - @Test - public void parameterPrimitive() throws Exception { - TypeDescriptor desc = new TypeDescriptor(new MethodParameter(getClass().getMethod("testParameterPrimitive", int.class), 0)); - assertEquals(int.class, desc.getType()); - assertEquals(Integer.class, desc.getObjectType()); - assertEquals("int", desc.getName()); - assertEquals("int", desc.toString()); - assertTrue(desc.isPrimitive()); - assertEquals(0, desc.getAnnotations().length); - assertFalse(desc.isCollection()); - assertFalse(desc.isMap()); - } - - public void testParameterPrimitive(int primitive) { - - } - - @Test - public void parameterScalar() throws Exception { - TypeDescriptor desc = new TypeDescriptor(new MethodParameter(getClass().getMethod("testParameterScalar", String.class), 0)); - assertEquals(String.class, desc.getType()); - assertEquals(String.class, desc.getObjectType()); - assertEquals("java.lang.String", desc.getName()); - assertEquals("java.lang.String", desc.toString()); - assertTrue(!desc.isPrimitive()); - assertEquals(0, desc.getAnnotations().length); - assertFalse(desc.isCollection()); - assertFalse(desc.isArray()); - assertFalse(desc.isMap()); - } - - public void testParameterScalar(String value) { - - } - - @Test - public void parameterList() throws Exception { - MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterList", List.class), 0); - TypeDescriptor desc = new TypeDescriptor(methodParameter); - assertEquals(List.class, desc.getType()); - assertEquals(List.class, desc.getObjectType()); - assertEquals("java.util.List", desc.getName()); - assertEquals("java.util.List>>", desc.toString()); - assertTrue(!desc.isPrimitive()); - assertEquals(0, desc.getAnnotations().length); - assertTrue(desc.isCollection()); - assertFalse(desc.isArray()); - assertEquals(List.class, desc.getElementTypeDescriptor().getType()); - assertEquals(TypeDescriptor.nested(methodParameter, 1), desc.getElementTypeDescriptor()); - assertEquals(TypeDescriptor.nested(methodParameter, 2), desc.getElementTypeDescriptor().getElementTypeDescriptor()); - assertEquals(TypeDescriptor.nested(methodParameter, 3), desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapValueTypeDescriptor()); - assertEquals(Integer.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapKeyTypeDescriptor().getType()); - assertEquals(Enum.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapValueTypeDescriptor().getType()); - assertFalse(desc.isMap()); - } - - public void testParameterList(List>>> list) { - - } - - @Test - public void parameterListNoParamTypes() throws Exception { - MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterListNoParamTypes", List.class), 0); - TypeDescriptor desc = new TypeDescriptor(methodParameter); - assertEquals(List.class, desc.getType()); - assertEquals(List.class, desc.getObjectType()); - assertEquals("java.util.List", desc.getName()); - assertEquals("java.util.List", desc.toString()); - assertTrue(!desc.isPrimitive()); - assertEquals(0, desc.getAnnotations().length); - assertTrue(desc.isCollection()); - assertFalse(desc.isArray()); - assertNull(desc.getElementTypeDescriptor()); - assertFalse(desc.isMap()); - } - - public void testParameterListNoParamTypes(List list) { - - } - - @Test - public void parameterArray() throws Exception { - MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterArray", Integer[].class), 0); - TypeDescriptor desc = new TypeDescriptor(methodParameter); - assertEquals(Integer[].class, desc.getType()); - assertEquals(Integer[].class, desc.getObjectType()); - assertEquals("java.lang.Integer[]", desc.getName()); - assertEquals("java.lang.Integer[]", desc.toString()); - assertTrue(!desc.isPrimitive()); - assertEquals(0, desc.getAnnotations().length); - assertFalse(desc.isCollection()); - assertTrue(desc.isArray()); - assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); - assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor()); - assertFalse(desc.isMap()); - } - - public void testParameterArray(Integer[] array) { - - } - - @Test - public void parameterMap() throws Exception { - MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterMap", Map.class), 0); - TypeDescriptor desc = new TypeDescriptor(methodParameter); - assertEquals(Map.class, desc.getType()); - assertEquals(Map.class, desc.getObjectType()); - assertEquals("java.util.Map", desc.getName()); - assertEquals("java.util.Map>", desc.toString()); - assertTrue(!desc.isPrimitive()); - assertEquals(0, desc.getAnnotations().length); - assertFalse(desc.isCollection()); - assertFalse(desc.isArray()); - assertTrue(desc.isMap()); - assertEquals(TypeDescriptor.nested(methodParameter, 1), desc.getMapValueTypeDescriptor()); - assertEquals(TypeDescriptor.nested(methodParameter, 2), desc.getMapValueTypeDescriptor().getElementTypeDescriptor()); - assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getType()); - assertEquals(List.class, desc.getMapValueTypeDescriptor().getType()); - assertEquals(String.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); - } - - public void testParameterMap(Map> map) { - - } - - @Test - public void parameterAnnotated() throws Exception { - TypeDescriptor t1 = new TypeDescriptor(new MethodParameter(getClass().getMethod("testAnnotatedMethod", String.class), 0)); - assertEquals(String.class, t1.getType()); - assertEquals(1, t1.getAnnotations().length); - assertNotNull(t1.getAnnotation(ParameterAnnotation.class)); - } - - @Target({ElementType.PARAMETER}) - @Retention(RetentionPolicy.RUNTIME) - public @interface ParameterAnnotation { - - } - - public void testAnnotatedMethod(@ParameterAnnotation String parameter) { - - } - - @Test - public void propertyComplex() throws Exception { - Property property = new Property(getClass(), getClass().getMethod("getComplexProperty"), getClass().getMethod("setComplexProperty", Map.class)); - TypeDescriptor desc = new TypeDescriptor(property); - assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType()); - assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getElementTypeDescriptor().getType()); - } - - public Map>> getComplexProperty() { - return null; - } - - public void setComplexProperty(Map>> complexProperty) { - - } - - @Test - public void propertyGenericType() throws Exception { - GenericType genericBean = new IntegerType(); - Property property = new Property(getClass(), genericBean.getClass().getMethod("getProperty"), genericBean.getClass().getMethod("setProperty", Integer.class)); - TypeDescriptor desc = new TypeDescriptor(property); - assertEquals(Integer.class, desc.getType()); - } - - @Test - public void propertyTypeCovariance() throws Exception { - GenericType genericBean = new NumberType(); - Property property = new Property(getClass(), genericBean.getClass().getMethod("getProperty"), genericBean.getClass().getMethod("setProperty", Number.class)); - TypeDescriptor desc = new TypeDescriptor(property); - assertEquals(Integer.class, desc.getType()); - } - - @Test - public void propertyGenericTypeList() throws Exception { - GenericType genericBean = new IntegerType(); - Property property = new Property(getClass(), genericBean.getClass().getMethod("getListProperty"), genericBean.getClass().getMethod("setListProperty", List.class)); - TypeDescriptor desc = new TypeDescriptor(property); - assertEquals(List.class, desc.getType()); - assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); - } - - public interface GenericType { - T getProperty(); - - void setProperty(T t); - - List getListProperty(); - - void setListProperty(List t); - - } - - public class IntegerType implements GenericType { - - public Integer getProperty() { - return null; - } - - public void setProperty(Integer t) { - } - - public List getListProperty() { - return null; - } - - public void setListProperty(List t) { - } - } - - public class NumberType implements GenericType { - - public Integer getProperty() { - return null; - } - - public void setProperty(Number t) { - } - - public List getListProperty() { - return null; - } - - public void setListProperty(List t) { - } - } - - @Test - public void propertyGenericClassList() throws Exception { - IntegerClass genericBean = new IntegerClass(); - Property property = new Property(genericBean.getClass(), genericBean.getClass().getMethod("getListProperty"), genericBean.getClass().getMethod("setListProperty", List.class)); - TypeDescriptor desc = new TypeDescriptor(property); - assertEquals(List.class, desc.getType()); - assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); - assertNotNull(desc.getAnnotation(MethodAnnotation1.class)); - } - - public static class GenericClass { - - public T getProperty() { - return null; - } - - public void setProperty(T t) { - } - - @MethodAnnotation1 - public List getListProperty() { - return null; - } - - public void setListProperty(List t) { - } - - } - - public static class IntegerClass extends GenericClass { - - } - - @Test - public void property() throws Exception { - Property property = new Property(getClass(), getClass().getMethod("getProperty"), getClass().getMethod("setProperty", Map.class)); - TypeDescriptor desc = new TypeDescriptor(property); - assertEquals(Map.class, desc.getType()); - assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getElementTypeDescriptor().getType()); - assertEquals(Long.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); - assertNotNull(desc.getAnnotation(MethodAnnotation1.class)); - assertNotNull(desc.getAnnotation(MethodAnnotation2.class)); - assertNotNull(desc.getAnnotation(MethodAnnotation3.class)); - } - - @MethodAnnotation1 - public Map, List> getProperty() { - return property; - } - - @MethodAnnotation2 - public void setProperty(Map, List> property) { - this.property = property; - } - - @MethodAnnotation3 - private Map, List> property; - - @Target({ElementType.METHOD}) - @Retention(RetentionPolicy.RUNTIME) - public @interface MethodAnnotation1 { - - } - - @Target({ElementType.METHOD}) - @Retention(RetentionPolicy.RUNTIME) - public @interface MethodAnnotation2 { - - } - - @Target({ElementType.FIELD}) - @Retention(RetentionPolicy.RUNTIME) - public @interface MethodAnnotation3 { - - } - - @Test - public void fieldScalar() throws Exception { - TypeDescriptor typeDescriptor = new TypeDescriptor(getClass().getField("fieldScalar")); - assertFalse(typeDescriptor.isPrimitive()); - assertFalse(typeDescriptor.isArray()); - assertFalse(typeDescriptor.isCollection()); - assertFalse(typeDescriptor.isMap()); - assertEquals(Integer.class, typeDescriptor.getType()); - assertEquals(Integer.class, typeDescriptor.getObjectType()); - } - - public Integer fieldScalar; - - @Test - public void fieldList() throws Exception { - TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfString")); - assertFalse(typeDescriptor.isArray()); - assertEquals(List.class, typeDescriptor.getType()); - assertEquals(String.class, typeDescriptor.getElementTypeDescriptor().getType()); - assertEquals("java.util.List", typeDescriptor.toString()); - } - - @Test - public void fieldListOfListOfString() throws Exception { - TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfListOfString")); - assertFalse(typeDescriptor.isArray()); - assertEquals(List.class, typeDescriptor.getType()); - assertEquals(List.class, typeDescriptor.getElementTypeDescriptor().getType()); - assertEquals(String.class, typeDescriptor.getElementTypeDescriptor().getElementTypeDescriptor().getType()); - assertEquals("java.util.List>", typeDescriptor.toString()); - } - - @Test - public void fieldListOfListUnknown() throws Exception { - TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfListOfUnknown")); - assertFalse(typeDescriptor.isArray()); - assertEquals(List.class, typeDescriptor.getType()); - assertEquals(List.class, typeDescriptor.getElementTypeDescriptor().getType()); - assertNull(typeDescriptor.getElementTypeDescriptor().getElementTypeDescriptor()); - assertEquals("java.util.List>", typeDescriptor.toString()); - } - - @Test - public void fieldArray() throws Exception { - TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("intArray")); - assertTrue(typeDescriptor.isArray()); - assertEquals(Integer.TYPE,typeDescriptor.getElementTypeDescriptor().getType()); - assertEquals("int[]",typeDescriptor.toString()); - } - - @Test - public void fieldComplexTypeDescriptor() throws Exception { - TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("arrayOfListOfString")); - assertTrue(typeDescriptor.isArray()); - assertEquals(List.class,typeDescriptor.getElementTypeDescriptor().getType()); - assertEquals(String.class, typeDescriptor.getElementTypeDescriptor().getElementTypeDescriptor().getType()); - assertEquals("java.util.List[]",typeDescriptor.toString()); - } - - @Test - public void fieldComplexTypeDescriptor2() throws Exception { - TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("nestedMapField")); - assertTrue(typeDescriptor.isMap()); - assertEquals(String.class,typeDescriptor.getMapKeyTypeDescriptor().getType()); - assertEquals(List.class, typeDescriptor.getMapValueTypeDescriptor().getType()); - assertEquals(Integer.class, typeDescriptor.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); - assertEquals("java.util.Map>", typeDescriptor.toString()); - } - - @Test - public void fieldMap() throws Exception { - TypeDescriptor desc = new TypeDescriptor(TypeDescriptorTests.class.getField("fieldMap")); - assertTrue(desc.isMap()); - assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getElementTypeDescriptor().getType()); - assertEquals(Long.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); - } - - public Map, List> fieldMap; - - @Test - public void fieldAnnotated() throws Exception { - TypeDescriptor typeDescriptor = new TypeDescriptor(getClass().getField("fieldAnnotated")); - assertEquals(1, typeDescriptor.getAnnotations().length); - assertNotNull(typeDescriptor.getAnnotation(FieldAnnotation.class)); - } - - @FieldAnnotation - public List fieldAnnotated; - - @Target({ElementType.FIELD}) - @Retention(RetentionPolicy.RUNTIME) - public @interface FieldAnnotation { - - } - - @Test - public void valueOfScalar() { - TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(Integer.class); - assertFalse(typeDescriptor.isPrimitive()); - assertFalse(typeDescriptor.isArray()); - assertFalse(typeDescriptor.isCollection()); - assertFalse(typeDescriptor.isMap()); - assertEquals(Integer.class, typeDescriptor.getType()); - assertEquals(Integer.class, typeDescriptor.getObjectType()); - } - - @Test - public void valueOfPrimitive() { - TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(int.class); - assertTrue(typeDescriptor.isPrimitive()); - assertFalse(typeDescriptor.isArray()); - assertFalse(typeDescriptor.isCollection()); - assertFalse(typeDescriptor.isMap()); - assertEquals(Integer.TYPE, typeDescriptor.getType()); - assertEquals(Integer.class, typeDescriptor.getObjectType()); - } - - @Test - public void valueOfArray() throws Exception { - TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(int[].class); - assertTrue(typeDescriptor.isArray()); - assertFalse(typeDescriptor.isCollection()); - assertFalse(typeDescriptor.isMap()); - assertEquals(Integer.TYPE, typeDescriptor.getElementTypeDescriptor().getType()); - } - - @Test - public void valueOfCollection() throws Exception { - TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(Collection.class); - assertTrue(typeDescriptor.isCollection()); - assertFalse(typeDescriptor.isArray()); - assertFalse(typeDescriptor.isMap()); - assertNull(typeDescriptor.getElementTypeDescriptor()); - } - - @Test - public void forObject() { - TypeDescriptor desc = TypeDescriptor.forObject("3"); - assertEquals(String.class, desc.getType()); - } - - @Test - public void forObjectNullTypeDescriptor() { - TypeDescriptor desc = TypeDescriptor.forObject(null); - assertNull(desc); - } - - @Test - public void nestedMethodParameterType2Levels() throws Exception { - TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test2", List.class), 0), 2); - assertEquals(String.class, t1.getType()); - } - - @Test - public void nestedMethodParameterTypeMap() throws Exception { - TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test3", Map.class), 0), 1); - assertEquals(String.class, t1.getType()); - } - - @Test - public void nestedMethodParameterTypeMapTwoLevels() throws Exception { - TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test4", List.class), 0), 2); - assertEquals(String.class, t1.getType()); - } - - @Test(expected=IllegalArgumentException.class) - public void nestedMethodParameterNot1NestedLevel() throws Exception { - TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test4", List.class), 0, 2), 2); - } - - @Test(expected=IllegalStateException.class) - public void nestedTooManyLevels() throws Exception { - TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test4", List.class), 0), 3); - assertEquals(String.class, t1.getType()); - } - - @Test(expected=IllegalStateException.class) - public void nestedMethodParameterTypeNotNestable() throws Exception { - TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test5", String.class), 0), 2); - } - - @Test(expected=IllegalArgumentException.class) - public void nestedMethodParameterTypeInvalidNestingLevel() throws Exception { - TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test5", String.class), 0, 2), 2); - } - - public void test1(List param1) { - - } - - public void test2(List> param1) { - - } - - public void test3(Map param1) { - - } - - public void test4(List> param1) { - - } - - public void test5(String param1) { - - } - - @Test - public void nestedNotParameterized() throws Exception { - TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test6", List.class), 0), 1); - assertEquals(List.class,t1.getType()); - assertEquals("java.util.List", t1.toString()); - TypeDescriptor t2 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test6", List.class), 0), 2); - assertNull(t2); - } - - public void test6(List param1) { - - } - - @Test - public void nestedFieldTypeMapTwoLevels() throws Exception { - TypeDescriptor t1 = TypeDescriptor.nested(getClass().getField("test4"), 2); - assertEquals(String.class, t1.getType()); - } - - public List> test4; - - @Test - public void nestedPropertyTypeMapTwoLevels() throws Exception { - Property property = new Property(getClass(), getClass().getMethod("getTest4"), getClass().getMethod("setTest4", List.class)); - TypeDescriptor t1 = TypeDescriptor.nested(property, 2); - assertEquals(String.class, t1.getType()); - } - - public List> getTest4() { - return null; - } - - public void setTest4(List> test4) { - - } - - @Test - public void collection() { - TypeDescriptor desc = TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Integer.class)); - assertEquals(List.class, desc.getType()); - assertEquals(List.class, desc.getObjectType()); - assertEquals("java.util.List", desc.getName()); - assertEquals("java.util.List", desc.toString()); - assertTrue(!desc.isPrimitive()); - assertEquals(0, desc.getAnnotations().length); - assertTrue(desc.isCollection()); - assertFalse(desc.isArray()); - assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); - assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor()); - assertFalse(desc.isMap()); - } - - @Test - public void collectionNested() { - TypeDescriptor desc = TypeDescriptor.collection(List.class, TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Integer.class))); - assertEquals(List.class, desc.getType()); - assertEquals(List.class, desc.getObjectType()); - assertEquals("java.util.List", desc.getName()); - assertEquals("java.util.List>", desc.toString()); - assertTrue(!desc.isPrimitive()); - assertEquals(0, desc.getAnnotations().length); - assertTrue(desc.isCollection()); - assertFalse(desc.isArray()); - assertEquals(List.class, desc.getElementTypeDescriptor().getType()); - assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor().getElementTypeDescriptor()); - assertFalse(desc.isMap()); - } - - @Test - public void map() { - TypeDescriptor desc = TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Integer.class)); - assertEquals(Map.class, desc.getType()); - assertEquals(Map.class, desc.getObjectType()); - assertEquals("java.util.Map", desc.getName()); - assertEquals("java.util.Map", desc.toString()); - assertTrue(!desc.isPrimitive()); - assertEquals(0, desc.getAnnotations().length); - assertFalse(desc.isCollection()); - assertFalse(desc.isArray()); - assertTrue(desc.isMap()); - assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType()); - assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getType()); - } - - @Test - public void mapNested() { - TypeDescriptor desc = TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(String.class), - TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Integer.class))); - assertEquals(Map.class, desc.getType()); - assertEquals(Map.class, desc.getObjectType()); - assertEquals("java.util.Map", desc.getName()); - assertEquals("java.util.Map>", desc.toString()); - assertTrue(!desc.isPrimitive()); - assertEquals(0, desc.getAnnotations().length); - assertFalse(desc.isCollection()); - assertFalse(desc.isArray()); - assertTrue(desc.isMap()); - assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType()); - assertEquals(String.class, desc.getMapValueTypeDescriptor().getMapKeyTypeDescriptor().getType()); - assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getMapValueTypeDescriptor().getType()); - } - - @Test - public void narrow() { - TypeDescriptor desc = TypeDescriptor.valueOf(Number.class); - Integer value = new Integer(3); - desc = desc.narrow(value); - assertEquals(Integer.class, desc.getType()); - } - - @Test - public void elementType() { - TypeDescriptor desc = TypeDescriptor.valueOf(List.class); - Integer value = new Integer(3); - desc = desc.elementTypeDescriptor(value); - assertEquals(Integer.class, desc.getType()); - } - - @Test - public void elementTypePreserveContext() throws Exception { - TypeDescriptor desc = new TypeDescriptor(getClass().getField("listPreserveContext")); - assertEquals(Integer.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getType()); - List value = new ArrayList(3); - desc = desc.elementTypeDescriptor(value); - assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); - assertNotNull(desc.getAnnotation(FieldAnnotation.class)); - } - - @FieldAnnotation - public List> listPreserveContext; - - @Test - public void mapKeyType() { - TypeDescriptor desc = TypeDescriptor.valueOf(Map.class); - Integer value = new Integer(3); - desc = desc.getMapKeyTypeDescriptor(value); - assertEquals(Integer.class, desc.getType()); - } - - @Test - public void mapKeyTypePreserveContext() throws Exception { - TypeDescriptor desc = new TypeDescriptor(getClass().getField("mapPreserveContext")); - assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getElementTypeDescriptor().getType()); - List value = new ArrayList(3); - desc = desc.getMapKeyTypeDescriptor(value); - assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); - assertNotNull(desc.getAnnotation(FieldAnnotation.class)); - } - - @FieldAnnotation - public Map, List> mapPreserveContext; - - @Test - public void mapValueType() { - TypeDescriptor desc = TypeDescriptor.valueOf(Map.class); - Integer value = new Integer(3); - desc = desc.getMapValueTypeDescriptor(value); - assertEquals(Integer.class, desc.getType()); - } - - @Test - public void mapValueTypePreserveContext() throws Exception { - TypeDescriptor desc = new TypeDescriptor(getClass().getField("mapPreserveContext")); - assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); - List value = new ArrayList(3); - desc = desc.getMapValueTypeDescriptor(value); - assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); - assertNotNull(desc.getAnnotation(FieldAnnotation.class)); - } - - @Test - public void equals() throws Exception { - TypeDescriptor t1 = TypeDescriptor.valueOf(String.class); - TypeDescriptor t2 = TypeDescriptor.valueOf(String.class); - TypeDescriptor t3 = TypeDescriptor.valueOf(Date.class); - TypeDescriptor t4 = TypeDescriptor.valueOf(Date.class); - TypeDescriptor t5 = TypeDescriptor.valueOf(List.class); - TypeDescriptor t6 = TypeDescriptor.valueOf(List.class); - TypeDescriptor t7 = TypeDescriptor.valueOf(Map.class); - TypeDescriptor t8 = TypeDescriptor.valueOf(Map.class); - assertEquals(t1, t2); - assertEquals(t3, t4); - assertEquals(t5, t6); - assertEquals(t7, t8); - - TypeDescriptor t9 = new TypeDescriptor(getClass().getField("listField")); - TypeDescriptor t10 = new TypeDescriptor(getClass().getField("listField")); - assertEquals(t9, t10); - - TypeDescriptor t11 = new TypeDescriptor(getClass().getField("mapField")); - TypeDescriptor t12 = new TypeDescriptor(getClass().getField("mapField")); - assertEquals(t11, t12); - } - - @Test - public void isAssignableTypes() { - assertTrue(TypeDescriptor.valueOf(Integer.class).isAssignableTo(TypeDescriptor.valueOf(Number.class))); - assertFalse(TypeDescriptor.valueOf(Number.class).isAssignableTo(TypeDescriptor.valueOf(Integer.class))); - assertFalse(TypeDescriptor.valueOf(String.class).isAssignableTo(TypeDescriptor.valueOf(String[].class))); - } - - @Test - public void isAssignableElementTypes() throws Exception { - assertTrue(new TypeDescriptor(getClass().getField("listField")).isAssignableTo(new TypeDescriptor(getClass().getField("listField")))); - assertTrue(new TypeDescriptor(getClass().getField("notGenericList")).isAssignableTo(new TypeDescriptor(getClass().getField("listField")))); - assertTrue(new TypeDescriptor(getClass().getField("listField")).isAssignableTo(new TypeDescriptor(getClass().getField("notGenericList")))); - assertFalse(new TypeDescriptor(getClass().getField("isAssignableElementTypes")).isAssignableTo(new TypeDescriptor(getClass().getField("listField")))); - assertTrue(TypeDescriptor.valueOf(List.class).isAssignableTo(new TypeDescriptor(getClass().getField("listField")))); - } - - public List notGenericList; - - public List isAssignableElementTypes; - - @Test - public void isAssignableMapKeyValueTypes() throws Exception { - assertTrue(new TypeDescriptor(getClass().getField("mapField")).isAssignableTo(new TypeDescriptor(getClass().getField("mapField")))); - assertTrue(new TypeDescriptor(getClass().getField("notGenericMap")).isAssignableTo(new TypeDescriptor(getClass().getField("mapField")))); - assertTrue(new TypeDescriptor(getClass().getField("mapField")).isAssignableTo(new TypeDescriptor(getClass().getField("notGenericMap")))); - assertFalse(new TypeDescriptor(getClass().getField("isAssignableMapKeyValueTypes")).isAssignableTo(new TypeDescriptor(getClass().getField("mapField")))); - assertTrue(TypeDescriptor.valueOf(Map.class).isAssignableTo(new TypeDescriptor(getClass().getField("mapField")))); - } - - public Map notGenericMap; - - public Map isAssignableMapKeyValueTypes; - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.convert; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Test; + +import org.springframework.core.MethodParameter; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +/** + * @author Keith Donald + * @author Andy Clement + */ +@SuppressWarnings("rawtypes") +public class TypeDescriptorTests { + + public List listOfString; + + public List> listOfListOfString = new ArrayList>(); + + public List listOfListOfUnknown = new ArrayList(); + + public int[] intArray; + + public List[] arrayOfListOfString; + + public List listField = new ArrayList(); + + public Map mapField = new HashMap(); + + public Map> nestedMapField = new HashMap>(); + + @Test + public void parameterPrimitive() throws Exception { + TypeDescriptor desc = new TypeDescriptor(new MethodParameter(getClass().getMethod("testParameterPrimitive", int.class), 0)); + assertEquals(int.class, desc.getType()); + assertEquals(Integer.class, desc.getObjectType()); + assertEquals("int", desc.getName()); + assertEquals("int", desc.toString()); + assertTrue(desc.isPrimitive()); + assertEquals(0, desc.getAnnotations().length); + assertFalse(desc.isCollection()); + assertFalse(desc.isMap()); + } + + public void testParameterPrimitive(int primitive) { + + } + + @Test + public void parameterScalar() throws Exception { + TypeDescriptor desc = new TypeDescriptor(new MethodParameter(getClass().getMethod("testParameterScalar", String.class), 0)); + assertEquals(String.class, desc.getType()); + assertEquals(String.class, desc.getObjectType()); + assertEquals("java.lang.String", desc.getName()); + assertEquals("java.lang.String", desc.toString()); + assertTrue(!desc.isPrimitive()); + assertEquals(0, desc.getAnnotations().length); + assertFalse(desc.isCollection()); + assertFalse(desc.isArray()); + assertFalse(desc.isMap()); + } + + public void testParameterScalar(String value) { + + } + + @Test + public void parameterList() throws Exception { + MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterList", List.class), 0); + TypeDescriptor desc = new TypeDescriptor(methodParameter); + assertEquals(List.class, desc.getType()); + assertEquals(List.class, desc.getObjectType()); + assertEquals("java.util.List", desc.getName()); + assertEquals("java.util.List>>", desc.toString()); + assertTrue(!desc.isPrimitive()); + assertEquals(0, desc.getAnnotations().length); + assertTrue(desc.isCollection()); + assertFalse(desc.isArray()); + assertEquals(List.class, desc.getElementTypeDescriptor().getType()); + assertEquals(TypeDescriptor.nested(methodParameter, 1), desc.getElementTypeDescriptor()); + assertEquals(TypeDescriptor.nested(methodParameter, 2), desc.getElementTypeDescriptor().getElementTypeDescriptor()); + assertEquals(TypeDescriptor.nested(methodParameter, 3), desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapValueTypeDescriptor()); + assertEquals(Integer.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapKeyTypeDescriptor().getType()); + assertEquals(Enum.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapValueTypeDescriptor().getType()); + assertFalse(desc.isMap()); + } + + public void testParameterList(List>>> list) { + + } + + @Test + public void parameterListNoParamTypes() throws Exception { + MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterListNoParamTypes", List.class), 0); + TypeDescriptor desc = new TypeDescriptor(methodParameter); + assertEquals(List.class, desc.getType()); + assertEquals(List.class, desc.getObjectType()); + assertEquals("java.util.List", desc.getName()); + assertEquals("java.util.List", desc.toString()); + assertTrue(!desc.isPrimitive()); + assertEquals(0, desc.getAnnotations().length); + assertTrue(desc.isCollection()); + assertFalse(desc.isArray()); + assertNull(desc.getElementTypeDescriptor()); + assertFalse(desc.isMap()); + } + + public void testParameterListNoParamTypes(List list) { + + } + + @Test + public void parameterArray() throws Exception { + MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterArray", Integer[].class), 0); + TypeDescriptor desc = new TypeDescriptor(methodParameter); + assertEquals(Integer[].class, desc.getType()); + assertEquals(Integer[].class, desc.getObjectType()); + assertEquals("java.lang.Integer[]", desc.getName()); + assertEquals("java.lang.Integer[]", desc.toString()); + assertTrue(!desc.isPrimitive()); + assertEquals(0, desc.getAnnotations().length); + assertFalse(desc.isCollection()); + assertTrue(desc.isArray()); + assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); + assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor()); + assertFalse(desc.isMap()); + } + + public void testParameterArray(Integer[] array) { + + } + + @Test + public void parameterMap() throws Exception { + MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterMap", Map.class), 0); + TypeDescriptor desc = new TypeDescriptor(methodParameter); + assertEquals(Map.class, desc.getType()); + assertEquals(Map.class, desc.getObjectType()); + assertEquals("java.util.Map", desc.getName()); + assertEquals("java.util.Map>", desc.toString()); + assertTrue(!desc.isPrimitive()); + assertEquals(0, desc.getAnnotations().length); + assertFalse(desc.isCollection()); + assertFalse(desc.isArray()); + assertTrue(desc.isMap()); + assertEquals(TypeDescriptor.nested(methodParameter, 1), desc.getMapValueTypeDescriptor()); + assertEquals(TypeDescriptor.nested(methodParameter, 2), desc.getMapValueTypeDescriptor().getElementTypeDescriptor()); + assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getType()); + assertEquals(List.class, desc.getMapValueTypeDescriptor().getType()); + assertEquals(String.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); + } + + public void testParameterMap(Map> map) { + + } + + @Test + public void parameterAnnotated() throws Exception { + TypeDescriptor t1 = new TypeDescriptor(new MethodParameter(getClass().getMethod("testAnnotatedMethod", String.class), 0)); + assertEquals(String.class, t1.getType()); + assertEquals(1, t1.getAnnotations().length); + assertNotNull(t1.getAnnotation(ParameterAnnotation.class)); + } + + @Target({ElementType.PARAMETER}) + @Retention(RetentionPolicy.RUNTIME) + public @interface ParameterAnnotation { + + } + + public void testAnnotatedMethod(@ParameterAnnotation String parameter) { + + } + + @Test + public void propertyComplex() throws Exception { + Property property = new Property(getClass(), getClass().getMethod("getComplexProperty"), getClass().getMethod("setComplexProperty", Map.class)); + TypeDescriptor desc = new TypeDescriptor(property); + assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType()); + assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getElementTypeDescriptor().getType()); + } + + public Map>> getComplexProperty() { + return null; + } + + public void setComplexProperty(Map>> complexProperty) { + + } + + @Test + public void propertyGenericType() throws Exception { + GenericType genericBean = new IntegerType(); + Property property = new Property(getClass(), genericBean.getClass().getMethod("getProperty"), genericBean.getClass().getMethod("setProperty", Integer.class)); + TypeDescriptor desc = new TypeDescriptor(property); + assertEquals(Integer.class, desc.getType()); + } + + @Test + public void propertyTypeCovariance() throws Exception { + GenericType genericBean = new NumberType(); + Property property = new Property(getClass(), genericBean.getClass().getMethod("getProperty"), genericBean.getClass().getMethod("setProperty", Number.class)); + TypeDescriptor desc = new TypeDescriptor(property); + assertEquals(Integer.class, desc.getType()); + } + + @Test + public void propertyGenericTypeList() throws Exception { + GenericType genericBean = new IntegerType(); + Property property = new Property(getClass(), genericBean.getClass().getMethod("getListProperty"), genericBean.getClass().getMethod("setListProperty", List.class)); + TypeDescriptor desc = new TypeDescriptor(property); + assertEquals(List.class, desc.getType()); + assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); + } + + public interface GenericType { + T getProperty(); + + void setProperty(T t); + + List getListProperty(); + + void setListProperty(List t); + + } + + public class IntegerType implements GenericType { + + public Integer getProperty() { + return null; + } + + public void setProperty(Integer t) { + } + + public List getListProperty() { + return null; + } + + public void setListProperty(List t) { + } + } + + public class NumberType implements GenericType { + + public Integer getProperty() { + return null; + } + + public void setProperty(Number t) { + } + + public List getListProperty() { + return null; + } + + public void setListProperty(List t) { + } + } + + @Test + public void propertyGenericClassList() throws Exception { + IntegerClass genericBean = new IntegerClass(); + Property property = new Property(genericBean.getClass(), genericBean.getClass().getMethod("getListProperty"), genericBean.getClass().getMethod("setListProperty", List.class)); + TypeDescriptor desc = new TypeDescriptor(property); + assertEquals(List.class, desc.getType()); + assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); + assertNotNull(desc.getAnnotation(MethodAnnotation1.class)); + } + + public static class GenericClass { + + public T getProperty() { + return null; + } + + public void setProperty(T t) { + } + + @MethodAnnotation1 + public List getListProperty() { + return null; + } + + public void setListProperty(List t) { + } + + } + + public static class IntegerClass extends GenericClass { + + } + + @Test + public void property() throws Exception { + Property property = new Property(getClass(), getClass().getMethod("getProperty"), getClass().getMethod("setProperty", Map.class)); + TypeDescriptor desc = new TypeDescriptor(property); + assertEquals(Map.class, desc.getType()); + assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getElementTypeDescriptor().getType()); + assertEquals(Long.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); + assertNotNull(desc.getAnnotation(MethodAnnotation1.class)); + assertNotNull(desc.getAnnotation(MethodAnnotation2.class)); + assertNotNull(desc.getAnnotation(MethodAnnotation3.class)); + } + + @MethodAnnotation1 + public Map, List> getProperty() { + return property; + } + + @MethodAnnotation2 + public void setProperty(Map, List> property) { + this.property = property; + } + + @MethodAnnotation3 + private Map, List> property; + + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface MethodAnnotation1 { + + } + + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface MethodAnnotation2 { + + } + + @Target({ElementType.FIELD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface MethodAnnotation3 { + + } + + @Test + public void fieldScalar() throws Exception { + TypeDescriptor typeDescriptor = new TypeDescriptor(getClass().getField("fieldScalar")); + assertFalse(typeDescriptor.isPrimitive()); + assertFalse(typeDescriptor.isArray()); + assertFalse(typeDescriptor.isCollection()); + assertFalse(typeDescriptor.isMap()); + assertEquals(Integer.class, typeDescriptor.getType()); + assertEquals(Integer.class, typeDescriptor.getObjectType()); + } + + public Integer fieldScalar; + + @Test + public void fieldList() throws Exception { + TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfString")); + assertFalse(typeDescriptor.isArray()); + assertEquals(List.class, typeDescriptor.getType()); + assertEquals(String.class, typeDescriptor.getElementTypeDescriptor().getType()); + assertEquals("java.util.List", typeDescriptor.toString()); + } + + @Test + public void fieldListOfListOfString() throws Exception { + TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfListOfString")); + assertFalse(typeDescriptor.isArray()); + assertEquals(List.class, typeDescriptor.getType()); + assertEquals(List.class, typeDescriptor.getElementTypeDescriptor().getType()); + assertEquals(String.class, typeDescriptor.getElementTypeDescriptor().getElementTypeDescriptor().getType()); + assertEquals("java.util.List>", typeDescriptor.toString()); + } + + @Test + public void fieldListOfListUnknown() throws Exception { + TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfListOfUnknown")); + assertFalse(typeDescriptor.isArray()); + assertEquals(List.class, typeDescriptor.getType()); + assertEquals(List.class, typeDescriptor.getElementTypeDescriptor().getType()); + assertNull(typeDescriptor.getElementTypeDescriptor().getElementTypeDescriptor()); + assertEquals("java.util.List>", typeDescriptor.toString()); + } + + @Test + public void fieldArray() throws Exception { + TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("intArray")); + assertTrue(typeDescriptor.isArray()); + assertEquals(Integer.TYPE,typeDescriptor.getElementTypeDescriptor().getType()); + assertEquals("int[]",typeDescriptor.toString()); + } + + @Test + public void fieldComplexTypeDescriptor() throws Exception { + TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("arrayOfListOfString")); + assertTrue(typeDescriptor.isArray()); + assertEquals(List.class,typeDescriptor.getElementTypeDescriptor().getType()); + assertEquals(String.class, typeDescriptor.getElementTypeDescriptor().getElementTypeDescriptor().getType()); + assertEquals("java.util.List[]",typeDescriptor.toString()); + } + + @Test + public void fieldComplexTypeDescriptor2() throws Exception { + TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("nestedMapField")); + assertTrue(typeDescriptor.isMap()); + assertEquals(String.class,typeDescriptor.getMapKeyTypeDescriptor().getType()); + assertEquals(List.class, typeDescriptor.getMapValueTypeDescriptor().getType()); + assertEquals(Integer.class, typeDescriptor.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); + assertEquals("java.util.Map>", typeDescriptor.toString()); + } + + @Test + public void fieldMap() throws Exception { + TypeDescriptor desc = new TypeDescriptor(TypeDescriptorTests.class.getField("fieldMap")); + assertTrue(desc.isMap()); + assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getElementTypeDescriptor().getType()); + assertEquals(Long.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); + } + + public Map, List> fieldMap; + + @Test + public void fieldAnnotated() throws Exception { + TypeDescriptor typeDescriptor = new TypeDescriptor(getClass().getField("fieldAnnotated")); + assertEquals(1, typeDescriptor.getAnnotations().length); + assertNotNull(typeDescriptor.getAnnotation(FieldAnnotation.class)); + } + + @FieldAnnotation + public List fieldAnnotated; + + @Target({ElementType.FIELD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface FieldAnnotation { + + } + + @Test + public void valueOfScalar() { + TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(Integer.class); + assertFalse(typeDescriptor.isPrimitive()); + assertFalse(typeDescriptor.isArray()); + assertFalse(typeDescriptor.isCollection()); + assertFalse(typeDescriptor.isMap()); + assertEquals(Integer.class, typeDescriptor.getType()); + assertEquals(Integer.class, typeDescriptor.getObjectType()); + } + + @Test + public void valueOfPrimitive() { + TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(int.class); + assertTrue(typeDescriptor.isPrimitive()); + assertFalse(typeDescriptor.isArray()); + assertFalse(typeDescriptor.isCollection()); + assertFalse(typeDescriptor.isMap()); + assertEquals(Integer.TYPE, typeDescriptor.getType()); + assertEquals(Integer.class, typeDescriptor.getObjectType()); + } + + @Test + public void valueOfArray() throws Exception { + TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(int[].class); + assertTrue(typeDescriptor.isArray()); + assertFalse(typeDescriptor.isCollection()); + assertFalse(typeDescriptor.isMap()); + assertEquals(Integer.TYPE, typeDescriptor.getElementTypeDescriptor().getType()); + } + + @Test + public void valueOfCollection() throws Exception { + TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(Collection.class); + assertTrue(typeDescriptor.isCollection()); + assertFalse(typeDescriptor.isArray()); + assertFalse(typeDescriptor.isMap()); + assertNull(typeDescriptor.getElementTypeDescriptor()); + } + + @Test + public void forObject() { + TypeDescriptor desc = TypeDescriptor.forObject("3"); + assertEquals(String.class, desc.getType()); + } + + @Test + public void forObjectNullTypeDescriptor() { + TypeDescriptor desc = TypeDescriptor.forObject(null); + assertNull(desc); + } + + @Test + public void nestedMethodParameterType2Levels() throws Exception { + TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test2", List.class), 0), 2); + assertEquals(String.class, t1.getType()); + } + + @Test + public void nestedMethodParameterTypeMap() throws Exception { + TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test3", Map.class), 0), 1); + assertEquals(String.class, t1.getType()); + } + + @Test + public void nestedMethodParameterTypeMapTwoLevels() throws Exception { + TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test4", List.class), 0), 2); + assertEquals(String.class, t1.getType()); + } + + @Test(expected=IllegalArgumentException.class) + public void nestedMethodParameterNot1NestedLevel() throws Exception { + TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test4", List.class), 0, 2), 2); + } + + @Test(expected=IllegalStateException.class) + public void nestedTooManyLevels() throws Exception { + TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test4", List.class), 0), 3); + assertEquals(String.class, t1.getType()); + } + + @Test(expected=IllegalStateException.class) + public void nestedMethodParameterTypeNotNestable() throws Exception { + TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test5", String.class), 0), 2); + } + + @Test(expected=IllegalArgumentException.class) + public void nestedMethodParameterTypeInvalidNestingLevel() throws Exception { + TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test5", String.class), 0, 2), 2); + } + + public void test1(List param1) { + + } + + public void test2(List> param1) { + + } + + public void test3(Map param1) { + + } + + public void test4(List> param1) { + + } + + public void test5(String param1) { + + } + + @Test + public void nestedNotParameterized() throws Exception { + TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test6", List.class), 0), 1); + assertEquals(List.class,t1.getType()); + assertEquals("java.util.List", t1.toString()); + TypeDescriptor t2 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test6", List.class), 0), 2); + assertNull(t2); + } + + public void test6(List param1) { + + } + + @Test + public void nestedFieldTypeMapTwoLevels() throws Exception { + TypeDescriptor t1 = TypeDescriptor.nested(getClass().getField("test4"), 2); + assertEquals(String.class, t1.getType()); + } + + public List> test4; + + @Test + public void nestedPropertyTypeMapTwoLevels() throws Exception { + Property property = new Property(getClass(), getClass().getMethod("getTest4"), getClass().getMethod("setTest4", List.class)); + TypeDescriptor t1 = TypeDescriptor.nested(property, 2); + assertEquals(String.class, t1.getType()); + } + + public List> getTest4() { + return null; + } + + public void setTest4(List> test4) { + + } + + @Test + public void collection() { + TypeDescriptor desc = TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Integer.class)); + assertEquals(List.class, desc.getType()); + assertEquals(List.class, desc.getObjectType()); + assertEquals("java.util.List", desc.getName()); + assertEquals("java.util.List", desc.toString()); + assertTrue(!desc.isPrimitive()); + assertEquals(0, desc.getAnnotations().length); + assertTrue(desc.isCollection()); + assertFalse(desc.isArray()); + assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); + assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor()); + assertFalse(desc.isMap()); + } + + @Test + public void collectionNested() { + TypeDescriptor desc = TypeDescriptor.collection(List.class, TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Integer.class))); + assertEquals(List.class, desc.getType()); + assertEquals(List.class, desc.getObjectType()); + assertEquals("java.util.List", desc.getName()); + assertEquals("java.util.List>", desc.toString()); + assertTrue(!desc.isPrimitive()); + assertEquals(0, desc.getAnnotations().length); + assertTrue(desc.isCollection()); + assertFalse(desc.isArray()); + assertEquals(List.class, desc.getElementTypeDescriptor().getType()); + assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor().getElementTypeDescriptor()); + assertFalse(desc.isMap()); + } + + @Test + public void map() { + TypeDescriptor desc = TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Integer.class)); + assertEquals(Map.class, desc.getType()); + assertEquals(Map.class, desc.getObjectType()); + assertEquals("java.util.Map", desc.getName()); + assertEquals("java.util.Map", desc.toString()); + assertTrue(!desc.isPrimitive()); + assertEquals(0, desc.getAnnotations().length); + assertFalse(desc.isCollection()); + assertFalse(desc.isArray()); + assertTrue(desc.isMap()); + assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType()); + assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getType()); + } + + @Test + public void mapNested() { + TypeDescriptor desc = TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(String.class), + TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Integer.class))); + assertEquals(Map.class, desc.getType()); + assertEquals(Map.class, desc.getObjectType()); + assertEquals("java.util.Map", desc.getName()); + assertEquals("java.util.Map>", desc.toString()); + assertTrue(!desc.isPrimitive()); + assertEquals(0, desc.getAnnotations().length); + assertFalse(desc.isCollection()); + assertFalse(desc.isArray()); + assertTrue(desc.isMap()); + assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType()); + assertEquals(String.class, desc.getMapValueTypeDescriptor().getMapKeyTypeDescriptor().getType()); + assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getMapValueTypeDescriptor().getType()); + } + + @Test + public void narrow() { + TypeDescriptor desc = TypeDescriptor.valueOf(Number.class); + Integer value = new Integer(3); + desc = desc.narrow(value); + assertEquals(Integer.class, desc.getType()); + } + + @Test + public void elementType() { + TypeDescriptor desc = TypeDescriptor.valueOf(List.class); + Integer value = new Integer(3); + desc = desc.elementTypeDescriptor(value); + assertEquals(Integer.class, desc.getType()); + } + + @Test + public void elementTypePreserveContext() throws Exception { + TypeDescriptor desc = new TypeDescriptor(getClass().getField("listPreserveContext")); + assertEquals(Integer.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getType()); + List value = new ArrayList(3); + desc = desc.elementTypeDescriptor(value); + assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); + assertNotNull(desc.getAnnotation(FieldAnnotation.class)); + } + + @FieldAnnotation + public List> listPreserveContext; + + @Test + public void mapKeyType() { + TypeDescriptor desc = TypeDescriptor.valueOf(Map.class); + Integer value = new Integer(3); + desc = desc.getMapKeyTypeDescriptor(value); + assertEquals(Integer.class, desc.getType()); + } + + @Test + public void mapKeyTypePreserveContext() throws Exception { + TypeDescriptor desc = new TypeDescriptor(getClass().getField("mapPreserveContext")); + assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getElementTypeDescriptor().getType()); + List value = new ArrayList(3); + desc = desc.getMapKeyTypeDescriptor(value); + assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); + assertNotNull(desc.getAnnotation(FieldAnnotation.class)); + } + + @FieldAnnotation + public Map, List> mapPreserveContext; + + @Test + public void mapValueType() { + TypeDescriptor desc = TypeDescriptor.valueOf(Map.class); + Integer value = new Integer(3); + desc = desc.getMapValueTypeDescriptor(value); + assertEquals(Integer.class, desc.getType()); + } + + @Test + public void mapValueTypePreserveContext() throws Exception { + TypeDescriptor desc = new TypeDescriptor(getClass().getField("mapPreserveContext")); + assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); + List value = new ArrayList(3); + desc = desc.getMapValueTypeDescriptor(value); + assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); + assertNotNull(desc.getAnnotation(FieldAnnotation.class)); + } + + @Test + public void equals() throws Exception { + TypeDescriptor t1 = TypeDescriptor.valueOf(String.class); + TypeDescriptor t2 = TypeDescriptor.valueOf(String.class); + TypeDescriptor t3 = TypeDescriptor.valueOf(Date.class); + TypeDescriptor t4 = TypeDescriptor.valueOf(Date.class); + TypeDescriptor t5 = TypeDescriptor.valueOf(List.class); + TypeDescriptor t6 = TypeDescriptor.valueOf(List.class); + TypeDescriptor t7 = TypeDescriptor.valueOf(Map.class); + TypeDescriptor t8 = TypeDescriptor.valueOf(Map.class); + assertEquals(t1, t2); + assertEquals(t3, t4); + assertEquals(t5, t6); + assertEquals(t7, t8); + + TypeDescriptor t9 = new TypeDescriptor(getClass().getField("listField")); + TypeDescriptor t10 = new TypeDescriptor(getClass().getField("listField")); + assertEquals(t9, t10); + + TypeDescriptor t11 = new TypeDescriptor(getClass().getField("mapField")); + TypeDescriptor t12 = new TypeDescriptor(getClass().getField("mapField")); + assertEquals(t11, t12); + } + + @Test + public void isAssignableTypes() { + assertTrue(TypeDescriptor.valueOf(Integer.class).isAssignableTo(TypeDescriptor.valueOf(Number.class))); + assertFalse(TypeDescriptor.valueOf(Number.class).isAssignableTo(TypeDescriptor.valueOf(Integer.class))); + assertFalse(TypeDescriptor.valueOf(String.class).isAssignableTo(TypeDescriptor.valueOf(String[].class))); + } + + @Test + public void isAssignableElementTypes() throws Exception { + assertTrue(new TypeDescriptor(getClass().getField("listField")).isAssignableTo(new TypeDescriptor(getClass().getField("listField")))); + assertTrue(new TypeDescriptor(getClass().getField("notGenericList")).isAssignableTo(new TypeDescriptor(getClass().getField("listField")))); + assertTrue(new TypeDescriptor(getClass().getField("listField")).isAssignableTo(new TypeDescriptor(getClass().getField("notGenericList")))); + assertFalse(new TypeDescriptor(getClass().getField("isAssignableElementTypes")).isAssignableTo(new TypeDescriptor(getClass().getField("listField")))); + assertTrue(TypeDescriptor.valueOf(List.class).isAssignableTo(new TypeDescriptor(getClass().getField("listField")))); + } + + public List notGenericList; + + public List isAssignableElementTypes; + + @Test + public void isAssignableMapKeyValueTypes() throws Exception { + assertTrue(new TypeDescriptor(getClass().getField("mapField")).isAssignableTo(new TypeDescriptor(getClass().getField("mapField")))); + assertTrue(new TypeDescriptor(getClass().getField("notGenericMap")).isAssignableTo(new TypeDescriptor(getClass().getField("mapField")))); + assertTrue(new TypeDescriptor(getClass().getField("mapField")).isAssignableTo(new TypeDescriptor(getClass().getField("notGenericMap")))); + assertFalse(new TypeDescriptor(getClass().getField("isAssignableMapKeyValueTypes")).isAssignableTo(new TypeDescriptor(getClass().getField("mapField")))); + assertTrue(TypeDescriptor.valueOf(Map.class).isAssignableTo(new TypeDescriptor(getClass().getField("mapField")))); + } + + public Map notGenericMap; + + public Map isAssignableMapKeyValueTypes; + +} diff --git a/org.springframework.core/src/test/java/org/springframework/core/type/CachingMetadataReaderLeakTest.java b/org.springframework.core/src/test/java/org/springframework/core/type/CachingMetadataReaderLeakTest.java index c01e3df94c..e6128c35bf 100644 --- a/org.springframework.core/src/test/java/org/springframework/core/type/CachingMetadataReaderLeakTest.java +++ b/org.springframework.core/src/test/java/org/springframework/core/type/CachingMetadataReaderLeakTest.java @@ -1,79 +1,79 @@ -/* - * Copyright 2006-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.core.type; - -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.junit.Assert.assertThat; - -import java.net.URL; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.core.io.Resource; -import org.springframework.core.io.UrlResource; -import org.springframework.core.type.classreading.CachingMetadataReaderFactory; -import org.springframework.core.type.classreading.MetadataReader; -import org.springframework.core.type.classreading.MetadataReaderFactory; -import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; - -/** - * Unit test checking the behaviour of {@link CachingMetadataReaderFactory under load. - * If the cache is not controller, this test should fail with an out of memory exception around entry - * 5k. - * - * @author Costin Leau - */ -public class CachingMetadataReaderLeakTest { - - private static int ITEMS_LOAD = 9999; - private MetadataReaderFactory mrf; - - @Before - public void before() { - mrf = new CachingMetadataReaderFactory(); - } - - @Test - public void testSignificantLoad() throws Exception { - // the biggest public class in the JDK (>60k) - URL url = getClass().getResource("/java/awt/Component.class"); - assertThat(url, notNullValue()); - - // look at a LOT of items - for (int i = 0; i < ITEMS_LOAD; i++) { - Resource resource = new UrlResource(url) { - private int counter = 0; - - @Override - public boolean equals(Object obj) { - return (obj == this); - - } - - @Override - public int hashCode() { - return System.identityHashCode(this); - } - }; - - MetadataReader reader = mrf.getMetadataReader(resource); - assertThat(reader, notNullValue()); - } - - // useful for profiling to take snapshots - //System.in.read(); - } -} +/* + * Copyright 2006-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.core.type; + +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; + +import java.net.URL; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.core.io.Resource; +import org.springframework.core.io.UrlResource; +import org.springframework.core.type.classreading.CachingMetadataReaderFactory; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; + +/** + * Unit test checking the behaviour of {@link CachingMetadataReaderFactory under load. + * If the cache is not controller, this test should fail with an out of memory exception around entry + * 5k. + * + * @author Costin Leau + */ +public class CachingMetadataReaderLeakTest { + + private static int ITEMS_LOAD = 9999; + private MetadataReaderFactory mrf; + + @Before + public void before() { + mrf = new CachingMetadataReaderFactory(); + } + + @Test + public void testSignificantLoad() throws Exception { + // the biggest public class in the JDK (>60k) + URL url = getClass().getResource("/java/awt/Component.class"); + assertThat(url, notNullValue()); + + // look at a LOT of items + for (int i = 0; i < ITEMS_LOAD; i++) { + Resource resource = new UrlResource(url) { + private int counter = 0; + + @Override + public boolean equals(Object obj) { + return (obj == this); + + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + }; + + MetadataReader reader = mrf.getMetadataReader(resource); + assertThat(reader, notNullValue()); + } + + // useful for profiling to take snapshots + //System.in.read(); + } +} diff --git a/org.springframework.core/src/test/java/org/springframework/util/CompositeIteratorTests.java b/org.springframework.core/src/test/java/org/springframework/util/CompositeIteratorTests.java index a92086e4ea..451005558e 100644 --- a/org.springframework.core/src/test/java/org/springframework/util/CompositeIteratorTests.java +++ b/org.springframework.core/src/test/java/org/springframework/util/CompositeIteratorTests.java @@ -1,98 +1,98 @@ -package org.springframework.util; - -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; - -import junit.framework.TestCase; - -/** - * Test case for {@link CompositeIterator}. - * - * @author Erwin Vervaet - */ -public class CompositeIteratorTests extends TestCase { - - public void testNoIterators() { - CompositeIterator it = new CompositeIterator(); - assertFalse(it.hasNext()); - try { - it.next(); - fail(); - } catch (NoSuchElementException e) { - // expected - } - } - - public void testSingleIterator() { - CompositeIterator it = new CompositeIterator(); - it.add(Arrays.asList(new String[] { "0", "1" }).iterator()); - for (int i = 0; i < 2; i++) { - assertTrue(it.hasNext()); - assertEquals(String.valueOf(i), it.next()); - } - assertFalse(it.hasNext()); - try { - it.next(); - fail(); - } catch (NoSuchElementException e) { - // expected - } - } - - public void testMultipleIterators() { - CompositeIterator it = new CompositeIterator(); - it.add(Arrays.asList(new String[] { "0", "1" }).iterator()); - it.add(Arrays.asList(new String[] { "2" }).iterator()); - it.add(Arrays.asList(new String[] { "3", "4" }).iterator()); - for (int i = 0; i < 5; i++) { - assertTrue(it.hasNext()); - assertEquals(String.valueOf(i), it.next()); - } - assertFalse(it.hasNext()); - try { - it.next(); - fail(); - } catch (NoSuchElementException e) { - // expected - } - } - - public void testInUse() { - List list = Arrays.asList(new String[] { "0", "1" }); - CompositeIterator it = new CompositeIterator(); - it.add(list.iterator()); - it.hasNext(); - try { - it.add(list.iterator()); - fail(); - } catch (IllegalStateException e) { - // expected - } - it = new CompositeIterator(); - it.add(list.iterator()); - it.next(); - try { - it.add(list.iterator()); - fail(); - } catch (IllegalStateException e) { - // expected - } - } - - public void testDuplicateIterators() { - List list = Arrays.asList(new String[] { "0", "1" }); - Iterator iterator = list.iterator(); - CompositeIterator it = new CompositeIterator(); - it.add(iterator); - it.add(list.iterator()); - try { - it.add(iterator); - fail(); - } catch (IllegalArgumentException e) { - // expected - } - } - -} +package org.springframework.util; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import junit.framework.TestCase; + +/** + * Test case for {@link CompositeIterator}. + * + * @author Erwin Vervaet + */ +public class CompositeIteratorTests extends TestCase { + + public void testNoIterators() { + CompositeIterator it = new CompositeIterator(); + assertFalse(it.hasNext()); + try { + it.next(); + fail(); + } catch (NoSuchElementException e) { + // expected + } + } + + public void testSingleIterator() { + CompositeIterator it = new CompositeIterator(); + it.add(Arrays.asList(new String[] { "0", "1" }).iterator()); + for (int i = 0; i < 2; i++) { + assertTrue(it.hasNext()); + assertEquals(String.valueOf(i), it.next()); + } + assertFalse(it.hasNext()); + try { + it.next(); + fail(); + } catch (NoSuchElementException e) { + // expected + } + } + + public void testMultipleIterators() { + CompositeIterator it = new CompositeIterator(); + it.add(Arrays.asList(new String[] { "0", "1" }).iterator()); + it.add(Arrays.asList(new String[] { "2" }).iterator()); + it.add(Arrays.asList(new String[] { "3", "4" }).iterator()); + for (int i = 0; i < 5; i++) { + assertTrue(it.hasNext()); + assertEquals(String.valueOf(i), it.next()); + } + assertFalse(it.hasNext()); + try { + it.next(); + fail(); + } catch (NoSuchElementException e) { + // expected + } + } + + public void testInUse() { + List list = Arrays.asList(new String[] { "0", "1" }); + CompositeIterator it = new CompositeIterator(); + it.add(list.iterator()); + it.hasNext(); + try { + it.add(list.iterator()); + fail(); + } catch (IllegalStateException e) { + // expected + } + it = new CompositeIterator(); + it.add(list.iterator()); + it.next(); + try { + it.add(list.iterator()); + fail(); + } catch (IllegalStateException e) { + // expected + } + } + + public void testDuplicateIterators() { + List list = Arrays.asList(new String[] { "0", "1" }); + Iterator iterator = list.iterator(); + CompositeIterator it = new CompositeIterator(); + it.add(iterator); + it.add(list.iterator()); + try { + it.add(iterator); + fail(); + } catch (IllegalArgumentException e) { + // expected + } + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/AccessException.java b/org.springframework.expression/src/main/java/org/springframework/expression/AccessException.java index 21b4c3bc6c..d0b41aab6d 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/AccessException.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/AccessException.java @@ -1,44 +1,44 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression; - -/** - * An AccessException is thrown by an accessor if it has an unexpected problem. - * - * @author Andy Clement - * @since 3.0 - */ -public class AccessException extends Exception { - - /** - * Create an AccessException with a specific message and cause. - * @param message the message - * @param cause the cause - */ - public AccessException(String message, Exception cause) { - super(message, cause); - } - - /** - * Create an AccessException with a specific message. - * @param message the message - */ - public AccessException(String message) { - super(message); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression; + +/** + * An AccessException is thrown by an accessor if it has an unexpected problem. + * + * @author Andy Clement + * @since 3.0 + */ +public class AccessException extends Exception { + + /** + * Create an AccessException with a specific message and cause. + * @param message the message + * @param cause the cause + */ + public AccessException(String message, Exception cause) { + super(message, cause); + } + + /** + * Create an AccessException with a specific message. + * @param message the message + */ + public AccessException(String message) { + super(message); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/BeanResolver.java b/org.springframework.expression/src/main/java/org/springframework/expression/BeanResolver.java index 22f164ecb7..c3857d8e98 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/BeanResolver.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/BeanResolver.java @@ -1,38 +1,38 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression; - -/** - * A bean resolver can be registered with the evaluation context - * and will kick in for @myBeanName still expressions. - * - * @author Andy Clement - * @since 3.0.3 - */ -public interface BeanResolver { - - /** - * Look up the named bean and return it. - * @param context the current evaluation context - * @param beanName the name of the bean to lookup - * @return an object representing the bean - * @throws AccessException if there is an unexpected problem resolving the named bean - */ - Object resolve(EvaluationContext context, String beanName) throws AccessException; - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression; + +/** + * A bean resolver can be registered with the evaluation context + * and will kick in for @myBeanName still expressions. + * + * @author Andy Clement + * @since 3.0.3 + */ +public interface BeanResolver { + + /** + * Look up the named bean and return it. + * @param context the current evaluation context + * @param beanName the name of the bean to lookup + * @return an object representing the bean + * @throws AccessException if there is an unexpected problem resolving the named bean + */ + Object resolve(EvaluationContext context, String beanName) throws AccessException; + +} \ No newline at end of file diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/ConstructorExecutor.java b/org.springframework.expression/src/main/java/org/springframework/expression/ConstructorExecutor.java index d0094376ee..34bda66d9e 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/ConstructorExecutor.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/ConstructorExecutor.java @@ -1,45 +1,45 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression; - - -// TODO Is the resolver/executor model too pervasive in this package? -/** - * Executors are built by resolvers and can be cached by the infrastructure to repeat an operation quickly without going - * back to the resolvers. For example, the particular constructor to run on a class may be discovered by the reflection - * constructor resolver - it will then build a ConstructorExecutor that executes that constructor and the - * ConstructorExecutor can be reused without needing to go back to the resolver to discover the constructor again. - * - * They can become stale, and in that case should throw an AccessException - this will cause the infrastructure to go - * back to the resolvers to ask for a new one. - * - * @author Andy Clement - * @since 3.0 - */ -public interface ConstructorExecutor { - - /** - * Execute a constructor in the specified context using the specified arguments. - * @param context the evaluation context in which the command is being executed - * @param arguments the arguments to the constructor call, should match (in terms of number and type) whatever the - * command will need to run - * @return the new object - * @throws AccessException if there is a problem executing the command or the CommandExecutor is no longer valid - */ - TypedValue execute(EvaluationContext context, Object... arguments) throws AccessException; - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression; + + +// TODO Is the resolver/executor model too pervasive in this package? +/** + * Executors are built by resolvers and can be cached by the infrastructure to repeat an operation quickly without going + * back to the resolvers. For example, the particular constructor to run on a class may be discovered by the reflection + * constructor resolver - it will then build a ConstructorExecutor that executes that constructor and the + * ConstructorExecutor can be reused without needing to go back to the resolver to discover the constructor again. + * + * They can become stale, and in that case should throw an AccessException - this will cause the infrastructure to go + * back to the resolvers to ask for a new one. + * + * @author Andy Clement + * @since 3.0 + */ +public interface ConstructorExecutor { + + /** + * Execute a constructor in the specified context using the specified arguments. + * @param context the evaluation context in which the command is being executed + * @param arguments the arguments to the constructor call, should match (in terms of number and type) whatever the + * command will need to run + * @return the new object + * @throws AccessException if there is a problem executing the command or the CommandExecutor is no longer valid + */ + TypedValue execute(EvaluationContext context, Object... arguments) throws AccessException; + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/ConstructorResolver.java b/org.springframework.expression/src/main/java/org/springframework/expression/ConstructorResolver.java index 800971791f..57fb661711 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/ConstructorResolver.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/ConstructorResolver.java @@ -1,44 +1,44 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression; - -import java.util.List; - -import org.springframework.core.convert.TypeDescriptor; - -/** - * A constructor resolver attempts locate a constructor and returns a ConstructorExecutor that can be used to invoke - * that constructor. The ConstructorExecutor will be cached but if it 'goes stale' the resolvers will be called again. - * - * @author Andy Clement - * @since 3.0 - */ -public interface ConstructorResolver { - - /** - * Within the supplied context determine a suitable constructor on the supplied type that can handle the - * specified arguments. Return a ConstructorExecutor that can be used to invoke that constructor - * (or null if no constructor could be found). - * @param context the current evaluation context - * @param typeName the type upon which to look for the constructor - * @param argumentTypes the arguments that the constructor must be able to handle - * @return a ConstructorExecutor that can invoke the constructor, or null if non found - */ - ConstructorExecutor resolve(EvaluationContext context, String typeName, List argumentTypes) - throws AccessException; - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression; + +import java.util.List; + +import org.springframework.core.convert.TypeDescriptor; + +/** + * A constructor resolver attempts locate a constructor and returns a ConstructorExecutor that can be used to invoke + * that constructor. The ConstructorExecutor will be cached but if it 'goes stale' the resolvers will be called again. + * + * @author Andy Clement + * @since 3.0 + */ +public interface ConstructorResolver { + + /** + * Within the supplied context determine a suitable constructor on the supplied type that can handle the + * specified arguments. Return a ConstructorExecutor that can be used to invoke that constructor + * (or null if no constructor could be found). + * @param context the current evaluation context + * @param typeName the type upon which to look for the constructor + * @param argumentTypes the arguments that the constructor must be able to handle + * @return a ConstructorExecutor that can invoke the constructor, or null if non found + */ + ConstructorExecutor resolve(EvaluationContext context, String typeName, List argumentTypes) + throws AccessException; + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/ExpressionInvocationTargetException.java b/org.springframework.expression/src/main/java/org/springframework/expression/ExpressionInvocationTargetException.java index 4268039b44..6668fff415 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/ExpressionInvocationTargetException.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/ExpressionInvocationTargetException.java @@ -1,49 +1,49 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.expression; - -/** - * This exception wraps (as cause) a checked exception thrown by some method that SpEL invokes. - * It differs from a SpelEvaluationException because this indicates the occurrence of a checked exception - * that the invoked method was defined to throw. SpelEvaluationExceptions are for handling (and wrapping) - * unexpected exceptions. - * - * @author Andy Clement - * @since 3.0.3 - */ -public class ExpressionInvocationTargetException extends EvaluationException { - - public ExpressionInvocationTargetException(int position, String message, Throwable cause) { - super(position, message, cause); - } - - public ExpressionInvocationTargetException(int position, String message) { - super(position, message); - } - - public ExpressionInvocationTargetException(String expressionString, String message) { - super(expressionString, message); - } - - public ExpressionInvocationTargetException(String message, Throwable cause) { - super(message, cause); - } - - public ExpressionInvocationTargetException(String message) { - super(message); - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression; + +/** + * This exception wraps (as cause) a checked exception thrown by some method that SpEL invokes. + * It differs from a SpelEvaluationException because this indicates the occurrence of a checked exception + * that the invoked method was defined to throw. SpelEvaluationExceptions are for handling (and wrapping) + * unexpected exceptions. + * + * @author Andy Clement + * @since 3.0.3 + */ +public class ExpressionInvocationTargetException extends EvaluationException { + + public ExpressionInvocationTargetException(int position, String message, Throwable cause) { + super(position, message, cause); + } + + public ExpressionInvocationTargetException(int position, String message) { + super(position, message); + } + + public ExpressionInvocationTargetException(String expressionString, String message) { + super(expressionString, message); + } + + public ExpressionInvocationTargetException(String message, Throwable cause) { + super(message, cause); + } + + public ExpressionInvocationTargetException(String message) { + super(message); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/MethodExecutor.java b/org.springframework.expression/src/main/java/org/springframework/expression/MethodExecutor.java index 4093d1c766..bd4dd74516 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/MethodExecutor.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/MethodExecutor.java @@ -1,44 +1,44 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression; - -/** - * MethodExecutors are built by the resolvers and can be cached by the infrastructure to repeat an operation quickly - * without going back to the resolvers. For example, the particular method to run on an object may be discovered by the - * reflection method resolver - it will then build a MethodExecutor that executes that method and the MethodExecutor can - * be reused without needing to go back to the resolver to discover the method again. - * - *

They can become stale, and in that case should throw an AccessException - this will cause the infrastructure to go - * back to the resolvers to ask for a new one. - * - * @author Andy Clement - * @since 3.0 - */ -public interface MethodExecutor { - - /** - * Execute a command using the specified arguments, and using the specified expression state. - * @param context the evaluation context in which the command is being executed - * @param target the target object of the call - null for static methods - * @param arguments the arguments to the executor, should match (in terms of number and type) whatever the - * command will need to run - * @return the value returned from execution - * @throws AccessException if there is a problem executing the command or the MethodExecutor is no longer valid - */ - TypedValue execute(EvaluationContext context, Object target, Object... arguments) throws AccessException; - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression; + +/** + * MethodExecutors are built by the resolvers and can be cached by the infrastructure to repeat an operation quickly + * without going back to the resolvers. For example, the particular method to run on an object may be discovered by the + * reflection method resolver - it will then build a MethodExecutor that executes that method and the MethodExecutor can + * be reused without needing to go back to the resolver to discover the method again. + * + *

They can become stale, and in that case should throw an AccessException - this will cause the infrastructure to go + * back to the resolvers to ask for a new one. + * + * @author Andy Clement + * @since 3.0 + */ +public interface MethodExecutor { + + /** + * Execute a command using the specified arguments, and using the specified expression state. + * @param context the evaluation context in which the command is being executed + * @param target the target object of the call - null for static methods + * @param arguments the arguments to the executor, should match (in terms of number and type) whatever the + * command will need to run + * @return the value returned from execution + * @throws AccessException if there is a problem executing the command or the MethodExecutor is no longer valid + */ + TypedValue execute(EvaluationContext context, Object target, Object... arguments) throws AccessException; + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/MethodFilter.java b/org.springframework.expression/src/main/java/org/springframework/expression/MethodFilter.java index d81268d226..b2567425d4 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/MethodFilter.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/MethodFilter.java @@ -1,46 +1,46 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.expression; - -import java.lang.reflect.Method; -import java.util.List; - -/** - * MethodFilter instances allow SpEL users to fine tune the behaviour of the method resolution - * process. Method resolution (which translates from a method name in an expression to a real - * method to invoke) will normally retrieve candidate methods for invocation via a simple call - * to 'Class.getMethods()' and will choose the first one that is suitable for the - * input parameters. By registering a MethodFilter the user can receive a callback - * and change the methods that will be considered suitable. - * - * @author Andy Clement - * @since 3.0.1 - */ -public interface MethodFilter { - - /** - * Called by the method resolver to allow the SpEL user to organize the list of candidate - * methods that may be invoked. The filter can remove methods that should not be - * considered candidates and it may sort the results. The resolver will then search - * through the methods as returned from the filter when looking for a suitable - * candidate to invoke. - * - * @param methods the full list of methods the resolver was going to choose from - * @return a possible subset of input methods that may be sorted by order of relevance - */ - List filter(List methods); - +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression; + +import java.lang.reflect.Method; +import java.util.List; + +/** + * MethodFilter instances allow SpEL users to fine tune the behaviour of the method resolution + * process. Method resolution (which translates from a method name in an expression to a real + * method to invoke) will normally retrieve candidate methods for invocation via a simple call + * to 'Class.getMethods()' and will choose the first one that is suitable for the + * input parameters. By registering a MethodFilter the user can receive a callback + * and change the methods that will be considered suitable. + * + * @author Andy Clement + * @since 3.0.1 + */ +public interface MethodFilter { + + /** + * Called by the method resolver to allow the SpEL user to organize the list of candidate + * methods that may be invoked. The filter can remove methods that should not be + * considered candidates and it may sort the results. The resolver will then search + * through the methods as returned from the filter when looking for a suitable + * candidate to invoke. + * + * @param methods the full list of methods the resolver was going to choose from + * @return a possible subset of input methods that may be sorted by order of relevance + */ + List filter(List methods); + } \ No newline at end of file diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/MethodResolver.java b/org.springframework.expression/src/main/java/org/springframework/expression/MethodResolver.java index fbe3836fc3..013bedc6a3 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/MethodResolver.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/MethodResolver.java @@ -1,44 +1,44 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression; - -import java.util.List; - -import org.springframework.core.convert.TypeDescriptor; - -/** - * A method resolver attempts locate a method and returns a command executor that can be used to invoke that method. - * The command executor will be cached but if it 'goes stale' the resolvers will be called again. - * - * @author Andy Clement - * @since 3.0 - */ -public interface MethodResolver { - - /** - * Within the supplied context determine a suitable method on the supplied object that can handle the - * specified arguments. Return a MethodExecutor that can be used to invoke that method - * (or null if no method could be found). - * @param context the current evaluation context - * @param targetObject the object upon which the method is being called - * @param argumentTypes the arguments that the constructor must be able to handle - * @return a MethodExecutor that can invoke the method, or null if the method cannot be found - */ - MethodExecutor resolve(EvaluationContext context, Object targetObject, String name, - List argumentTypes) throws AccessException; - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression; + +import java.util.List; + +import org.springframework.core.convert.TypeDescriptor; + +/** + * A method resolver attempts locate a method and returns a command executor that can be used to invoke that method. + * The command executor will be cached but if it 'goes stale' the resolvers will be called again. + * + * @author Andy Clement + * @since 3.0 + */ +public interface MethodResolver { + + /** + * Within the supplied context determine a suitable method on the supplied object that can handle the + * specified arguments. Return a MethodExecutor that can be used to invoke that method + * (or null if no method could be found). + * @param context the current evaluation context + * @param targetObject the object upon which the method is being called + * @param argumentTypes the arguments that the constructor must be able to handle + * @return a MethodExecutor that can invoke the method, or null if the method cannot be found + */ + MethodExecutor resolve(EvaluationContext context, Object targetObject, String name, + List argumentTypes) throws AccessException; + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/Operation.java b/org.springframework.expression/src/main/java/org/springframework/expression/Operation.java index 38636a2b38..55055a5b4f 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/Operation.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/Operation.java @@ -1,29 +1,29 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression; - -/** - * Supported operations that an {@link OperatorOverloader} can implement for any pair of operands. - * - * @author Andy Clement - * @since 3.0 - */ -public enum Operation { - - ADD, SUBTRACT, DIVIDE, MULTIPLY, MODULUS, POWER - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression; + +/** + * Supported operations that an {@link OperatorOverloader} can implement for any pair of operands. + * + * @author Andy Clement + * @since 3.0 + */ +public enum Operation { + + ADD, SUBTRACT, DIVIDE, MULTIPLY, MODULUS, POWER + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/PropertyAccessor.java b/org.springframework.expression/src/main/java/org/springframework/expression/PropertyAccessor.java index 6b080ea373..c5f474e3ca 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/PropertyAccessor.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/PropertyAccessor.java @@ -1,81 +1,81 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression; - - -/** - * A property accessor is able to read (and possibly write) to object properties. The interface places no restrictions - * and so implementors are free to access properties directly as fields or through getters or in any other way they see - * as appropriate. A resolver can optionally specify an array of target classes for which it should be called - but if - * it returns null from getSpecificTargetClasses() then it will be called for all property references and given a chance - * to determine if it can read or write them. Property resolvers are considered to be ordered and each will be called in - * turn. The only rule that affects the call order is that any naming the target class directly in - * getSpecifiedTargetClasses() will be called first, before the general resolvers. - * - * @author Andy Clement - * @since 3.0 - */ -public interface PropertyAccessor { - - /** - * Return an array of classes for which this resolver should be called. Returning null indicates this is a general - * resolver that can be called in an attempt to resolve a property on any type. - * @return an array of classes that this resolver is suitable for (or null if a general resolver) - */ - Class[] getSpecificTargetClasses(); - - /** - * Called to determine if a resolver instance is able to access a specified property on a specified target object. - * @param context the evaluation context in which the access is being attempted - * @param target the target object upon which the property is being accessed - * @param name the name of the property being accessed - * @return true if this resolver is able to read the property - * @throws AccessException if there is any problem determining whether the property can be read - */ - boolean canRead(EvaluationContext context, Object target, String name) throws AccessException; - - /** - * Called to read a property from a specified target object - * @param context the evaluation context in which the access is being attempted - * @param target the target object upon which the property is being accessed - * @param name the name of the property being accessed - * @return a TypedValue object wrapping the property value read and a type descriptor for it - * @throws AccessException if there is any problem accessing the property value - */ - TypedValue read(EvaluationContext context, Object target, String name) throws AccessException; - - /** - * Called to determine if a resolver instance is able to write to a specified property on a specified target object. - * @param context the evaluation context in which the access is being attempted - * @param target the target object upon which the property is being accessed - * @param name the name of the property being accessed - * @return true if this resolver is able to write to the property - * @throws AccessException if there is any problem determining whether the property can be written to - */ - boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException; - - /** - * Called to write to a property on a specified target object. Should only succeed if canWrite() also returns true. - * @param context the evaluation context in which the access is being attempted - * @param target the target object upon which the property is being accessed - * @param name the name of the property being accessed - * @param newValue the new value for the property - * @throws AccessException if there is any problem writing to the property value - */ - void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException; - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression; + + +/** + * A property accessor is able to read (and possibly write) to object properties. The interface places no restrictions + * and so implementors are free to access properties directly as fields or through getters or in any other way they see + * as appropriate. A resolver can optionally specify an array of target classes for which it should be called - but if + * it returns null from getSpecificTargetClasses() then it will be called for all property references and given a chance + * to determine if it can read or write them. Property resolvers are considered to be ordered and each will be called in + * turn. The only rule that affects the call order is that any naming the target class directly in + * getSpecifiedTargetClasses() will be called first, before the general resolvers. + * + * @author Andy Clement + * @since 3.0 + */ +public interface PropertyAccessor { + + /** + * Return an array of classes for which this resolver should be called. Returning null indicates this is a general + * resolver that can be called in an attempt to resolve a property on any type. + * @return an array of classes that this resolver is suitable for (or null if a general resolver) + */ + Class[] getSpecificTargetClasses(); + + /** + * Called to determine if a resolver instance is able to access a specified property on a specified target object. + * @param context the evaluation context in which the access is being attempted + * @param target the target object upon which the property is being accessed + * @param name the name of the property being accessed + * @return true if this resolver is able to read the property + * @throws AccessException if there is any problem determining whether the property can be read + */ + boolean canRead(EvaluationContext context, Object target, String name) throws AccessException; + + /** + * Called to read a property from a specified target object + * @param context the evaluation context in which the access is being attempted + * @param target the target object upon which the property is being accessed + * @param name the name of the property being accessed + * @return a TypedValue object wrapping the property value read and a type descriptor for it + * @throws AccessException if there is any problem accessing the property value + */ + TypedValue read(EvaluationContext context, Object target, String name) throws AccessException; + + /** + * Called to determine if a resolver instance is able to write to a specified property on a specified target object. + * @param context the evaluation context in which the access is being attempted + * @param target the target object upon which the property is being accessed + * @param name the name of the property being accessed + * @return true if this resolver is able to write to the property + * @throws AccessException if there is any problem determining whether the property can be written to + */ + boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException; + + /** + * Called to write to a property on a specified target object. Should only succeed if canWrite() also returns true. + * @param context the evaluation context in which the access is being attempted + * @param target the target object upon which the property is being accessed + * @param name the name of the property being accessed + * @param newValue the new value for the property + * @throws AccessException if there is any problem writing to the property value + */ + void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException; + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/TypeConverter.java b/org.springframework.expression/src/main/java/org/springframework/expression/TypeConverter.java index 8ac4ebf9e4..e6145ab20e 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/TypeConverter.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/TypeConverter.java @@ -1,53 +1,53 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression; - -import org.springframework.core.convert.TypeDescriptor; - -/** - * A type converter can convert values between different types encountered - * during expression evaluation. This is an SPI for the expression parser; - * see {@link org.springframework.core.convert.ConversionService} for the - * primary user API to Spring's conversion facilities. - * - * @author Andy Clement - * @author Juergen Hoeller - * @since 3.0 - */ -public interface TypeConverter { - - /** - * Return true if the type converter can convert the specified type to the desired target type. - * @param sourceType a type descriptor that describes the source type - * @param targetType a type descriptor that describes the requested result type - * @return true if that conversion can be performed - */ - boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType); - - /** - * Convert (may coerce) a value from one type to another, for example from a boolean to a string. - * The typeDescriptor parameter enables support for typed collections - if the caller really wishes they - * can have a List<Integer> for example, rather than simply a List. - * @param value the value to be converted - * @param sourceType a type descriptor that supplies extra information about the source object - * @param targetType a type descriptor that supplies extra information about the requested result type - * @return the converted value - * @throws EvaluationException if conversion is not possible - */ - Object convertValue(Object value, TypeDescriptor sourceType, TypeDescriptor targetType); - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression; + +import org.springframework.core.convert.TypeDescriptor; + +/** + * A type converter can convert values between different types encountered + * during expression evaluation. This is an SPI for the expression parser; + * see {@link org.springframework.core.convert.ConversionService} for the + * primary user API to Spring's conversion facilities. + * + * @author Andy Clement + * @author Juergen Hoeller + * @since 3.0 + */ +public interface TypeConverter { + + /** + * Return true if the type converter can convert the specified type to the desired target type. + * @param sourceType a type descriptor that describes the source type + * @param targetType a type descriptor that describes the requested result type + * @return true if that conversion can be performed + */ + boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType); + + /** + * Convert (may coerce) a value from one type to another, for example from a boolean to a string. + * The typeDescriptor parameter enables support for typed collections - if the caller really wishes they + * can have a List<Integer> for example, rather than simply a List. + * @param value the value to be converted + * @param sourceType a type descriptor that supplies extra information about the source object + * @param targetType a type descriptor that supplies extra information about the requested result type + * @return the converted value + * @throws EvaluationException if conversion is not possible + */ + Object convertValue(Object value, TypeDescriptor sourceType, TypeDescriptor targetType); + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/TypedValue.java b/org.springframework.expression/src/main/java/org/springframework/expression/TypedValue.java index bf85bd72f3..ec063ff54c 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/TypedValue.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/TypedValue.java @@ -1,80 +1,80 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression; - -import org.springframework.core.convert.TypeDescriptor; - -/** - * Encapsulates an object and a type descriptor that describes it. - * The type descriptor can hold generic information that would not be - * accessible through a simple getClass() call on the object. - * - * @author Andy Clement - * @author Juergen Hoeller - * @since 3.0 - */ -public class TypedValue { - - public static final TypedValue NULL = new TypedValue(null); - - - private final Object value; - - private TypeDescriptor typeDescriptor; - - - /** - * Create a TypedValue for a simple object. The type descriptor is inferred - * from the object, so no generic information is preserved. - * @param value the object value - */ - public TypedValue(Object value) { - this.value = value; - this.typeDescriptor = null; // initialized when/if requested - } - - /** - * Create a TypedValue for a particular value with a particular type descriptor. - * @param value the object value - * @param typeDescriptor a type descriptor describing the type of the value - */ - public TypedValue(Object value, TypeDescriptor typeDescriptor) { - this.value = value; - this.typeDescriptor = typeDescriptor; - } - - - public Object getValue() { - return this.value; - } - - public TypeDescriptor getTypeDescriptor() { - if (this.typeDescriptor == null) { - this.typeDescriptor = TypeDescriptor.forObject(this.value); - } - return this.typeDescriptor; - } - - - @Override - public String toString() { - StringBuilder str = new StringBuilder(); - str.append("TypedValue: '").append(this.value).append("' of [").append(getTypeDescriptor() + "]"); - return str.toString(); - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression; + +import org.springframework.core.convert.TypeDescriptor; + +/** + * Encapsulates an object and a type descriptor that describes it. + * The type descriptor can hold generic information that would not be + * accessible through a simple getClass() call on the object. + * + * @author Andy Clement + * @author Juergen Hoeller + * @since 3.0 + */ +public class TypedValue { + + public static final TypedValue NULL = new TypedValue(null); + + + private final Object value; + + private TypeDescriptor typeDescriptor; + + + /** + * Create a TypedValue for a simple object. The type descriptor is inferred + * from the object, so no generic information is preserved. + * @param value the object value + */ + public TypedValue(Object value) { + this.value = value; + this.typeDescriptor = null; // initialized when/if requested + } + + /** + * Create a TypedValue for a particular value with a particular type descriptor. + * @param value the object value + * @param typeDescriptor a type descriptor describing the type of the value + */ + public TypedValue(Object value, TypeDescriptor typeDescriptor) { + this.value = value; + this.typeDescriptor = typeDescriptor; + } + + + public Object getValue() { + return this.value; + } + + public TypeDescriptor getTypeDescriptor() { + if (this.typeDescriptor == null) { + this.typeDescriptor = TypeDescriptor.forObject(this.value); + } + return this.typeDescriptor; + } + + + @Override + public String toString() { + StringBuilder str = new StringBuilder(); + str.append("TypedValue: '").append(this.value).append("' of [").append(getTypeDescriptor() + "]"); + return str.toString(); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/common/TemplateParserContext.java b/org.springframework.expression/src/main/java/org/springframework/expression/common/TemplateParserContext.java index fb6251038b..c1ed129dec 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/common/TemplateParserContext.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/common/TemplateParserContext.java @@ -1,65 +1,65 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.common; - -import org.springframework.expression.ParserContext; - -/** - * Configurable {@link ParserContext} implementation for template parsing. - * Expects the expression prefix and suffix as constructor arguments. - * - * @author Juergen Hoeller - * @since 3.0 - */ -public class TemplateParserContext implements ParserContext { - - private final String expressionPrefix; - - private final String expressionSuffix; - - - /** - * Create a new TemplateParserContext with the default "#{" prefix and "}" suffix. - */ - public TemplateParserContext() { - this("#{", "}"); - } - - /** - * Create a new TemplateParserContext for the given prefix and suffix. - * @param expressionPrefix the expression prefix to use - * @param expressionSuffix the expression suffix to use - */ - public TemplateParserContext(String expressionPrefix, String expressionSuffix) { - this.expressionPrefix = expressionPrefix; - this.expressionSuffix = expressionSuffix; - } - - - public final boolean isTemplate() { - return true; - } - - public final String getExpressionPrefix() { - return this.expressionPrefix; - } - - public final String getExpressionSuffix() { - return this.expressionSuffix; - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.common; + +import org.springframework.expression.ParserContext; + +/** + * Configurable {@link ParserContext} implementation for template parsing. + * Expects the expression prefix and suffix as constructor arguments. + * + * @author Juergen Hoeller + * @since 3.0 + */ +public class TemplateParserContext implements ParserContext { + + private final String expressionPrefix; + + private final String expressionSuffix; + + + /** + * Create a new TemplateParserContext with the default "#{" prefix and "}" suffix. + */ + public TemplateParserContext() { + this("#{", "}"); + } + + /** + * Create a new TemplateParserContext for the given prefix and suffix. + * @param expressionPrefix the expression prefix to use + * @param expressionSuffix the expression suffix to use + */ + public TemplateParserContext(String expressionPrefix, String expressionSuffix) { + this.expressionPrefix = expressionPrefix; + this.expressionSuffix = expressionSuffix; + } + + + public final boolean isTemplate() { + return true; + } + + public final String getExpressionPrefix() { + return this.expressionPrefix; + } + + public final String getExpressionSuffix() { + return this.expressionSuffix; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ExpressionState.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ExpressionState.java index 5eb3ce8a88..09f51cfe81 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ExpressionState.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ExpressionState.java @@ -1,242 +1,242 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Stack; - -import org.springframework.core.convert.TypeDescriptor; -import org.springframework.expression.EvaluationContext; -import org.springframework.expression.EvaluationException; -import org.springframework.expression.Operation; -import org.springframework.expression.OperatorOverloader; -import org.springframework.expression.PropertyAccessor; -import org.springframework.expression.TypeComparator; -import org.springframework.expression.TypedValue; - -/** - * An ExpressionState is for maintaining per-expression-evaluation state, any changes to it are not seen by other - * expressions but it gives a place to hold local variables and for component expressions in a compound expression to - * communicate state. This is in contrast to the EvaluationContext, which is shared amongst expression evaluations, and - * any changes to it will be seen by other expressions or any code that chooses to ask questions of the context. - * - *

It also acts as a place for to define common utility routines that the various Ast nodes might need. - * - * @author Andy Clement - * @since 3.0 - */ -public class ExpressionState { - - private final EvaluationContext relatedContext; - - private Stack variableScopes; - - private Stack contextObjects; - - private final TypedValue rootObject; - - private SpelParserConfiguration configuration; - - - public ExpressionState(EvaluationContext context) { - this.relatedContext = context; - this.rootObject = context.getRootObject(); - } - - public ExpressionState(EvaluationContext context, SpelParserConfiguration configuration) { - this.relatedContext = context; - this.configuration = configuration; - this.rootObject = context.getRootObject(); - } - - public ExpressionState(EvaluationContext context, TypedValue rootObject) { - this.relatedContext = context; - this.rootObject = rootObject; - } - - public ExpressionState(EvaluationContext context, TypedValue rootObject, SpelParserConfiguration configuration) { - this.relatedContext = context; - this.configuration = configuration; - this.rootObject = rootObject; - } - - - private void ensureVariableScopesInitialized() { - if (this.variableScopes == null) { - this.variableScopes = new Stack(); - // top level empty variable scope - this.variableScopes.add(new VariableScope()); - } - } - - /** - * The active context object is what unqualified references to properties/etc are resolved against. - */ - public TypedValue getActiveContextObject() { - if (this.contextObjects==null || this.contextObjects.isEmpty()) { - return this.rootObject; - } - - return this.contextObjects.peek(); - } - - public void pushActiveContextObject(TypedValue obj) { - if (this.contextObjects==null) { - this.contextObjects = new Stack(); - } - this.contextObjects.push(obj); - } - - public void popActiveContextObject() { - if (this.contextObjects==null) { - this.contextObjects = new Stack(); - } - this.contextObjects.pop(); - } - - public TypedValue getRootContextObject() { - return this.rootObject; - } - - public void setVariable(String name, Object value) { - this.relatedContext.setVariable(name, value); - } - - public TypedValue lookupVariable(String name) { - Object value = this.relatedContext.lookupVariable(name); - if (value == null) { - return TypedValue.NULL; - } - else { - return new TypedValue(value); - } - } - - public TypeComparator getTypeComparator() { - return this.relatedContext.getTypeComparator(); - } - - public Class findType(String type) throws EvaluationException { - return this.relatedContext.getTypeLocator().findType(type); - } - - public Object convertValue(Object value, TypeDescriptor targetTypeDescriptor) throws EvaluationException { - return this.relatedContext.getTypeConverter().convertValue(value, TypeDescriptor.forObject(value), targetTypeDescriptor); - } - - public Object convertValue(TypedValue value, TypeDescriptor targetTypeDescriptor) throws EvaluationException { - Object val = value.getValue(); - return this.relatedContext.getTypeConverter().convertValue(val, TypeDescriptor.forObject(val), targetTypeDescriptor); - } - - /* - * A new scope is entered when a function is invoked - */ - - public void enterScope(Map argMap) { - ensureVariableScopesInitialized(); - this.variableScopes.push(new VariableScope(argMap)); - } - - public void enterScope(String name, Object value) { - ensureVariableScopesInitialized(); - this.variableScopes.push(new VariableScope(name, value)); - } - - public void exitScope() { - ensureVariableScopesInitialized(); - this.variableScopes.pop(); - } - - public void setLocalVariable(String name, Object value) { - ensureVariableScopesInitialized(); - this.variableScopes.peek().setVariable(name, value); - } - - public Object lookupLocalVariable(String name) { - ensureVariableScopesInitialized(); - int scopeNumber = this.variableScopes.size() - 1; - for (int i = scopeNumber; i >= 0; i--) { - if (this.variableScopes.get(i).definesVariable(name)) { - return this.variableScopes.get(i).lookupVariable(name); - } - } - return null; - } - - public TypedValue operate(Operation op, Object left, Object right) throws EvaluationException { - OperatorOverloader overloader = this.relatedContext.getOperatorOverloader(); - if (overloader.overridesOperation(op, left, right)) { - Object returnValue = overloader.operate(op, left, right); - return new TypedValue(returnValue); - } - else { - String leftType = (left==null?"null":left.getClass().getName()); - String rightType = (right==null?"null":right.getClass().getName()); - throw new SpelEvaluationException(SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES, op, leftType, rightType); - } - } - - public List getPropertyAccessors() { - return this.relatedContext.getPropertyAccessors(); - } - - public EvaluationContext getEvaluationContext() { - return this.relatedContext; - } - - public SpelParserConfiguration getConfiguration() { - return this.configuration; - } - - /** - * A new scope is entered when a function is called and it is used to hold the parameters to the function call. If the names - * of the parameters clash with those in a higher level scope, those in the higher level scope will not be accessible whilst - * the function is executing. When the function returns the scope is exited. - */ - private static class VariableScope { - - private final Map vars = new HashMap(); - - public VariableScope() { } - - public VariableScope(Map arguments) { - if (arguments != null) { - this.vars.putAll(arguments); - } - } - - public VariableScope(String name, Object value) { - this.vars.put(name,value); - } - - public Object lookupVariable(String name) { - return this.vars.get(name); - } - - public void setVariable(String name, Object value) { - this.vars.put(name,value); - } - - public boolean definesVariable(String name) { - return this.vars.containsKey(name); - } - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.Operation; +import org.springframework.expression.OperatorOverloader; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.TypeComparator; +import org.springframework.expression.TypedValue; + +/** + * An ExpressionState is for maintaining per-expression-evaluation state, any changes to it are not seen by other + * expressions but it gives a place to hold local variables and for component expressions in a compound expression to + * communicate state. This is in contrast to the EvaluationContext, which is shared amongst expression evaluations, and + * any changes to it will be seen by other expressions or any code that chooses to ask questions of the context. + * + *

It also acts as a place for to define common utility routines that the various Ast nodes might need. + * + * @author Andy Clement + * @since 3.0 + */ +public class ExpressionState { + + private final EvaluationContext relatedContext; + + private Stack variableScopes; + + private Stack contextObjects; + + private final TypedValue rootObject; + + private SpelParserConfiguration configuration; + + + public ExpressionState(EvaluationContext context) { + this.relatedContext = context; + this.rootObject = context.getRootObject(); + } + + public ExpressionState(EvaluationContext context, SpelParserConfiguration configuration) { + this.relatedContext = context; + this.configuration = configuration; + this.rootObject = context.getRootObject(); + } + + public ExpressionState(EvaluationContext context, TypedValue rootObject) { + this.relatedContext = context; + this.rootObject = rootObject; + } + + public ExpressionState(EvaluationContext context, TypedValue rootObject, SpelParserConfiguration configuration) { + this.relatedContext = context; + this.configuration = configuration; + this.rootObject = rootObject; + } + + + private void ensureVariableScopesInitialized() { + if (this.variableScopes == null) { + this.variableScopes = new Stack(); + // top level empty variable scope + this.variableScopes.add(new VariableScope()); + } + } + + /** + * The active context object is what unqualified references to properties/etc are resolved against. + */ + public TypedValue getActiveContextObject() { + if (this.contextObjects==null || this.contextObjects.isEmpty()) { + return this.rootObject; + } + + return this.contextObjects.peek(); + } + + public void pushActiveContextObject(TypedValue obj) { + if (this.contextObjects==null) { + this.contextObjects = new Stack(); + } + this.contextObjects.push(obj); + } + + public void popActiveContextObject() { + if (this.contextObjects==null) { + this.contextObjects = new Stack(); + } + this.contextObjects.pop(); + } + + public TypedValue getRootContextObject() { + return this.rootObject; + } + + public void setVariable(String name, Object value) { + this.relatedContext.setVariable(name, value); + } + + public TypedValue lookupVariable(String name) { + Object value = this.relatedContext.lookupVariable(name); + if (value == null) { + return TypedValue.NULL; + } + else { + return new TypedValue(value); + } + } + + public TypeComparator getTypeComparator() { + return this.relatedContext.getTypeComparator(); + } + + public Class findType(String type) throws EvaluationException { + return this.relatedContext.getTypeLocator().findType(type); + } + + public Object convertValue(Object value, TypeDescriptor targetTypeDescriptor) throws EvaluationException { + return this.relatedContext.getTypeConverter().convertValue(value, TypeDescriptor.forObject(value), targetTypeDescriptor); + } + + public Object convertValue(TypedValue value, TypeDescriptor targetTypeDescriptor) throws EvaluationException { + Object val = value.getValue(); + return this.relatedContext.getTypeConverter().convertValue(val, TypeDescriptor.forObject(val), targetTypeDescriptor); + } + + /* + * A new scope is entered when a function is invoked + */ + + public void enterScope(Map argMap) { + ensureVariableScopesInitialized(); + this.variableScopes.push(new VariableScope(argMap)); + } + + public void enterScope(String name, Object value) { + ensureVariableScopesInitialized(); + this.variableScopes.push(new VariableScope(name, value)); + } + + public void exitScope() { + ensureVariableScopesInitialized(); + this.variableScopes.pop(); + } + + public void setLocalVariable(String name, Object value) { + ensureVariableScopesInitialized(); + this.variableScopes.peek().setVariable(name, value); + } + + public Object lookupLocalVariable(String name) { + ensureVariableScopesInitialized(); + int scopeNumber = this.variableScopes.size() - 1; + for (int i = scopeNumber; i >= 0; i--) { + if (this.variableScopes.get(i).definesVariable(name)) { + return this.variableScopes.get(i).lookupVariable(name); + } + } + return null; + } + + public TypedValue operate(Operation op, Object left, Object right) throws EvaluationException { + OperatorOverloader overloader = this.relatedContext.getOperatorOverloader(); + if (overloader.overridesOperation(op, left, right)) { + Object returnValue = overloader.operate(op, left, right); + return new TypedValue(returnValue); + } + else { + String leftType = (left==null?"null":left.getClass().getName()); + String rightType = (right==null?"null":right.getClass().getName()); + throw new SpelEvaluationException(SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES, op, leftType, rightType); + } + } + + public List getPropertyAccessors() { + return this.relatedContext.getPropertyAccessors(); + } + + public EvaluationContext getEvaluationContext() { + return this.relatedContext; + } + + public SpelParserConfiguration getConfiguration() { + return this.configuration; + } + + /** + * A new scope is entered when a function is called and it is used to hold the parameters to the function call. If the names + * of the parameters clash with those in a higher level scope, those in the higher level scope will not be accessible whilst + * the function is executing. When the function returns the scope is exited. + */ + private static class VariableScope { + + private final Map vars = new HashMap(); + + public VariableScope() { } + + public VariableScope(Map arguments) { + if (arguments != null) { + this.vars.putAll(arguments); + } + } + + public VariableScope(String name, Object value) { + this.vars.put(name,value); + } + + public Object lookupVariable(String name) { + return this.vars.get(name); + } + + public void setVariable(String name, Object value) { + this.vars.put(name,value); + } + + public boolean definesVariable(String name) { + return this.vars.containsKey(name); + } + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/InternalParseException.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/InternalParseException.java index ac76105e28..fd3dcb5549 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/InternalParseException.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/InternalParseException.java @@ -1,38 +1,38 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel; - -import org.springframework.expression.spel.SpelParseException; - -/** - * Wraps a real parse exception. This exception flows to the top parse method and then - * the wrapped exception is thrown as the real problem. - * - * @author Andy Clement - * @since 3.0 - */ -public class InternalParseException extends RuntimeException { - - public InternalParseException(SpelParseException cause) { - super(cause); - } - - public SpelParseException getCause() { - return (SpelParseException) super.getCause(); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel; + +import org.springframework.expression.spel.SpelParseException; + +/** + * Wraps a real parse exception. This exception flows to the top parse method and then + * the wrapped exception is thrown as the real problem. + * + * @author Andy Clement + * @since 3.0 + */ +public class InternalParseException extends RuntimeException { + + public InternalParseException(SpelParseException cause) { + super(cause); + } + + public SpelParseException getCause() { + return (SpelParseException) super.getCause(); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelEvaluationException.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelEvaluationException.java index c7c3161781..e736d3bf74 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelEvaluationException.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelEvaluationException.java @@ -1,92 +1,92 @@ -/* - * Copyright 2004-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.expression.spel; - -import org.springframework.expression.EvaluationException; - -/** - * Root exception for Spring EL related exceptions. Rather than holding a hard coded string indicating the problem, it - * records a message key and the inserts for the message. See {@link SpelMessage} for the list of all possible messages - * that can occur. - * - * @author Andy Clement - * @since 3.0 - */ -public class SpelEvaluationException extends EvaluationException { - - private SpelMessage message; - private Object[] inserts; - - public SpelEvaluationException(SpelMessage message, Object... inserts) { - super(message.formatMessage(0, inserts)); // TODO poor position information, can the callers not really supply something? - this.message = message; - this.inserts = inserts; - } - - public SpelEvaluationException(int position, SpelMessage message, Object... inserts) { - super(position, message.formatMessage(position, inserts)); - this.message = message; - this.inserts = inserts; - } - - public SpelEvaluationException(int position, Throwable cause, - SpelMessage message, Object... inserts) { - super(position,message.formatMessage(position,inserts),cause); - this.message = message; - this.inserts = inserts; - } - - public SpelEvaluationException(Throwable cause, SpelMessage message, Object... inserts) { - super(message.formatMessage(0,inserts),cause); - this.message = message; - this.inserts = inserts; - } - - /** - * @return a formatted message with inserts applied - */ - @Override - public String getMessage() { - if (message != null) - return message.formatMessage(position, inserts); - else - return super.getMessage(); - } - - /** - * @return the message code - */ - public SpelMessage getMessageCode() { - return this.message; - } - - /** - * Set the position in the related expression which gave rise to this exception. - * - * @param position the position in the expression that gave rise to the exception - */ - public void setPosition(int position) { - this.position = position; - } - - /** - * @return the message inserts - */ - public Object[] getInserts() { - return inserts; - } - -} +/* + * Copyright 2004-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel; + +import org.springframework.expression.EvaluationException; + +/** + * Root exception for Spring EL related exceptions. Rather than holding a hard coded string indicating the problem, it + * records a message key and the inserts for the message. See {@link SpelMessage} for the list of all possible messages + * that can occur. + * + * @author Andy Clement + * @since 3.0 + */ +public class SpelEvaluationException extends EvaluationException { + + private SpelMessage message; + private Object[] inserts; + + public SpelEvaluationException(SpelMessage message, Object... inserts) { + super(message.formatMessage(0, inserts)); // TODO poor position information, can the callers not really supply something? + this.message = message; + this.inserts = inserts; + } + + public SpelEvaluationException(int position, SpelMessage message, Object... inserts) { + super(position, message.formatMessage(position, inserts)); + this.message = message; + this.inserts = inserts; + } + + public SpelEvaluationException(int position, Throwable cause, + SpelMessage message, Object... inserts) { + super(position,message.formatMessage(position,inserts),cause); + this.message = message; + this.inserts = inserts; + } + + public SpelEvaluationException(Throwable cause, SpelMessage message, Object... inserts) { + super(message.formatMessage(0,inserts),cause); + this.message = message; + this.inserts = inserts; + } + + /** + * @return a formatted message with inserts applied + */ + @Override + public String getMessage() { + if (message != null) + return message.formatMessage(position, inserts); + else + return super.getMessage(); + } + + /** + * @return the message code + */ + public SpelMessage getMessageCode() { + return this.message; + } + + /** + * Set the position in the related expression which gave rise to this exception. + * + * @param position the position in the expression that gave rise to the exception + */ + public void setPosition(int position) { + this.position = position; + } + + /** + * @return the message inserts + */ + public Object[] getInserts() { + return inserts; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelMessage.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelMessage.java index 459bed1ea4..14f0bfb9b9 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelMessage.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelMessage.java @@ -1,156 +1,156 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel; - -import java.text.MessageFormat; - -/** - * Contains all the messages that can be produced by the Spring Expression Language. Each message has a kind (info, - * warn, error) and a code number. Tests can be written to expect particular code numbers rather than particular text, - * enabling the message text to more easily be modified and the tests to run successfully in different locales. - *

- * When a message is formatted, it will have this kind of form - * - *

- * EL1004E: (pos 34): Type cannot be found 'String'
- * 
- * - * The prefix captures the code and the error kind, whilst the position is included if it is known. - * - * @author Andy Clement - * @since 3.0 - */ -public enum SpelMessage { - - TYPE_CONVERSION_ERROR(Kind.ERROR, 1001, "Type conversion problem, cannot convert from {0} to {1}"), // - CONSTRUCTOR_NOT_FOUND(Kind.ERROR, 1002, "Constructor call: No suitable constructor found on type {0} for arguments {1}"), // - CONSTRUCTOR_INVOCATION_PROBLEM(Kind.ERROR, 1003, "A problem occurred whilst attempting to construct an object of type ''{0}'' using arguments ''{1}''"), // - METHOD_NOT_FOUND(Kind.ERROR, 1004, "Method call: Method {0} cannot be found on {1} type"), // - TYPE_NOT_FOUND(Kind.ERROR, 1005, "Type cannot be found ''{0}''"), // - FUNCTION_NOT_DEFINED(Kind.ERROR, 1006, "The function ''{0}'' could not be found"), // - PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL(Kind.ERROR, 1007, "Field or property ''{0}'' cannot be found on null"), // - PROPERTY_OR_FIELD_NOT_READABLE(Kind.ERROR, 1008, "Field or property ''{0}'' cannot be found on object of type ''{1}''"), // - PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL(Kind.ERROR, 1009, "Field or property ''{0}'' cannot be set on null"), // - PROPERTY_OR_FIELD_NOT_WRITABLE(Kind.ERROR, 1010, "Field or property ''{0}'' cannot be set on object of type ''{1}''"), // - METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED(Kind.ERROR, 1011, "Method call: Attempted to call method {0} on null context object"), // - CANNOT_INDEX_INTO_NULL_VALUE(Kind.ERROR, 1012, "Cannot index into a null value"), - NOT_COMPARABLE(Kind.ERROR, 1013, "Cannot compare instances of {0} and {1}"), // - INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION(Kind.ERROR, 1014, "Incorrect number of arguments for function, {0} supplied but function takes {1}"), // - INVALID_TYPE_FOR_SELECTION(Kind.ERROR, 1015, "Cannot perform selection on input data of type ''{0}''"), // - RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN(Kind.ERROR, 1016, "Result of selection criteria is not boolean"), // - BETWEEN_RIGHT_OPERAND_MUST_BE_TWO_ELEMENT_LIST(Kind.ERROR, 1017, "Right operand for the 'between' operator has to be a two-element list"), // - INVALID_PATTERN(Kind.ERROR, 1018, "Pattern is not valid ''{0}''"), // - PROJECTION_NOT_SUPPORTED_ON_TYPE(Kind.ERROR, 1019, "Projection is not supported on the type ''{0}''"), // - ARGLIST_SHOULD_NOT_BE_EVALUATED(Kind.ERROR, 1020, "The argument list of a lambda expression should never have getValue() called upon it"), // - EXCEPTION_DURING_PROPERTY_READ(Kind.ERROR, 1021, "A problem occurred whilst attempting to access the property ''{0}'': ''{1}''"), // - FUNCTION_REFERENCE_CANNOT_BE_INVOKED(Kind.ERROR, 1022, "The function ''{0}'' mapped to an object of type ''{1}'' which cannot be invoked"), // - EXCEPTION_DURING_FUNCTION_CALL(Kind.ERROR, 1023, "A problem occurred whilst attempting to invoke the function ''{0}'': ''{1}''"), // - ARRAY_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1024, "The array has ''{0}'' elements, index ''{1}'' is invalid"), // - COLLECTION_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1025, "The collection has ''{0}'' elements, index ''{1}'' is invalid"), // - STRING_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1026, "The string has ''{0}'' characters, index ''{1}'' is invalid"), // - INDEXING_NOT_SUPPORTED_FOR_TYPE(Kind.ERROR, 1027, "Indexing into type ''{0}'' is not supported"), // - INSTANCEOF_OPERATOR_NEEDS_CLASS_OPERAND(Kind.ERROR, 1028, "The operator 'instanceof' needs the right operand to be a class, not a ''{0}''"), // - EXCEPTION_DURING_METHOD_INVOCATION(Kind.ERROR, 1029, "A problem occurred when trying to execute method ''{0}'' on object of type ''{1}'': ''{2}''"), // - OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES(Kind.ERROR, 1030, "The operator ''{0}'' is not supported between objects of type ''{1}'' and ''{2}''"), // - PROBLEM_LOCATING_METHOD(Kind.ERROR, 1031, "Problem locating method {0} cannot on type {1}"), - SETVALUE_NOT_SUPPORTED( Kind.ERROR, 1032, "setValue(ExpressionState, Object) not supported for ''{0}''"), // - MULTIPLE_POSSIBLE_METHODS(Kind.ERROR, 1033, "Method call of ''{0}'' is ambiguous, supported type conversions allow multiple variants to match"), // - EXCEPTION_DURING_PROPERTY_WRITE(Kind.ERROR, 1034, "A problem occurred whilst attempting to set the property ''{0}'': {1}"), // - NOT_AN_INTEGER(Kind.ERROR, 1035, "The value ''{0}'' cannot be parsed as an int"), // - NOT_A_LONG(Kind.ERROR, 1036, "The value ''{0}'' cannot be parsed as a long"), // - INVALID_FIRST_OPERAND_FOR_MATCHES_OPERATOR(Kind.ERROR, 1037, "First operand to matches operator must be a string. ''{0}'' is not"), // - INVALID_SECOND_OPERAND_FOR_MATCHES_OPERATOR(Kind.ERROR, 1038, "Second operand to matches operator must be a string. ''{0}'' is not"), // - FUNCTION_MUST_BE_STATIC(Kind.ERROR, 1039, "Only static methods can be called via function references. The method ''{0}'' referred to by name ''{1}'' is not static."),// - NOT_A_REAL(Kind.ERROR, 1040, "The value ''{0}'' cannot be parsed as a double"), // - MORE_INPUT(Kind.ERROR,1041, "After parsing a valid expression, there is still more data in the expression: ''{0}''"), - RIGHT_OPERAND_PROBLEM(Kind.ERROR,1042, "Problem parsing right operand"), - NOT_EXPECTED_TOKEN(Kind.ERROR,1043,"Unexpected token. Expected ''{0}'' but was ''{1}''"), - OOD(Kind.ERROR,1044,"Unexpectedly ran out of input"), // - NON_TERMINATING_DOUBLE_QUOTED_STRING(Kind.ERROR,1045,"Cannot find terminating \" for string"),// - NON_TERMINATING_QUOTED_STRING(Kind.ERROR,1046,"Cannot find terminating ' for string"), // - MISSING_LEADING_ZERO_FOR_NUMBER(Kind.ERROR,1047,"A real number must be prefixed by zero, it cannot start with just ''.''"), // - REAL_CANNOT_BE_LONG(Kind.ERROR,1048,"Real number cannot be suffixed with a long (L or l) suffix"),// - UNEXPECTED_DATA_AFTER_DOT(Kind.ERROR,1049,"Unexpected data after ''.'': ''{0}''"),// - MISSING_CONSTRUCTOR_ARGS(Kind.ERROR,1050,"The arguments '(...)' for the constructor call are missing"),// - RUN_OUT_OF_ARGUMENTS(Kind.ERROR,1051,"Unexpected ran out of arguments"),// - UNABLE_TO_GROW_COLLECTION(Kind.ERROR,1052,"Unable to grow collection"),// - UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE(Kind.ERROR,1053,"Unable to grow collection: unable to determine list element type"),// - UNABLE_TO_CREATE_LIST_FOR_INDEXING(Kind.ERROR,1054,"Unable to dynamically create a List to replace a null value"),// - UNABLE_TO_CREATE_MAP_FOR_INDEXING(Kind.ERROR,1055,"Unable to dynamically create a Map to replace a null value"),// - UNABLE_TO_DYNAMICALLY_CREATE_OBJECT(Kind.ERROR,1056,"Unable to dynamically create instance of ''{0}'' to replace a null value"),// - NO_BEAN_RESOLVER_REGISTERED(Kind.ERROR,1057,"No bean resolver registered in the context to resolve access to bean ''{0}''"),// - EXCEPTION_DURING_BEAN_RESOLUTION(Kind.ERROR, 1058, "A problem occurred when trying to resolve bean ''{0}'':''{1}''"), // - INVALID_BEAN_REFERENCE(Kind.ERROR,1059,"@ can only be followed by an identifier or a quoted name"),// - TYPE_NAME_EXPECTED_FOR_ARRAY_CONSTRUCTION(Kind.ERROR, 1060, - "Expected the type of the new array to be specified as a String but found ''{0}''"), // - INCORRECT_ELEMENT_TYPE_FOR_ARRAY(Kind.ERROR, 1061, - "The array of type ''{0}'' cannot have an element of type ''{1}'' inserted"), // - MULTIDIM_ARRAY_INITIALIZER_NOT_SUPPORTED(Kind.ERROR, 1062, - "Using an initializer to build a multi-dimensional array is not currently supported"), // - MISSING_ARRAY_DIMENSION(Kind.ERROR, 1063, "A required array dimension has not been specified"), // - INITIALIZER_LENGTH_INCORRECT( - Kind.ERROR, 1064, "array initializer size does not match array dimensions"), // - ; - - private Kind kind; - private int code; - private String message; - - - private SpelMessage(Kind kind, int code, String message) { - this.kind = kind; - this.code = code; - this.message = message; - } - - - /** - * Produce a complete message including the prefix, the position (if known) and with the inserts applied to the - * message. - * - * @param pos the position, if less than zero it is ignored and not included in the message - * @param inserts the inserts to put into the formatted message - * @return a formatted message - */ - public String formatMessage(int pos, Object... inserts) { - StringBuilder formattedMessage = new StringBuilder(); - formattedMessage.append("EL").append(code); - switch (kind) { -// case WARNING: -// formattedMessage.append("W"); -// break; -// case INFO: -// formattedMessage.append("I"); -// break; - case ERROR: - formattedMessage.append("E"); - break; - } - formattedMessage.append(":"); - if (pos != -1) { - formattedMessage.append("(pos ").append(pos).append("): "); - } - formattedMessage.append(MessageFormat.format(message, inserts)); - return formattedMessage.toString(); - } - - - public static enum Kind { - INFO, WARNING, ERROR - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel; + +import java.text.MessageFormat; + +/** + * Contains all the messages that can be produced by the Spring Expression Language. Each message has a kind (info, + * warn, error) and a code number. Tests can be written to expect particular code numbers rather than particular text, + * enabling the message text to more easily be modified and the tests to run successfully in different locales. + *

+ * When a message is formatted, it will have this kind of form + * + *

+ * EL1004E: (pos 34): Type cannot be found 'String'
+ * 
+ * + * The prefix captures the code and the error kind, whilst the position is included if it is known. + * + * @author Andy Clement + * @since 3.0 + */ +public enum SpelMessage { + + TYPE_CONVERSION_ERROR(Kind.ERROR, 1001, "Type conversion problem, cannot convert from {0} to {1}"), // + CONSTRUCTOR_NOT_FOUND(Kind.ERROR, 1002, "Constructor call: No suitable constructor found on type {0} for arguments {1}"), // + CONSTRUCTOR_INVOCATION_PROBLEM(Kind.ERROR, 1003, "A problem occurred whilst attempting to construct an object of type ''{0}'' using arguments ''{1}''"), // + METHOD_NOT_FOUND(Kind.ERROR, 1004, "Method call: Method {0} cannot be found on {1} type"), // + TYPE_NOT_FOUND(Kind.ERROR, 1005, "Type cannot be found ''{0}''"), // + FUNCTION_NOT_DEFINED(Kind.ERROR, 1006, "The function ''{0}'' could not be found"), // + PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL(Kind.ERROR, 1007, "Field or property ''{0}'' cannot be found on null"), // + PROPERTY_OR_FIELD_NOT_READABLE(Kind.ERROR, 1008, "Field or property ''{0}'' cannot be found on object of type ''{1}''"), // + PROPERTY_OR_FIELD_NOT_WRITABLE_ON_NULL(Kind.ERROR, 1009, "Field or property ''{0}'' cannot be set on null"), // + PROPERTY_OR_FIELD_NOT_WRITABLE(Kind.ERROR, 1010, "Field or property ''{0}'' cannot be set on object of type ''{1}''"), // + METHOD_CALL_ON_NULL_OBJECT_NOT_ALLOWED(Kind.ERROR, 1011, "Method call: Attempted to call method {0} on null context object"), // + CANNOT_INDEX_INTO_NULL_VALUE(Kind.ERROR, 1012, "Cannot index into a null value"), + NOT_COMPARABLE(Kind.ERROR, 1013, "Cannot compare instances of {0} and {1}"), // + INCORRECT_NUMBER_OF_ARGUMENTS_TO_FUNCTION(Kind.ERROR, 1014, "Incorrect number of arguments for function, {0} supplied but function takes {1}"), // + INVALID_TYPE_FOR_SELECTION(Kind.ERROR, 1015, "Cannot perform selection on input data of type ''{0}''"), // + RESULT_OF_SELECTION_CRITERIA_IS_NOT_BOOLEAN(Kind.ERROR, 1016, "Result of selection criteria is not boolean"), // + BETWEEN_RIGHT_OPERAND_MUST_BE_TWO_ELEMENT_LIST(Kind.ERROR, 1017, "Right operand for the 'between' operator has to be a two-element list"), // + INVALID_PATTERN(Kind.ERROR, 1018, "Pattern is not valid ''{0}''"), // + PROJECTION_NOT_SUPPORTED_ON_TYPE(Kind.ERROR, 1019, "Projection is not supported on the type ''{0}''"), // + ARGLIST_SHOULD_NOT_BE_EVALUATED(Kind.ERROR, 1020, "The argument list of a lambda expression should never have getValue() called upon it"), // + EXCEPTION_DURING_PROPERTY_READ(Kind.ERROR, 1021, "A problem occurred whilst attempting to access the property ''{0}'': ''{1}''"), // + FUNCTION_REFERENCE_CANNOT_BE_INVOKED(Kind.ERROR, 1022, "The function ''{0}'' mapped to an object of type ''{1}'' which cannot be invoked"), // + EXCEPTION_DURING_FUNCTION_CALL(Kind.ERROR, 1023, "A problem occurred whilst attempting to invoke the function ''{0}'': ''{1}''"), // + ARRAY_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1024, "The array has ''{0}'' elements, index ''{1}'' is invalid"), // + COLLECTION_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1025, "The collection has ''{0}'' elements, index ''{1}'' is invalid"), // + STRING_INDEX_OUT_OF_BOUNDS(Kind.ERROR, 1026, "The string has ''{0}'' characters, index ''{1}'' is invalid"), // + INDEXING_NOT_SUPPORTED_FOR_TYPE(Kind.ERROR, 1027, "Indexing into type ''{0}'' is not supported"), // + INSTANCEOF_OPERATOR_NEEDS_CLASS_OPERAND(Kind.ERROR, 1028, "The operator 'instanceof' needs the right operand to be a class, not a ''{0}''"), // + EXCEPTION_DURING_METHOD_INVOCATION(Kind.ERROR, 1029, "A problem occurred when trying to execute method ''{0}'' on object of type ''{1}'': ''{2}''"), // + OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES(Kind.ERROR, 1030, "The operator ''{0}'' is not supported between objects of type ''{1}'' and ''{2}''"), // + PROBLEM_LOCATING_METHOD(Kind.ERROR, 1031, "Problem locating method {0} cannot on type {1}"), + SETVALUE_NOT_SUPPORTED( Kind.ERROR, 1032, "setValue(ExpressionState, Object) not supported for ''{0}''"), // + MULTIPLE_POSSIBLE_METHODS(Kind.ERROR, 1033, "Method call of ''{0}'' is ambiguous, supported type conversions allow multiple variants to match"), // + EXCEPTION_DURING_PROPERTY_WRITE(Kind.ERROR, 1034, "A problem occurred whilst attempting to set the property ''{0}'': {1}"), // + NOT_AN_INTEGER(Kind.ERROR, 1035, "The value ''{0}'' cannot be parsed as an int"), // + NOT_A_LONG(Kind.ERROR, 1036, "The value ''{0}'' cannot be parsed as a long"), // + INVALID_FIRST_OPERAND_FOR_MATCHES_OPERATOR(Kind.ERROR, 1037, "First operand to matches operator must be a string. ''{0}'' is not"), // + INVALID_SECOND_OPERAND_FOR_MATCHES_OPERATOR(Kind.ERROR, 1038, "Second operand to matches operator must be a string. ''{0}'' is not"), // + FUNCTION_MUST_BE_STATIC(Kind.ERROR, 1039, "Only static methods can be called via function references. The method ''{0}'' referred to by name ''{1}'' is not static."),// + NOT_A_REAL(Kind.ERROR, 1040, "The value ''{0}'' cannot be parsed as a double"), // + MORE_INPUT(Kind.ERROR,1041, "After parsing a valid expression, there is still more data in the expression: ''{0}''"), + RIGHT_OPERAND_PROBLEM(Kind.ERROR,1042, "Problem parsing right operand"), + NOT_EXPECTED_TOKEN(Kind.ERROR,1043,"Unexpected token. Expected ''{0}'' but was ''{1}''"), + OOD(Kind.ERROR,1044,"Unexpectedly ran out of input"), // + NON_TERMINATING_DOUBLE_QUOTED_STRING(Kind.ERROR,1045,"Cannot find terminating \" for string"),// + NON_TERMINATING_QUOTED_STRING(Kind.ERROR,1046,"Cannot find terminating ' for string"), // + MISSING_LEADING_ZERO_FOR_NUMBER(Kind.ERROR,1047,"A real number must be prefixed by zero, it cannot start with just ''.''"), // + REAL_CANNOT_BE_LONG(Kind.ERROR,1048,"Real number cannot be suffixed with a long (L or l) suffix"),// + UNEXPECTED_DATA_AFTER_DOT(Kind.ERROR,1049,"Unexpected data after ''.'': ''{0}''"),// + MISSING_CONSTRUCTOR_ARGS(Kind.ERROR,1050,"The arguments '(...)' for the constructor call are missing"),// + RUN_OUT_OF_ARGUMENTS(Kind.ERROR,1051,"Unexpected ran out of arguments"),// + UNABLE_TO_GROW_COLLECTION(Kind.ERROR,1052,"Unable to grow collection"),// + UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE(Kind.ERROR,1053,"Unable to grow collection: unable to determine list element type"),// + UNABLE_TO_CREATE_LIST_FOR_INDEXING(Kind.ERROR,1054,"Unable to dynamically create a List to replace a null value"),// + UNABLE_TO_CREATE_MAP_FOR_INDEXING(Kind.ERROR,1055,"Unable to dynamically create a Map to replace a null value"),// + UNABLE_TO_DYNAMICALLY_CREATE_OBJECT(Kind.ERROR,1056,"Unable to dynamically create instance of ''{0}'' to replace a null value"),// + NO_BEAN_RESOLVER_REGISTERED(Kind.ERROR,1057,"No bean resolver registered in the context to resolve access to bean ''{0}''"),// + EXCEPTION_DURING_BEAN_RESOLUTION(Kind.ERROR, 1058, "A problem occurred when trying to resolve bean ''{0}'':''{1}''"), // + INVALID_BEAN_REFERENCE(Kind.ERROR,1059,"@ can only be followed by an identifier or a quoted name"),// + TYPE_NAME_EXPECTED_FOR_ARRAY_CONSTRUCTION(Kind.ERROR, 1060, + "Expected the type of the new array to be specified as a String but found ''{0}''"), // + INCORRECT_ELEMENT_TYPE_FOR_ARRAY(Kind.ERROR, 1061, + "The array of type ''{0}'' cannot have an element of type ''{1}'' inserted"), // + MULTIDIM_ARRAY_INITIALIZER_NOT_SUPPORTED(Kind.ERROR, 1062, + "Using an initializer to build a multi-dimensional array is not currently supported"), // + MISSING_ARRAY_DIMENSION(Kind.ERROR, 1063, "A required array dimension has not been specified"), // + INITIALIZER_LENGTH_INCORRECT( + Kind.ERROR, 1064, "array initializer size does not match array dimensions"), // + ; + + private Kind kind; + private int code; + private String message; + + + private SpelMessage(Kind kind, int code, String message) { + this.kind = kind; + this.code = code; + this.message = message; + } + + + /** + * Produce a complete message including the prefix, the position (if known) and with the inserts applied to the + * message. + * + * @param pos the position, if less than zero it is ignored and not included in the message + * @param inserts the inserts to put into the formatted message + * @return a formatted message + */ + public String formatMessage(int pos, Object... inserts) { + StringBuilder formattedMessage = new StringBuilder(); + formattedMessage.append("EL").append(code); + switch (kind) { +// case WARNING: +// formattedMessage.append("W"); +// break; +// case INFO: +// formattedMessage.append("I"); +// break; + case ERROR: + formattedMessage.append("E"); + break; + } + formattedMessage.append(":"); + if (pos != -1) { + formattedMessage.append("(pos ").append(pos).append("): "); + } + formattedMessage.append(MessageFormat.format(message, inserts)); + return formattedMessage.toString(); + } + + + public static enum Kind { + INFO, WARNING, ERROR + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelNode.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelNode.java index d0decbac71..392807ae16 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelNode.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelNode.java @@ -1,95 +1,95 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel; - -import org.springframework.expression.EvaluationException; -import org.springframework.expression.TypedValue; - -/** - * Represents a node in the Ast for a parsed expression. - * - * @author Andy Clement - * @since 3.0 - */ -public interface SpelNode { - - /** - * Evaluate the expression node in the context of the supplied expression state and return the value. - * @param expressionState the current expression state (includes the context) - * @return the value of this node evaluated against the specified state - */ - Object getValue(ExpressionState expressionState) throws EvaluationException; - - /** - * Evaluate the expression node in the context of the supplied expression state and return the typed value. - * @param expressionState the current expression state (includes the context) - * @return the type value of this node evaluated against the specified state - */ - TypedValue getTypedValue(ExpressionState expressionState) throws EvaluationException; - - /** - * Determine if this expression node will support a setValue() call. - * - * @param expressionState the current expression state (includes the context) - * @return true if the expression node will allow setValue() - * @throws EvaluationException if something went wrong trying to determine if the node supports writing - */ - boolean isWritable(ExpressionState expressionState) throws EvaluationException; - - /** - * Evaluate the expression to a node and then set the new value on that node. For example, if the expression - * evaluates to a property reference then the property will be set to the new value. - * @param expressionState the current expression state (includes the context) - * @param newValue the new value - * @throws EvaluationException if any problem occurs evaluating the expression or setting the new value - */ - void setValue(ExpressionState expressionState, Object newValue) throws EvaluationException; - - /** - * @return the string form of this AST node - */ - String toStringAST(); - - /** - * @return the number of children under this node - */ - int getChildCount(); - - /** - * Helper method that returns a SpelNode rather than an Antlr Tree node. - * @return the child node cast to a SpelNode - */ - SpelNode getChild(int index); - - /** - * Determine the class of the object passed in, unless it is already a class object. - * @param o the object that the caller wants the class of - * @return the class of the object if it is not already a class object, or null if the object is null - */ - Class getObjectClass(Object obj); - - /** - * @return the start position of this Ast node in the expression string - */ - int getStartPosition(); - - /** - * @return the end position of this Ast node in the expression string - */ - int getEndPosition(); - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel; + +import org.springframework.expression.EvaluationException; +import org.springframework.expression.TypedValue; + +/** + * Represents a node in the Ast for a parsed expression. + * + * @author Andy Clement + * @since 3.0 + */ +public interface SpelNode { + + /** + * Evaluate the expression node in the context of the supplied expression state and return the value. + * @param expressionState the current expression state (includes the context) + * @return the value of this node evaluated against the specified state + */ + Object getValue(ExpressionState expressionState) throws EvaluationException; + + /** + * Evaluate the expression node in the context of the supplied expression state and return the typed value. + * @param expressionState the current expression state (includes the context) + * @return the type value of this node evaluated against the specified state + */ + TypedValue getTypedValue(ExpressionState expressionState) throws EvaluationException; + + /** + * Determine if this expression node will support a setValue() call. + * + * @param expressionState the current expression state (includes the context) + * @return true if the expression node will allow setValue() + * @throws EvaluationException if something went wrong trying to determine if the node supports writing + */ + boolean isWritable(ExpressionState expressionState) throws EvaluationException; + + /** + * Evaluate the expression to a node and then set the new value on that node. For example, if the expression + * evaluates to a property reference then the property will be set to the new value. + * @param expressionState the current expression state (includes the context) + * @param newValue the new value + * @throws EvaluationException if any problem occurs evaluating the expression or setting the new value + */ + void setValue(ExpressionState expressionState, Object newValue) throws EvaluationException; + + /** + * @return the string form of this AST node + */ + String toStringAST(); + + /** + * @return the number of children under this node + */ + int getChildCount(); + + /** + * Helper method that returns a SpelNode rather than an Antlr Tree node. + * @return the child node cast to a SpelNode + */ + SpelNode getChild(int index); + + /** + * Determine the class of the object passed in, unless it is already a class object. + * @param o the object that the caller wants the class of + * @return the class of the object if it is not already a class object, or null if the object is null + */ + Class getObjectClass(Object obj); + + /** + * @return the start position of this Ast node in the expression string + */ + int getStartPosition(); + + /** + * @return the end position of this Ast node in the expression string + */ + int getEndPosition(); + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelParseException.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelParseException.java index 03672eb7f4..3b8c14ff13 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelParseException.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelParseException.java @@ -1,107 +1,107 @@ -/* - * Copyright 2004-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.expression.spel; - -import org.springframework.expression.ParseException; - - -/** - * Root exception for Spring EL related exceptions. Rather than holding a hard coded string indicating the problem, it - * records a message key and the inserts for the message. See {@link SpelMessage} for the list of all possible messages - * that can occur. - * - * @author Andy Clement - * @since 3.0 - */ -public class SpelParseException extends ParseException { - - private SpelMessage message; - private Object[] inserts; - -// public SpelParseException(String expressionString, int position, Throwable cause, SpelMessages message, Object... inserts) { -// super(expressionString, position, message.formatMessage(position,inserts), cause); -// this.message = message; -// this.inserts = inserts; -// } - - public SpelParseException(String expressionString, int position, SpelMessage message, Object... inserts) { - super(expressionString, position, message.formatMessage(position,inserts)); - this.position = position; - this.message = message; - this.inserts = inserts; - } - - public SpelParseException(int position, SpelMessage message, Object... inserts) { - super(position, message.formatMessage(position,inserts)); - this.position = position; - this.message = message; - this.inserts = inserts; - } - - public SpelParseException(int position, Throwable cause, SpelMessage message, Object... inserts) { - super(position, message.formatMessage(position,inserts), cause); - this.position = position; - this.message = message; - this.inserts = inserts; - } - -// -// public SpelException(Throwable cause, SpelMessages message, Object... inserts) { -// super(cause); -// this.message = message; -// this.inserts = inserts; -// } -// -// public SpelException(int position, SpelMessages message, Object... inserts) { -// super((Throwable)null); -// this.position = position; -// this.message = message; -// this.inserts = inserts; -// } -// -// public SpelException(SpelMessages message, Object... inserts) { -// super((Throwable)null); -// this.message = message; -// this.inserts = inserts; -// } - - - /** - * @return a formatted message with inserts applied - */ - @Override - public String getMessage() { - if (message != null) - return message.formatMessage(position, inserts); - else - return super.getMessage(); - } - - /** - * @return the message code - */ - public SpelMessage getMessageCode() { - return this.message; - } - - /** - * @return the message inserts - */ - public Object[] getInserts() { - return inserts; - } - -} +/* + * Copyright 2004-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel; + +import org.springframework.expression.ParseException; + + +/** + * Root exception for Spring EL related exceptions. Rather than holding a hard coded string indicating the problem, it + * records a message key and the inserts for the message. See {@link SpelMessage} for the list of all possible messages + * that can occur. + * + * @author Andy Clement + * @since 3.0 + */ +public class SpelParseException extends ParseException { + + private SpelMessage message; + private Object[] inserts; + +// public SpelParseException(String expressionString, int position, Throwable cause, SpelMessages message, Object... inserts) { +// super(expressionString, position, message.formatMessage(position,inserts), cause); +// this.message = message; +// this.inserts = inserts; +// } + + public SpelParseException(String expressionString, int position, SpelMessage message, Object... inserts) { + super(expressionString, position, message.formatMessage(position,inserts)); + this.position = position; + this.message = message; + this.inserts = inserts; + } + + public SpelParseException(int position, SpelMessage message, Object... inserts) { + super(position, message.formatMessage(position,inserts)); + this.position = position; + this.message = message; + this.inserts = inserts; + } + + public SpelParseException(int position, Throwable cause, SpelMessage message, Object... inserts) { + super(position, message.formatMessage(position,inserts), cause); + this.position = position; + this.message = message; + this.inserts = inserts; + } + +// +// public SpelException(Throwable cause, SpelMessages message, Object... inserts) { +// super(cause); +// this.message = message; +// this.inserts = inserts; +// } +// +// public SpelException(int position, SpelMessages message, Object... inserts) { +// super((Throwable)null); +// this.position = position; +// this.message = message; +// this.inserts = inserts; +// } +// +// public SpelException(SpelMessages message, Object... inserts) { +// super((Throwable)null); +// this.message = message; +// this.inserts = inserts; +// } + + + /** + * @return a formatted message with inserts applied + */ + @Override + public String getMessage() { + if (message != null) + return message.formatMessage(position, inserts); + else + return super.getMessage(); + } + + /** + * @return the message code + */ + public SpelMessage getMessageCode() { + return this.message; + } + + /** + * @return the message inserts + */ + public Object[] getInserts() { + return inserts; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java index 5787b7e549..c9e7bad2f1 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java @@ -1,47 +1,47 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel; - -/** - * Configuration object for the SpEL expression parser. - * - * @author Juergen Hoeller - * @since 3.0 - * @see org.springframework.expression.spel.standard.SpelExpressionParser#SpelExpressionParser(SpelParserConfiguration) - */ -public class SpelParserConfiguration { - - private final boolean autoGrowNullReferences; - - private final boolean autoGrowCollections; - - - public SpelParserConfiguration(boolean autoGrowNullReferences, boolean autoGrowCollections) { - this.autoGrowNullReferences = autoGrowNullReferences; - this.autoGrowCollections = autoGrowCollections; - } - - - public boolean isAutoGrowNullReferences() { - return this.autoGrowNullReferences; - } - - public boolean isAutoGrowCollections() { - return this.autoGrowCollections; - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel; + +/** + * Configuration object for the SpEL expression parser. + * + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.expression.spel.standard.SpelExpressionParser#SpelExpressionParser(SpelParserConfiguration) + */ +public class SpelParserConfiguration { + + private final boolean autoGrowNullReferences; + + private final boolean autoGrowCollections; + + + public SpelParserConfiguration(boolean autoGrowNullReferences, boolean autoGrowCollections) { + this.autoGrowNullReferences = autoGrowNullReferences; + this.autoGrowCollections = autoGrowCollections; + } + + + public boolean isAutoGrowNullReferences() { + return this.autoGrowNullReferences; + } + + public boolean isAutoGrowCollections() { + return this.autoGrowCollections; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/AstUtils.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/AstUtils.java index ff998fef13..2d0aa72611 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/AstUtils.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/AstUtils.java @@ -1,72 +1,72 @@ -/* - * Copyright 2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel.ast; - -import java.util.ArrayList; -import java.util.List; - -import org.springframework.expression.PropertyAccessor; -import org.springframework.expression.spel.ExpressionState; - -/** - * Utilities methods for use in the Ast classes. - * - * @author Andy Clement - * @since 3.0.2 - */ -public class AstUtils { - - /** - * Determines the set of property resolvers that should be used to try and access a property on the specified target - * type. The resolvers are considered to be in an ordered list, however in the returned list any that are exact - * matches for the input target type (as opposed to 'general' resolvers that could work for any type) are placed at - * the start of the list. In addition, there are specific resolvers that exactly name the class in question and - * resolvers that name a specific class but it is a supertype of the class we have. These are put at the end of the - * specific resolvers set and will be tried after exactly matching accessors but before generic accessors. - * - * @param targetType the type upon which property access is being attempted - * @return a list of resolvers that should be tried in order to access the property - */ - public static List getPropertyAccessorsToTry(Class targetType, ExpressionState state) { - List specificAccessors = new ArrayList(); - List generalAccessors = new ArrayList(); - for (PropertyAccessor resolver : state.getPropertyAccessors()) { - Class[] targets = resolver.getSpecificTargetClasses(); - if (targets == null) { // generic resolver that says it can be used for any type - generalAccessors.add(resolver); - } - else { - if (targetType != null) { - int pos = 0; - for (Class clazz : targets) { - if (clazz == targetType) { // put exact matches on the front to be tried first? - specificAccessors.add(pos++, resolver); - } - else if (clazz.isAssignableFrom(targetType)) { // put supertype matches at the end of the - // specificAccessor list - generalAccessors.add(resolver); - } - } - } - } - } - List resolvers = new ArrayList(); - resolvers.addAll(specificAccessors); - resolvers.addAll(generalAccessors); - return resolvers; - } -} +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel.ast; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.spel.ExpressionState; + +/** + * Utilities methods for use in the Ast classes. + * + * @author Andy Clement + * @since 3.0.2 + */ +public class AstUtils { + + /** + * Determines the set of property resolvers that should be used to try and access a property on the specified target + * type. The resolvers are considered to be in an ordered list, however in the returned list any that are exact + * matches for the input target type (as opposed to 'general' resolvers that could work for any type) are placed at + * the start of the list. In addition, there are specific resolvers that exactly name the class in question and + * resolvers that name a specific class but it is a supertype of the class we have. These are put at the end of the + * specific resolvers set and will be tried after exactly matching accessors but before generic accessors. + * + * @param targetType the type upon which property access is being attempted + * @return a list of resolvers that should be tried in order to access the property + */ + public static List getPropertyAccessorsToTry(Class targetType, ExpressionState state) { + List specificAccessors = new ArrayList(); + List generalAccessors = new ArrayList(); + for (PropertyAccessor resolver : state.getPropertyAccessors()) { + Class[] targets = resolver.getSpecificTargetClasses(); + if (targets == null) { // generic resolver that says it can be used for any type + generalAccessors.add(resolver); + } + else { + if (targetType != null) { + int pos = 0; + for (Class clazz : targets) { + if (clazz == targetType) { // put exact matches on the front to be tried first? + specificAccessors.add(pos++, resolver); + } + else if (clazz.isAssignableFrom(targetType)) { // put supertype matches at the end of the + // specificAccessor list + generalAccessors.add(resolver); + } + } + } + } + } + List resolvers = new ArrayList(); + resolvers.addAll(specificAccessors); + resolvers.addAll(generalAccessors); + return resolvers; + } +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/FormatHelper.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/FormatHelper.java index f0af0bbbb1..3983c207a2 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/FormatHelper.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/FormatHelper.java @@ -1,84 +1,84 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel.ast; - -import java.util.List; - -import org.springframework.core.convert.TypeDescriptor; - -/** - * Utility methods (formatters, etc) used during parsing and evaluation. - * - * @author Andy Clement - */ -public class FormatHelper { - - /** - * Produce a nice string for a given method name with specified arguments. - * @param name the name of the method - * @param argumentTypes the types of the arguments to the method - * @return nicely formatted string, eg. foo(String,int) - */ - public static String formatMethodForMessage(String name, List argumentTypes) { - StringBuilder sb = new StringBuilder(); - sb.append(name); - sb.append("("); - for (int i = 0; i < argumentTypes.size(); i++) { - if (i > 0) { - sb.append(","); - } - TypeDescriptor typeDescriptor = argumentTypes.get(i); - if (typeDescriptor != null) { - sb.append(formatClassNameForMessage(typeDescriptor.getType())); - } - else { - sb.append(formatClassNameForMessage(null)); - } - } - sb.append(")"); - return sb.toString(); - } - - /** - * Produce a nice string for a given class object. - * For example, a string array will have the formatted name "java.lang.String[]". - * @param clazz The class whose name is to be formatted - * @return a formatted string suitable for message inclusion - */ - public static String formatClassNameForMessage(Class clazz) { - if (clazz == null) { - return "null"; - } - StringBuilder fmtd = new StringBuilder(); - if (clazz.isArray()) { - int dims = 1; - Class baseClass = clazz.getComponentType(); - while (baseClass.isArray()) { - baseClass = baseClass.getComponentType(); - dims++; - } - fmtd.append(baseClass.getName()); - for (int i = 0; i < dims; i++) { - fmtd.append("[]"); - } - } else { - fmtd.append(clazz.getName()); - } - return fmtd.toString(); - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel.ast; + +import java.util.List; + +import org.springframework.core.convert.TypeDescriptor; + +/** + * Utility methods (formatters, etc) used during parsing and evaluation. + * + * @author Andy Clement + */ +public class FormatHelper { + + /** + * Produce a nice string for a given method name with specified arguments. + * @param name the name of the method + * @param argumentTypes the types of the arguments to the method + * @return nicely formatted string, eg. foo(String,int) + */ + public static String formatMethodForMessage(String name, List argumentTypes) { + StringBuilder sb = new StringBuilder(); + sb.append(name); + sb.append("("); + for (int i = 0; i < argumentTypes.size(); i++) { + if (i > 0) { + sb.append(","); + } + TypeDescriptor typeDescriptor = argumentTypes.get(i); + if (typeDescriptor != null) { + sb.append(formatClassNameForMessage(typeDescriptor.getType())); + } + else { + sb.append(formatClassNameForMessage(null)); + } + } + sb.append(")"); + return sb.toString(); + } + + /** + * Produce a nice string for a given class object. + * For example, a string array will have the formatted name "java.lang.String[]". + * @param clazz The class whose name is to be formatted + * @return a formatted string suitable for message inclusion + */ + public static String formatClassNameForMessage(Class clazz) { + if (clazz == null) { + return "null"; + } + StringBuilder fmtd = new StringBuilder(); + if (clazz.isArray()) { + int dims = 1; + Class baseClass = clazz.getComponentType(); + while (baseClass.isArray()) { + baseClass = baseClass.getComponentType(); + dims++; + } + fmtd.append(baseClass.getName()); + for (int i = 0; i < dims; i++) { + fmtd.append("[]"); + } + } else { + fmtd.append(clazz.getName()); + } + return fmtd.toString(); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/InlineList.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/InlineList.java index a5a818a3b2..ad7bf42a84 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/InlineList.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/InlineList.java @@ -1,120 +1,120 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.expression.spel.ast; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.springframework.expression.EvaluationException; -import org.springframework.expression.TypedValue; -import org.springframework.expression.spel.ExpressionState; -import org.springframework.expression.spel.SpelNode; - -/** - * Represent a list in an expression, e.g. '{1,2,3}' - * - * @author Andy Clement - * @since 3.0.4 - */ -public class InlineList extends SpelNodeImpl { - - // if the list is purely literals, it is a constant value and can be computed and cached - TypedValue constant = null; // TODO must be immutable list - - public InlineList(int pos, SpelNodeImpl... args) { - super(pos, args); - checkIfConstant(); - } - - /** - * If all the components of the list are constants, or lists that themselves contain constants, then a constant list - * can be built to represent this node. This will speed up later getValue calls and reduce the amount of garbage - * created. - */ - private void checkIfConstant() { - boolean isConstant = true; - for (int c = 0, max = getChildCount(); c < max; c++) { - SpelNode child = getChild(c); - if (!(child instanceof Literal)) { - if (child instanceof InlineList) { - InlineList inlineList = (InlineList) child; - if (!inlineList.isConstant()) { - isConstant = false; - } - } else { - isConstant = false; - } - } - } - if (isConstant) { - List constantList = new ArrayList(); - int childcount = getChildCount(); - for (int c = 0; c < childcount; c++) { - SpelNode child = getChild(c); - if ((child instanceof Literal)) { - constantList.add(((Literal) child).getLiteralValue().getValue()); - } else if (child instanceof InlineList) { - constantList.add(((InlineList) child).getConstantValue()); - } - } - this.constant = new TypedValue(Collections.unmodifiableList(constantList)); - } - } - - @Override - public TypedValue getValueInternal(ExpressionState expressionState) throws EvaluationException { - if (constant != null) { - return constant; - } else { - List returnValue = new ArrayList(); - int childcount = getChildCount(); - for (int c = 0; c < childcount; c++) { - returnValue.add(getChild(c).getValue(expressionState)); - } - return new TypedValue(returnValue); - } - } - - @Override - public String toStringAST() { - StringBuilder s = new StringBuilder(); - // string ast matches input string, not the 'toString()' of the resultant collection, which would use [] - s.append('{'); - int count = getChildCount(); - for (int c = 0; c < count; c++) { - if (c > 0) { - s.append(','); - } - s.append(getChild(c).toStringAST()); - } - s.append('}'); - return s.toString(); - } - - /** - * @return whether this list is a constant value - */ - public boolean isConstant() { - return constant != null; - } - - @SuppressWarnings("unchecked") - private List getConstantValue() { - return (List) constant.getValue(); - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.springframework.expression.EvaluationException; +import org.springframework.expression.TypedValue; +import org.springframework.expression.spel.ExpressionState; +import org.springframework.expression.spel.SpelNode; + +/** + * Represent a list in an expression, e.g. '{1,2,3}' + * + * @author Andy Clement + * @since 3.0.4 + */ +public class InlineList extends SpelNodeImpl { + + // if the list is purely literals, it is a constant value and can be computed and cached + TypedValue constant = null; // TODO must be immutable list + + public InlineList(int pos, SpelNodeImpl... args) { + super(pos, args); + checkIfConstant(); + } + + /** + * If all the components of the list are constants, or lists that themselves contain constants, then a constant list + * can be built to represent this node. This will speed up later getValue calls and reduce the amount of garbage + * created. + */ + private void checkIfConstant() { + boolean isConstant = true; + for (int c = 0, max = getChildCount(); c < max; c++) { + SpelNode child = getChild(c); + if (!(child instanceof Literal)) { + if (child instanceof InlineList) { + InlineList inlineList = (InlineList) child; + if (!inlineList.isConstant()) { + isConstant = false; + } + } else { + isConstant = false; + } + } + } + if (isConstant) { + List constantList = new ArrayList(); + int childcount = getChildCount(); + for (int c = 0; c < childcount; c++) { + SpelNode child = getChild(c); + if ((child instanceof Literal)) { + constantList.add(((Literal) child).getLiteralValue().getValue()); + } else if (child instanceof InlineList) { + constantList.add(((InlineList) child).getConstantValue()); + } + } + this.constant = new TypedValue(Collections.unmodifiableList(constantList)); + } + } + + @Override + public TypedValue getValueInternal(ExpressionState expressionState) throws EvaluationException { + if (constant != null) { + return constant; + } else { + List returnValue = new ArrayList(); + int childcount = getChildCount(); + for (int c = 0; c < childcount; c++) { + returnValue.add(getChild(c).getValue(expressionState)); + } + return new TypedValue(returnValue); + } + } + + @Override + public String toStringAST() { + StringBuilder s = new StringBuilder(); + // string ast matches input string, not the 'toString()' of the resultant collection, which would use [] + s.append('{'); + int count = getChildCount(); + for (int c = 0; c < count; c++) { + if (c > 0) { + s.append(','); + } + s.append(getChild(c).toStringAST()); + } + s.append('}'); + return s.toString(); + } + + /** + * @return whether this list is a constant value + */ + public boolean isConstant() { + return constant != null; + } + + @SuppressWarnings("unchecked") + private List getConstantValue() { + return (List) constant.getValue(); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/IntLiteral.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/IntLiteral.java index 51ca0c385f..15dc80d2db 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/IntLiteral.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/IntLiteral.java @@ -1,40 +1,40 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.expression.spel.ast; - -import org.springframework.expression.TypedValue; - -/** - * Expression language AST node that represents an integer literal. - * - * @author Andy Clement - * @since 3.0 - */ -public class IntLiteral extends Literal { - - private final TypedValue value; - - IntLiteral(String payload, int pos, int value) { - super(payload, pos); - this.value = new TypedValue(value); - } - - @Override - public TypedValue getLiteralValue() { - return this.value; - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +import org.springframework.expression.TypedValue; + +/** + * Expression language AST node that represents an integer literal. + * + * @author Andy Clement + * @since 3.0 + */ +public class IntLiteral extends Literal { + + private final TypedValue value; + + IntLiteral(String payload, int pos, int value) { + super(payload, pos); + this.value = new TypedValue(value); + } + + @Override + public TypedValue getLiteralValue() { + return this.value; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/TypeCode.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/TypeCode.java index 124a74752d..aeb7ca1cc6 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/TypeCode.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/TypeCode.java @@ -1,61 +1,61 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.expression.spel.ast; - -/** - * Captures primitive types and their corresponding class objects, plus one special entry that represents all reference - * (non-primitive) types. - * - * @author Andy Clement - */ -public enum TypeCode { - - OBJECT(Object.class), BOOLEAN(Boolean.TYPE), BYTE(Byte.TYPE), CHAR(Character.TYPE), // - SHORT(Short.TYPE), INT(Integer.TYPE), LONG(Long.TYPE), FLOAT(Float.TYPE), DOUBLE(Double.TYPE); - - private Class type; - - TypeCode(Class type) { - this.type = type; - } - - public Class getType() { - return type; - } - - public static TypeCode forName(String name) { - String searchingFor = name.toUpperCase(); - TypeCode[] tcs = values(); - for (int i = 1; i < tcs.length; i++) { - if (tcs[i].name().equals(searchingFor)) { - return tcs[i]; - } - } - return TypeCode.OBJECT; - } - - public static TypeCode forClass(Class c) { - TypeCode[] allValues = TypeCode.values(); - for (int i = 0; i < allValues.length; i++) { - TypeCode typeCode = allValues[i]; - if (c == typeCode.getType()) { - return typeCode; - } - } - return OBJECT; - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.ast; + +/** + * Captures primitive types and their corresponding class objects, plus one special entry that represents all reference + * (non-primitive) types. + * + * @author Andy Clement + */ +public enum TypeCode { + + OBJECT(Object.class), BOOLEAN(Boolean.TYPE), BYTE(Byte.TYPE), CHAR(Character.TYPE), // + SHORT(Short.TYPE), INT(Integer.TYPE), LONG(Long.TYPE), FLOAT(Float.TYPE), DOUBLE(Double.TYPE); + + private Class type; + + TypeCode(Class type) { + this.type = type; + } + + public Class getType() { + return type; + } + + public static TypeCode forName(String name) { + String searchingFor = name.toUpperCase(); + TypeCode[] tcs = values(); + for (int i = 1; i < tcs.length; i++) { + if (tcs[i].name().equals(searchingFor)) { + return tcs[i]; + } + } + return TypeCode.OBJECT; + } + + public static TypeCode forClass(Class c) { + TypeCode[] allValues = TypeCode.values(); + for (int i = 0; i < allValues.length; i++) { + TypeCode typeCode = allValues[i]; + if (c == typeCode.getType()) { + return typeCode; + } + } + return OBJECT; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g b/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g index fd53c878d8..82a5f4a8b9 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/generated/SpringExpressions.g @@ -1,268 +1,268 @@ -grammar SpringExpressions; - -options { - language = Java; - output=AST; - k=2; -} - -tokens { - INTEGER_LITERAL; - EXPRESSION; - QUALIFIED_IDENTIFIER; - PROPERTY_OR_FIELD; - INDEXER; - CONSTRUCTOR; - HOLDER; - NAMED_ARGUMENT; - FUNCTIONREF; - TYPEREF; - VARIABLEREF; - METHOD; - ADD; - SUBTRACT; - NUMBER; -} - -// applies only to the parser: -@header {package org.springframework.expression.spel.generated;} - -// applies only to the lexer: -@lexer::header {package org.springframework.expression.spel.generated;} - -@members { - // For collecting info whilst processing rules that can be used in messages - protected Stack paraphrase = new Stack(); -} - -@rulecatch { - catch(RecognitionException e) { - reportError(e); - throw e; - } -} - -expr: expression EOF!; - -expression : - logicalOrExpression - ( (ASSIGN^ logicalOrExpression) - | (DEFAULT^ logicalOrExpression) - | (QMARK^ expression COLON! expression))?; - -parenExpr : LPAREN! expression RPAREN!; - -logicalOrExpression -: logicalAndExpression (OR^ logicalAndExpression)*; - -logicalAndExpression -: relationalExpression (AND^ relationalExpression)*; - -relationalExpression : sumExpression (relationalOperator^ sumExpression)?; - -sumExpression - : productExpression ( (PLUS^ | MINUS^) productExpression)*; - -productExpression - : powerExpr ((STAR^ | DIV^| MOD^) powerExpr)* ; - -powerExpr : unaryExpression (POWER^ unaryExpression)? ; - -unaryExpression - : (PLUS^ | MINUS^ | BANG^) unaryExpression - | primaryExpression ; - -primaryExpression - : startNode (node)? -> ^(EXPRESSION startNode (node)?); - -startNode - : - parenExpr - | methodOrProperty - | functionOrVar - | indexer - | literal - | type - | constructor - | projection - | selection - | firstSelection - | lastSelection - ; - -node - : ((DOT dottedNode) | nonDottedNode)+; - -nonDottedNode - : indexer; - -dottedNode - : - ((methodOrProperty - | functionOrVar - | projection - | selection - | firstSelection - | lastSelection - )) - ; - -functionOrVar - : (POUND ID LPAREN) => function - | var - ; - -function : POUND id=ID methodArgs -> ^(FUNCTIONREF[$id] methodArgs); - -var : POUND id=ID -> ^(VARIABLEREF[$id]); - - -methodOrProperty - : (ID LPAREN) => id=ID methodArgs -> ^(METHOD[$id] methodArgs) - | property - ; - -// may have to preserve these commas to make it easier to offer suggestions in the right place -// mod at 9th feb 19:13 - added the second 'COMMA?' to allow for code completion "foo(A," -// TODO need to preserve commas and then check for badly formed call later (optimizing tree walk) to disallow "foo(a,b,c,)" -methodArgs : LPAREN! (argument (COMMA! argument)* (COMMA!)?)? RPAREN!; - -// If we match ID then create a node called PROPERTY_OR_FIELD and copy the id info into it. -// this means the propertyOrField.text is what id.text would have been, rather than having to -// access id as a child of the new node. -property: id=ID -> ^(PROPERTY_OR_FIELD[$id]); - - -indexer: LBRACKET r1=argument (COMMA r2=argument)* RBRACKET -> ^(INDEXER $r1 ($r2)*); - -// argument; - // TODO make expression conditional with ? if want completion for when the RCURLY is missing -projection: PROJECT^ expression RBRACKET!; - -selection: SELECT^ expression RBRACKET!; - -firstSelection: SELECT_FIRST^ expression RBRACKET!; - -lastSelection: SELECT_LAST^ expression RBRACKET!; - -// TODO cope with array types -type: TYPE qualifiedId RPAREN -> ^(TYPEREF qualifiedId); -//type: TYPE tn=qualifiedId (LBRACKET RBRACKET)? (COMMA qid=qualifiedId)? RPAREN - - -constructor - : ('new' qualifiedId LPAREN) => 'new' qualifiedId ctorArgs -> ^(CONSTRUCTOR qualifiedId ctorArgs) - ; - -ctorArgs - : LPAREN! (namedArgument (COMMA! namedArgument)*)? RPAREN!; - -argument : expression; - -namedArgument - : (ID ASSIGN) => id=ID ASSIGN expression - -> ^(NAMED_ARGUMENT[$id] expression) - | argument ; - -qualifiedId : ID (DOT ID)* -> ^(QUALIFIED_IDENTIFIER ID*); - -contextName : ID (DIV ID)* -> ^(QUALIFIED_IDENTIFIER ID*); - -literal - : INTEGER_LITERAL - | STRING_LITERAL - | DQ_STRING_LITERAL - | boolLiteral - | NULL_LITERAL - | HEXADECIMAL_INTEGER_LITERAL - | REAL_LITERAL - ; - -boolLiteral: TRUE | FALSE; - -INTEGER_LITERAL - : (DECIMAL_DIGIT)+ (INTEGER_TYPE_SUFFIX)?; - -HEXADECIMAL_INTEGER_LITERAL : ('0x' | '0X') (HEX_DIGIT)+ (INTEGER_TYPE_SUFFIX)?; - -relationalOperator - : EQUAL - | NOT_EQUAL - | LESS_THAN - | LESS_THAN_OR_EQUAL - | GREATER_THAN - | GREATER_THAN_OR_EQUAL - | INSTANCEOF - | BETWEEN - | MATCHES - ; - -ASSIGN: '='; -EQUAL: '=='; -NOT_EQUAL: '!='; -LESS_THAN: '<'; -LESS_THAN_OR_EQUAL: '<='; -GREATER_THAN: '>'; -GREATER_THAN_OR_EQUAL: '>='; -INSTANCEOF: 'instanceof'; -BETWEEN:'between'; -MATCHES:'matches'; -NULL_LITERAL: 'null'; - -SEMI: ';'; -DOT: '.'; -COMMA: ','; -LPAREN: '('; -RPAREN: ')'; -LCURLY: '{'; -RCURLY: '}'; -LBRACKET: '['; -RBRACKET: ']'; -PIPE: '|'; - -AND: 'and'; -OR: 'or'; -FALSE: 'false'; -TRUE: 'true'; - -PLUS: '+'; -MINUS: '-'; -DIV: '/'; -STAR: '*'; -MOD: '%'; -POWER: '^'; -BANG: '!'; -POUND: '#'; -QMARK: '?'; -DEFAULT: '??'; -PROJECT: '!['; -SELECT: '?['; -SELECT_FIRST: '^['; -SELECT_LAST: '$['; -TYPE: 'T('; - -STRING_LITERAL: '\''! (APOS|~'\'')* '\''!; -DQ_STRING_LITERAL: '"'! (~'"')* '"'!; -ID: ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|DOT_ESCAPED)*; -DOT_ESCAPED: '\\.'; -WS: ( ' ' | '\t' | '\n' |'\r')+ { $channel=HIDDEN; } ; -DOLLAR: '$'; -AT: '@'; -UPTO: '..'; -COLON: ':'; - - -REAL_LITERAL : - ('.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) | - ((DECIMAL_DIGIT)+ '.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) | - ((DECIMAL_DIGIT)+ (EXPONENT_PART) (REAL_TYPE_SUFFIX)?) | - ((DECIMAL_DIGIT)+ (REAL_TYPE_SUFFIX)); - -fragment APOS : '\''! '\''; -fragment DECIMAL_DIGIT : '0'..'9' ; -fragment INTEGER_TYPE_SUFFIX : ( 'L' | 'l' ); -fragment HEX_DIGIT : '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'A'|'B'|'C'|'D'|'E'|'F'|'a'|'b'|'c'|'d'|'e'|'f'; - -fragment EXPONENT_PART : 'e' (SIGN)* (DECIMAL_DIGIT)+ | 'E' (SIGN)* (DECIMAL_DIGIT)+ ; -fragment SIGN : '+' | '-' ; -fragment REAL_TYPE_SUFFIX : 'F' | 'f' | 'D' | 'd'; +grammar SpringExpressions; + +options { + language = Java; + output=AST; + k=2; +} + +tokens { + INTEGER_LITERAL; + EXPRESSION; + QUALIFIED_IDENTIFIER; + PROPERTY_OR_FIELD; + INDEXER; + CONSTRUCTOR; + HOLDER; + NAMED_ARGUMENT; + FUNCTIONREF; + TYPEREF; + VARIABLEREF; + METHOD; + ADD; + SUBTRACT; + NUMBER; +} + +// applies only to the parser: +@header {package org.springframework.expression.spel.generated;} + +// applies only to the lexer: +@lexer::header {package org.springframework.expression.spel.generated;} + +@members { + // For collecting info whilst processing rules that can be used in messages + protected Stack paraphrase = new Stack(); +} + +@rulecatch { + catch(RecognitionException e) { + reportError(e); + throw e; + } +} + +expr: expression EOF!; + +expression : + logicalOrExpression + ( (ASSIGN^ logicalOrExpression) + | (DEFAULT^ logicalOrExpression) + | (QMARK^ expression COLON! expression))?; + +parenExpr : LPAREN! expression RPAREN!; + +logicalOrExpression +: logicalAndExpression (OR^ logicalAndExpression)*; + +logicalAndExpression +: relationalExpression (AND^ relationalExpression)*; + +relationalExpression : sumExpression (relationalOperator^ sumExpression)?; + +sumExpression + : productExpression ( (PLUS^ | MINUS^) productExpression)*; + +productExpression + : powerExpr ((STAR^ | DIV^| MOD^) powerExpr)* ; + +powerExpr : unaryExpression (POWER^ unaryExpression)? ; + +unaryExpression + : (PLUS^ | MINUS^ | BANG^) unaryExpression + | primaryExpression ; + +primaryExpression + : startNode (node)? -> ^(EXPRESSION startNode (node)?); + +startNode + : + parenExpr + | methodOrProperty + | functionOrVar + | indexer + | literal + | type + | constructor + | projection + | selection + | firstSelection + | lastSelection + ; + +node + : ((DOT dottedNode) | nonDottedNode)+; + +nonDottedNode + : indexer; + +dottedNode + : + ((methodOrProperty + | functionOrVar + | projection + | selection + | firstSelection + | lastSelection + )) + ; + +functionOrVar + : (POUND ID LPAREN) => function + | var + ; + +function : POUND id=ID methodArgs -> ^(FUNCTIONREF[$id] methodArgs); + +var : POUND id=ID -> ^(VARIABLEREF[$id]); + + +methodOrProperty + : (ID LPAREN) => id=ID methodArgs -> ^(METHOD[$id] methodArgs) + | property + ; + +// may have to preserve these commas to make it easier to offer suggestions in the right place +// mod at 9th feb 19:13 - added the second 'COMMA?' to allow for code completion "foo(A," +// TODO need to preserve commas and then check for badly formed call later (optimizing tree walk) to disallow "foo(a,b,c,)" +methodArgs : LPAREN! (argument (COMMA! argument)* (COMMA!)?)? RPAREN!; + +// If we match ID then create a node called PROPERTY_OR_FIELD and copy the id info into it. +// this means the propertyOrField.text is what id.text would have been, rather than having to +// access id as a child of the new node. +property: id=ID -> ^(PROPERTY_OR_FIELD[$id]); + + +indexer: LBRACKET r1=argument (COMMA r2=argument)* RBRACKET -> ^(INDEXER $r1 ($r2)*); + +// argument; + // TODO make expression conditional with ? if want completion for when the RCURLY is missing +projection: PROJECT^ expression RBRACKET!; + +selection: SELECT^ expression RBRACKET!; + +firstSelection: SELECT_FIRST^ expression RBRACKET!; + +lastSelection: SELECT_LAST^ expression RBRACKET!; + +// TODO cope with array types +type: TYPE qualifiedId RPAREN -> ^(TYPEREF qualifiedId); +//type: TYPE tn=qualifiedId (LBRACKET RBRACKET)? (COMMA qid=qualifiedId)? RPAREN + + +constructor + : ('new' qualifiedId LPAREN) => 'new' qualifiedId ctorArgs -> ^(CONSTRUCTOR qualifiedId ctorArgs) + ; + +ctorArgs + : LPAREN! (namedArgument (COMMA! namedArgument)*)? RPAREN!; + +argument : expression; + +namedArgument + : (ID ASSIGN) => id=ID ASSIGN expression + -> ^(NAMED_ARGUMENT[$id] expression) + | argument ; + +qualifiedId : ID (DOT ID)* -> ^(QUALIFIED_IDENTIFIER ID*); + +contextName : ID (DIV ID)* -> ^(QUALIFIED_IDENTIFIER ID*); + +literal + : INTEGER_LITERAL + | STRING_LITERAL + | DQ_STRING_LITERAL + | boolLiteral + | NULL_LITERAL + | HEXADECIMAL_INTEGER_LITERAL + | REAL_LITERAL + ; + +boolLiteral: TRUE | FALSE; + +INTEGER_LITERAL + : (DECIMAL_DIGIT)+ (INTEGER_TYPE_SUFFIX)?; + +HEXADECIMAL_INTEGER_LITERAL : ('0x' | '0X') (HEX_DIGIT)+ (INTEGER_TYPE_SUFFIX)?; + +relationalOperator + : EQUAL + | NOT_EQUAL + | LESS_THAN + | LESS_THAN_OR_EQUAL + | GREATER_THAN + | GREATER_THAN_OR_EQUAL + | INSTANCEOF + | BETWEEN + | MATCHES + ; + +ASSIGN: '='; +EQUAL: '=='; +NOT_EQUAL: '!='; +LESS_THAN: '<'; +LESS_THAN_OR_EQUAL: '<='; +GREATER_THAN: '>'; +GREATER_THAN_OR_EQUAL: '>='; +INSTANCEOF: 'instanceof'; +BETWEEN:'between'; +MATCHES:'matches'; +NULL_LITERAL: 'null'; + +SEMI: ';'; +DOT: '.'; +COMMA: ','; +LPAREN: '('; +RPAREN: ')'; +LCURLY: '{'; +RCURLY: '}'; +LBRACKET: '['; +RBRACKET: ']'; +PIPE: '|'; + +AND: 'and'; +OR: 'or'; +FALSE: 'false'; +TRUE: 'true'; + +PLUS: '+'; +MINUS: '-'; +DIV: '/'; +STAR: '*'; +MOD: '%'; +POWER: '^'; +BANG: '!'; +POUND: '#'; +QMARK: '?'; +DEFAULT: '??'; +PROJECT: '!['; +SELECT: '?['; +SELECT_FIRST: '^['; +SELECT_LAST: '$['; +TYPE: 'T('; + +STRING_LITERAL: '\''! (APOS|~'\'')* '\''!; +DQ_STRING_LITERAL: '"'! (~'"')* '"'!; +ID: ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|DOT_ESCAPED)*; +DOT_ESCAPED: '\\.'; +WS: ( ' ' | '\t' | '\n' |'\r')+ { $channel=HIDDEN; } ; +DOLLAR: '$'; +AT: '@'; +UPTO: '..'; +COLON: ':'; + + +REAL_LITERAL : + ('.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) | + ((DECIMAL_DIGIT)+ '.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) | + ((DECIMAL_DIGIT)+ (EXPONENT_PART) (REAL_TYPE_SUFFIX)?) | + ((DECIMAL_DIGIT)+ (REAL_TYPE_SUFFIX)); + +fragment APOS : '\''! '\''; +fragment DECIMAL_DIGIT : '0'..'9' ; +fragment INTEGER_TYPE_SUFFIX : ( 'L' | 'l' ); +fragment HEX_DIGIT : '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'A'|'B'|'C'|'D'|'E'|'F'|'a'|'b'|'c'|'d'|'e'|'f'; + +fragment EXPONENT_PART : 'e' (SIGN)* (DECIMAL_DIGIT)+ | 'E' (SIGN)* (DECIMAL_DIGIT)+ ; +fragment SIGN : '+' | '-' ; +fragment REAL_TYPE_SUFFIX : 'F' | 'f' | 'D' | 'd'; diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java index 11a3cdbee8..668e9e91a9 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java @@ -1,850 +1,850 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel.standard; - -import java.util.ArrayList; -import java.util.List; -import java.util.Stack; - -import org.springframework.expression.ParseException; -import org.springframework.expression.ParserContext; -import org.springframework.expression.common.TemplateAwareExpressionParser; -import org.springframework.expression.spel.InternalParseException; -import org.springframework.expression.spel.SpelMessage; -import org.springframework.expression.spel.SpelParseException; -import org.springframework.expression.spel.SpelParserConfiguration; -import org.springframework.expression.spel.ast.Assign; -import org.springframework.expression.spel.ast.BeanReference; -import org.springframework.expression.spel.ast.BooleanLiteral; -import org.springframework.expression.spel.ast.CompoundExpression; -import org.springframework.expression.spel.ast.ConstructorReference; -import org.springframework.expression.spel.ast.Elvis; -import org.springframework.expression.spel.ast.FunctionReference; -import org.springframework.expression.spel.ast.Identifier; -import org.springframework.expression.spel.ast.Indexer; -import org.springframework.expression.spel.ast.InlineList; -import org.springframework.expression.spel.ast.Literal; -import org.springframework.expression.spel.ast.MethodReference; -import org.springframework.expression.spel.ast.NullLiteral; -import org.springframework.expression.spel.ast.OpAnd; -import org.springframework.expression.spel.ast.OpDivide; -import org.springframework.expression.spel.ast.OpEQ; -import org.springframework.expression.spel.ast.OpGE; -import org.springframework.expression.spel.ast.OpGT; -import org.springframework.expression.spel.ast.OpLE; -import org.springframework.expression.spel.ast.OpLT; -import org.springframework.expression.spel.ast.OpMinus; -import org.springframework.expression.spel.ast.OpModulus; -import org.springframework.expression.spel.ast.OpMultiply; -import org.springframework.expression.spel.ast.OpNE; -import org.springframework.expression.spel.ast.OpOr; -import org.springframework.expression.spel.ast.OpPlus; -import org.springframework.expression.spel.ast.OperatorInstanceof; -import org.springframework.expression.spel.ast.OperatorMatches; -import org.springframework.expression.spel.ast.OperatorNot; -import org.springframework.expression.spel.ast.OperatorPower; -import org.springframework.expression.spel.ast.Projection; -import org.springframework.expression.spel.ast.PropertyOrFieldReference; -import org.springframework.expression.spel.ast.QualifiedIdentifier; -import org.springframework.expression.spel.ast.Selection; -import org.springframework.expression.spel.ast.SpelNodeImpl; -import org.springframework.expression.spel.ast.StringLiteral; -import org.springframework.expression.spel.ast.Ternary; -import org.springframework.expression.spel.ast.TypeReference; -import org.springframework.expression.spel.ast.VariableReference; -import org.springframework.util.Assert; - -/** - * Hand written SpEL parser. Instances are reusable but are not thread safe. - * - * @author Andy Clement - * @since 3.0 - */ -class InternalSpelExpressionParser extends TemplateAwareExpressionParser { - - // The expression being parsed - private String expressionString; - - // The token stream constructed from that expression string - private List tokenStream; - - // length of a populated token stream - private int tokenStreamLength; - - // Current location in the token stream when processing tokens - private int tokenStreamPointer; - - // For rules that build nodes, they are stacked here for return - private Stack constructedNodes = new Stack(); - - private SpelParserConfiguration configuration; - - - /** - * Create a parser with some configured behavior. - * @param configuration custom configuration options - */ - public InternalSpelExpressionParser(SpelParserConfiguration configuration) { - this.configuration = configuration; - } - - - @Override - protected SpelExpression doParseExpression(String expressionString, ParserContext context) throws ParseException { - try { - this.expressionString = expressionString; - Tokenizer tokenizer = new Tokenizer(expressionString); - tokenizer.process(); - tokenStream = tokenizer.getTokens(); - tokenStreamLength = tokenStream.size(); - tokenStreamPointer = 0; - constructedNodes.clear(); - SpelNodeImpl ast = eatExpression(); - if (moreTokens()) { - throw new SpelParseException(peekToken().startpos,SpelMessage.MORE_INPUT,toString(nextToken())); - } - Assert.isTrue(constructedNodes.isEmpty()); - return new SpelExpression(expressionString, ast, configuration); - } - catch (InternalParseException ipe) { - throw ipe.getCause(); - } - } - - // expression - // : logicalOrExpression - // ( (ASSIGN^ logicalOrExpression) - // | (DEFAULT^ logicalOrExpression) - // | (QMARK^ expression COLON! expression) - // | (ELVIS^ expression))?; - private SpelNodeImpl eatExpression() { - SpelNodeImpl expr = eatLogicalOrExpression(); - if (moreTokens()) { - Token t = peekToken(); - if (t.kind==TokenKind.ASSIGN) { // a=b - if (expr==null) { - expr = new NullLiteral(toPos(t.startpos-1,t.endpos-1)); - } - nextToken(); - SpelNodeImpl assignedValue = eatLogicalOrExpression(); - return new Assign(toPos(t),expr,assignedValue); - } else if (t.kind==TokenKind.ELVIS) { // a?:b (a if it isn't null, otherwise b) - if (expr==null) { - expr = new NullLiteral(toPos(t.startpos-1,t.endpos-2)); - } - nextToken(); // elvis has left the building - SpelNodeImpl valueIfNull = eatExpression(); - if (valueIfNull==null) { - valueIfNull = new NullLiteral(toPos(t.startpos+1,t.endpos+1)); - } - return new Elvis(toPos(t),expr,valueIfNull); - } else if (t.kind==TokenKind.QMARK) { // a?b:c - if (expr==null) { - expr = new NullLiteral(toPos(t.startpos-1,t.endpos-1)); - } - nextToken(); - SpelNodeImpl ifTrueExprValue = eatExpression(); - eatToken(TokenKind.COLON); - SpelNodeImpl ifFalseExprValue = eatExpression(); - return new Ternary(toPos(t),expr,ifTrueExprValue,ifFalseExprValue); - } - } - return expr; - } - - //logicalOrExpression : logicalAndExpression (OR^ logicalAndExpression)*; - private SpelNodeImpl eatLogicalOrExpression() { - SpelNodeImpl expr = eatLogicalAndExpression(); - while (peekIdentifierToken("or")) { - Token t = nextToken(); //consume OR - SpelNodeImpl rhExpr = eatLogicalAndExpression(); - checkRightOperand(t,rhExpr); - expr = new OpOr(toPos(t),expr,rhExpr); - } - return expr; - } - - // logicalAndExpression : relationalExpression (AND^ relationalExpression)*; - private SpelNodeImpl eatLogicalAndExpression() { - SpelNodeImpl expr = eatRelationalExpression(); - while (peekIdentifierToken("and")) { - Token t = nextToken();// consume 'AND' - SpelNodeImpl rhExpr = eatRelationalExpression(); - checkRightOperand(t,rhExpr); - expr = new OpAnd(toPos(t),expr,rhExpr); - } - return expr; - } - - // relationalExpression : sumExpression (relationalOperator^ sumExpression)?; - private SpelNodeImpl eatRelationalExpression() { - SpelNodeImpl expr = eatSumExpression(); - Token relationalOperatorToken = maybeEatRelationalOperator(); - if (relationalOperatorToken != null) { - Token t = nextToken(); //consume relational operator token - SpelNodeImpl rhExpr = eatSumExpression(); - checkRightOperand(t,rhExpr); - TokenKind tk = relationalOperatorToken.kind; - if (relationalOperatorToken.isNumericRelationalOperator()) { - int pos = toPos(t); - if (tk==TokenKind.GT) { - return new OpGT(pos,expr,rhExpr); - } else if (tk==TokenKind.LT) { - return new OpLT(pos,expr,rhExpr); - } else if (tk==TokenKind.LE) { - return new OpLE(pos,expr,rhExpr); - } else if (tk==TokenKind.GE) { - return new OpGE(pos,expr,rhExpr); - } else if (tk == TokenKind.EQ) { - return new OpEQ(pos,expr,rhExpr); - } else { - Assert.isTrue(tk == TokenKind.NE); - return new OpNE(pos,expr,rhExpr); - } - } - if (tk==TokenKind.INSTANCEOF) { - return new OperatorInstanceof(toPos(t),expr,rhExpr); - } else if (tk==TokenKind.MATCHES) { - return new OperatorMatches(toPos(t),expr,rhExpr); - } else { - Assert.isTrue(tk==TokenKind.BETWEEN); - return new org.springframework.expression.spel.ast.OperatorBetween(toPos(t),expr,rhExpr); - } - } - return expr; - } - - //sumExpression: productExpression ( (PLUS^ | MINUS^) productExpression)*; - private SpelNodeImpl eatSumExpression() { - SpelNodeImpl expr = eatProductExpression(); - while (peekToken(TokenKind.PLUS,TokenKind.MINUS)) { - Token t = nextToken();//consume PLUS or MINUS - SpelNodeImpl rhExpr = eatProductExpression(); - checkRightOperand(t,rhExpr); - if (t.kind==TokenKind.PLUS) { - expr = new OpPlus(toPos(t),expr,rhExpr); - } else { - Assert.isTrue(t.kind==TokenKind.MINUS); - expr = new OpMinus(toPos(t),expr,rhExpr); - } - } - return expr; - } - - // productExpression: powerExpr ((STAR^ | DIV^| MOD^) powerExpr)* ; - private SpelNodeImpl eatProductExpression() { - SpelNodeImpl expr = eatPowerExpression(); - while (peekToken(TokenKind.STAR,TokenKind.DIV,TokenKind.MOD)) { - Token t = nextToken(); // consume STAR/DIV/MOD - SpelNodeImpl rhExpr = eatPowerExpression(); - checkRightOperand(t,rhExpr); - if (t.kind==TokenKind.STAR) { - expr = new OpMultiply(toPos(t),expr,rhExpr); - } else if (t.kind==TokenKind.DIV) { - expr = new OpDivide(toPos(t),expr,rhExpr); - } else { - Assert.isTrue(t.kind==TokenKind.MOD); - expr = new OpModulus(toPos(t),expr,rhExpr); - } - } - return expr; - } - - // powerExpr : unaryExpression (POWER^ unaryExpression)? ; - private SpelNodeImpl eatPowerExpression() { - SpelNodeImpl expr = eatUnaryExpression(); - if (peekToken(TokenKind.POWER)) { - Token t = nextToken();//consume POWER - SpelNodeImpl rhExpr = eatUnaryExpression(); - checkRightOperand(t,rhExpr); - return new OperatorPower(toPos(t),expr, rhExpr); - } - return expr; - } - - // unaryExpression: (PLUS^ | MINUS^ | BANG^) unaryExpression | primaryExpression ; - private SpelNodeImpl eatUnaryExpression() { - if (peekToken(TokenKind.PLUS,TokenKind.MINUS,TokenKind.NOT)) { - Token t = nextToken(); - SpelNodeImpl expr = eatUnaryExpression(); - if (t.kind==TokenKind.NOT) { - return new OperatorNot(toPos(t),expr); - } else if (t.kind==TokenKind.PLUS) { - return new OpPlus(toPos(t),expr); - } else { - Assert.isTrue(t.kind==TokenKind.MINUS); - return new OpMinus(toPos(t),expr); - } - } else { - return eatPrimaryExpression(); - } - } - - // primaryExpression : startNode (node)? -> ^(EXPRESSION startNode (node)?); - private SpelNodeImpl eatPrimaryExpression() { - List nodes = new ArrayList(); - SpelNodeImpl start = eatStartNode(); // always a start node - nodes.add(start); - while (maybeEatNode()) { - nodes.add(pop()); - } - if (nodes.size()==1) { - return nodes.get(0); - } else { - return new CompoundExpression(toPos(start.getStartPosition(),nodes.get(nodes.size()-1).getEndPosition()),nodes.toArray(new SpelNodeImpl[nodes.size()])); - } - } - - // node : ((DOT dottedNode) | (SAFE_NAVI dottedNode) | nonDottedNode)+; - private boolean maybeEatNode() { - SpelNodeImpl expr = null; - if (peekToken(TokenKind.DOT,TokenKind.SAFE_NAVI)) { - expr = eatDottedNode(); - } else { - expr = maybeEatNonDottedNode(); - } - if (expr==null) { - return false; - } else { - push(expr); - return true; - } - } - - // nonDottedNode: indexer; - private SpelNodeImpl maybeEatNonDottedNode() { - if (peekToken(TokenKind.LSQUARE)) { - if (maybeEatIndexer()) { - return pop(); - } - } - return null; - } - - //dottedNode - // : ((methodOrProperty - // | functionOrVar - // | projection - // | selection - // | firstSelection - // | lastSelection - // )) - // ; - private SpelNodeImpl eatDottedNode() { - Token t = nextToken();// it was a '.' or a '?.' - boolean nullSafeNavigation = t.kind==TokenKind.SAFE_NAVI; - if (maybeEatMethodOrProperty(nullSafeNavigation) || maybeEatFunctionOrVar() || maybeEatProjection(nullSafeNavigation) || maybeEatSelection(nullSafeNavigation)) { - return pop(); - } - if (peekToken()==null) { - // unexpectedly ran out of data - raiseInternalException(t.startpos,SpelMessage.OOD); - } else { - raiseInternalException(t.startpos,SpelMessage.UNEXPECTED_DATA_AFTER_DOT,toString(peekToken())); - } - return null; - } - - // functionOrVar - // : (POUND ID LPAREN) => function - // | var - // - // function : POUND id=ID methodArgs -> ^(FUNCTIONREF[$id] methodArgs); - // var : POUND id=ID -> ^(VARIABLEREF[$id]); - private boolean maybeEatFunctionOrVar() { - if (!peekToken(TokenKind.HASH)) { - return false; - } - Token t = nextToken(); - Token functionOrVariableName = eatToken(TokenKind.IDENTIFIER); - SpelNodeImpl[] args = maybeEatMethodArgs(); - if (args==null) { - push(new VariableReference(functionOrVariableName.data,toPos(t.startpos,functionOrVariableName.endpos))); - return true; - } else { - push(new FunctionReference(functionOrVariableName.data,toPos(t.startpos,functionOrVariableName.endpos),args)); - return true; - } - } - - // methodArgs : LPAREN! (argument (COMMA! argument)* (COMMA!)?)? RPAREN!; - private SpelNodeImpl[] maybeEatMethodArgs() { - if (!peekToken(TokenKind.LPAREN)) { - return null; - } - List args = new ArrayList(); - consumeArguments(args); - eatToken(TokenKind.RPAREN); - return args.toArray(new SpelNodeImpl[args.size()]); - } - - private void eatConstructorArgs(List accumulatedArguments) { - if (!peekToken(TokenKind.LPAREN)) { - throw new InternalParseException(new SpelParseException(expressionString,positionOf(peekToken()),SpelMessage.MISSING_CONSTRUCTOR_ARGS)); - } - consumeArguments(accumulatedArguments); - eatToken(TokenKind.RPAREN); - } - - /** - * Used for consuming arguments for either a method or a constructor call - */ - private void consumeArguments(List accumulatedArguments) { - int pos = peekToken().startpos; - Token next = null; - do { - nextToken();// consume ( (first time through) or comma (subsequent times) - Token t = peekToken(); - if (t==null) { - raiseInternalException(pos,SpelMessage.RUN_OUT_OF_ARGUMENTS); - } - if (t.kind!=TokenKind.RPAREN) { - accumulatedArguments.add(eatExpression()); - } - next = peekToken(); - } while (next!=null && next.kind==TokenKind.COMMA); - if (next==null) { - raiseInternalException(pos,SpelMessage.RUN_OUT_OF_ARGUMENTS); - } - } - - private int positionOf(Token t) { - if (t==null) { - // if null assume the problem is because the right token was - // not found at the end of the expression - return expressionString.length(); - } else { - return t.startpos; - } - } - - - //startNode - // : parenExpr | literal - // | type - // | methodOrProperty - // | functionOrVar - // | projection - // | selection - // | firstSelection - // | lastSelection - // | indexer - // | constructor - private SpelNodeImpl eatStartNode() { - if (maybeEatLiteral()) { - return pop(); - } else if (maybeEatParenExpression()) { - return pop(); - } else if (maybeEatTypeReference() || maybeEatNullReference() || maybeEatConstructorReference() || maybeEatMethodOrProperty(false) || maybeEatFunctionOrVar()) { - return pop(); - } else if (maybeEatBeanReference()) { - return pop(); - } else if (maybeEatProjection(false) || maybeEatSelection(false) || maybeEatIndexer()) { - return pop(); - } else if (maybeEatInlineList()) { - return pop(); - } else { - return null; - } - } - - // parse: @beanname @'bean.name' - // quoted if dotted - private boolean maybeEatBeanReference() { - if (peekToken(TokenKind.BEAN_REF)) { - Token beanRefToken = nextToken(); - Token beanNameToken = null; - String beanname = null; - if (peekToken(TokenKind.IDENTIFIER)) { - beanNameToken = eatToken(TokenKind.IDENTIFIER); - beanname = beanNameToken.data; - } else if (peekToken(TokenKind.LITERAL_STRING)) { - beanNameToken = eatToken(TokenKind.LITERAL_STRING); - beanname = beanNameToken.stringValue(); - beanname = beanname.substring(1, beanname.length() - 1); - } else { - raiseInternalException(beanRefToken.startpos,SpelMessage.INVALID_BEAN_REFERENCE); - } - - BeanReference beanReference = new BeanReference(toPos(beanNameToken),beanname); - constructedNodes.push(beanReference); - return true; - } - return false; - } - - private boolean maybeEatTypeReference() { - if (peekToken(TokenKind.IDENTIFIER)) { - Token typeName = peekToken(); - if (!typeName.stringValue().equals("T")) { - return false; - } - nextToken(); - eatToken(TokenKind.LPAREN); - SpelNodeImpl node = eatPossiblyQualifiedId(); - // dotted qualified id - eatToken(TokenKind.RPAREN); - constructedNodes.push(new TypeReference(toPos(typeName),node)); - return true; - } - return false; - } - - private boolean maybeEatNullReference() { - if (peekToken(TokenKind.IDENTIFIER)) { - Token nullToken = peekToken(); - if (!nullToken.stringValue().equals("null")) { - return false; - } - nextToken(); - constructedNodes.push(new NullLiteral(toPos(nullToken))); - return true; - } - return false; - } - - //projection: PROJECT^ expression RCURLY!; - private boolean maybeEatProjection(boolean nullSafeNavigation) { - Token t = peekToken(); - if (!peekToken(TokenKind.PROJECT,true)) { - return false; - } - SpelNodeImpl expr = eatExpression(); - eatToken(TokenKind.RSQUARE); - constructedNodes.push(new Projection(nullSafeNavigation, toPos(t), expr)); - return true; - } - - // list = LCURLY (element (COMMA element)*) RCURLY - private boolean maybeEatInlineList() { - Token t = peekToken(); - if (!peekToken(TokenKind.LCURLY,true)) { - return false; - } - SpelNodeImpl expr = null; - Token closingCurly = peekToken(); - if (peekToken(TokenKind.RCURLY,true)) { - // empty list '[]' - expr = new InlineList(toPos(t.startpos,closingCurly.endpos)); - } else { - List listElements = new ArrayList(); - do { - listElements.add(eatExpression()); - } while (peekToken(TokenKind.COMMA,true)); - closingCurly = eatToken(TokenKind.RCURLY); - expr = new InlineList(toPos(t.startpos,closingCurly.endpos),listElements.toArray(new SpelNodeImpl[listElements.size()])); - } - constructedNodes.push(expr); - return true; - } - - private boolean maybeEatIndexer() { - Token t = peekToken(); - if (!peekToken(TokenKind.LSQUARE,true)) { - return false; - } - SpelNodeImpl expr = eatExpression(); - eatToken(TokenKind.RSQUARE); - constructedNodes.push(new Indexer(toPos(t),expr)); - return true; - } - - private boolean maybeEatSelection(boolean nullSafeNavigation) { - Token t = peekToken(); - if (!peekSelectToken()) { - return false; - } - nextToken(); - SpelNodeImpl expr = eatExpression(); - eatToken(TokenKind.RSQUARE); - if (t.kind==TokenKind.SELECT_FIRST) { - constructedNodes.push(new Selection(nullSafeNavigation,Selection.FIRST,toPos(t),expr)); - } else if (t.kind==TokenKind.SELECT_LAST) { - constructedNodes.push(new Selection(nullSafeNavigation,Selection.LAST,toPos(t),expr)); - } else { - constructedNodes.push(new Selection(nullSafeNavigation,Selection.ALL,toPos(t),expr)); - } - return true; - } - - /** - * Eat an identifier, possibly qualified (meaning that it is dotted). - * TODO AndyC Could create complete identifiers (a.b.c) here rather than a sequence of them? (a, b, c) - */ - private SpelNodeImpl eatPossiblyQualifiedId() { - List qualifiedIdPieces = new ArrayList(); - Token startnode = eatToken(TokenKind.IDENTIFIER); - qualifiedIdPieces.add(new Identifier(startnode.stringValue(),toPos(startnode))); - while (peekToken(TokenKind.DOT,true)) { - Token node = eatToken(TokenKind.IDENTIFIER); - qualifiedIdPieces.add(new Identifier(node.stringValue(),toPos(node))); - } - return new QualifiedIdentifier(toPos(startnode.startpos,qualifiedIdPieces.get(qualifiedIdPieces.size()-1).getEndPosition()),qualifiedIdPieces.toArray(new SpelNodeImpl[qualifiedIdPieces.size()])); - } - - // This is complicated due to the support for dollars in identifiers. Dollars are normally separate tokens but - // there we want to combine a series of identifiers and dollars into a single identifier - private boolean maybeEatMethodOrProperty(boolean nullSafeNavigation) { - if (peekToken(TokenKind.IDENTIFIER)) { - Token methodOrPropertyName = nextToken(); - SpelNodeImpl[] args = maybeEatMethodArgs(); - if (args==null) { - // property - push(new PropertyOrFieldReference(nullSafeNavigation, methodOrPropertyName.data,toPos(methodOrPropertyName))); - return true; - } else { - // methodreference - push(new MethodReference(nullSafeNavigation, methodOrPropertyName.data,toPos(methodOrPropertyName),args)); - // TODO what is the end position for a method reference? the name or the last arg? - return true; - } - } - return false; - - } - - //constructor - //: ('new' qualifiedId LPAREN) => 'new' qualifiedId ctorArgs -> ^(CONSTRUCTOR qualifiedId ctorArgs) - private boolean maybeEatConstructorReference() { - if (peekIdentifierToken("new")) { - Token newToken = nextToken(); - SpelNodeImpl possiblyQualifiedConstructorName = eatPossiblyQualifiedId(); - List nodes = new ArrayList(); - nodes.add(possiblyQualifiedConstructorName); - if (peekToken(TokenKind.LSQUARE)) { - // array initializer - List dimensions = new ArrayList(); - while (peekToken(TokenKind.LSQUARE,true)) { - if (!peekToken(TokenKind.RSQUARE)) { - dimensions.add(eatExpression()); - } else { - dimensions.add(null); - } - eatToken(TokenKind.RSQUARE); - } - if (maybeEatInlineList()) { - nodes.add(pop()); - } - push(new ConstructorReference(toPos(newToken), dimensions.toArray(new SpelNodeImpl[dimensions.size()]), - nodes.toArray(new SpelNodeImpl[nodes.size()]))); - } else { - // regular constructor invocation - eatConstructorArgs(nodes); - // TODO correct end position? - push(new ConstructorReference(toPos(newToken), nodes.toArray(new SpelNodeImpl[nodes.size()]))); - } - return true; - } - return false; - } - - private void push(SpelNodeImpl newNode) { - constructedNodes.push(newNode); - } - - private SpelNodeImpl pop() { - return constructedNodes.pop(); - } - - // literal - // : INTEGER_LITERAL - // | boolLiteral - // | STRING_LITERAL - // | HEXADECIMAL_INTEGER_LITERAL - // | REAL_LITERAL - // | DQ_STRING_LITERAL - // | NULL_LITERAL - private boolean maybeEatLiteral() { - Token t = peekToken(); - if (t==null) { - return false; - } - if (t.kind==TokenKind.LITERAL_INT) { - push(Literal.getIntLiteral(t.data, toPos(t), 10)); - } else if (t.kind==TokenKind.LITERAL_LONG) { - push(Literal.getLongLiteral(t.data, toPos(t), 10)); - } else if (t.kind==TokenKind.LITERAL_HEXINT) { - push(Literal.getIntLiteral(t.data, toPos(t), 16)); - } else if (t.kind==TokenKind.LITERAL_HEXLONG) { - push(Literal.getLongLiteral(t.data, toPos(t), 16)); - } else if (t.kind==TokenKind.LITERAL_REAL) { - push(Literal.getRealLiteral(t.data, toPos(t),false)); - } else if (t.kind==TokenKind.LITERAL_REAL_FLOAT) { - push(Literal.getRealLiteral(t.data, toPos(t), true)); - } else if (peekIdentifierToken("true")) { - push(new BooleanLiteral(t.data,toPos(t),true)); - } else if (peekIdentifierToken("false")) { - push(new BooleanLiteral(t.data,toPos(t),false)); - } else if (t.kind==TokenKind.LITERAL_STRING) { - push(new StringLiteral(t.data,toPos(t),t.data)); - } else { - return false; - } - nextToken(); - return true; - } - - //parenExpr : LPAREN! expression RPAREN!; - private boolean maybeEatParenExpression() { - if (peekToken(TokenKind.LPAREN)) { - nextToken(); - SpelNodeImpl expr = eatExpression(); - eatToken(TokenKind.RPAREN); - push(expr); - return true; - } else { - return false; - } - } - - // relationalOperator - // : EQUAL | NOT_EQUAL | LESS_THAN | LESS_THAN_OR_EQUAL | GREATER_THAN - // | GREATER_THAN_OR_EQUAL | INSTANCEOF | BETWEEN | MATCHES - private Token maybeEatRelationalOperator() { - Token t = peekToken(); - if (t==null) { - return null; - } - if (t.isNumericRelationalOperator()) { - return t; - } - if (t.isIdentifier()) { - String idString = t.stringValue(); - if (idString.equalsIgnoreCase("instanceof")) { - return t.asInstanceOfToken(); - } else if (idString.equalsIgnoreCase("matches")) { - return t.asMatchesToken(); - } else if (idString.equalsIgnoreCase("between")) { - return t.asBetweenToken(); - } - } - return null; - } - - private Token eatToken(TokenKind expectedKind) { - Token t = nextToken(); - if (t==null) { - raiseInternalException( expressionString.length(), SpelMessage.OOD); - } - if (t.kind!=expectedKind) { - raiseInternalException(t.startpos,SpelMessage.NOT_EXPECTED_TOKEN, expectedKind.toString().toLowerCase(),t.getKind().toString().toLowerCase()); - } - return t; - } - - private boolean peekToken(TokenKind desiredTokenKind) { - return peekToken(desiredTokenKind,false); - } - - private boolean peekToken(TokenKind desiredTokenKind, boolean consumeIfMatched) { - if (!moreTokens()) { - return false; - } - Token t = peekToken(); - if (t.kind==desiredTokenKind) { - if (consumeIfMatched) { - tokenStreamPointer++; - } - return true; - } else { - if (desiredTokenKind == TokenKind.IDENTIFIER) { - // might be one of the textual forms of the operators (e.g. NE for != ) - in which case we can treat it as an identifier - // The list is represented here: Tokenizer.alternativeOperatorNames and those ones are in order in the TokenKind enum - if (t.kind.ordinal()>=TokenKind.DIV.ordinal() && t.kind.ordinal()<=TokenKind.NOT.ordinal() && t.data!=null) { - // if t.data were null, we'd know it wasn't the textual form, it was the symbol form - return true; - } - } - return false; - } - } - - private boolean peekToken(TokenKind possible1,TokenKind possible2) { - if (!moreTokens()) return false; - Token t = peekToken(); - return t.kind==possible1 || t.kind==possible2; - } - - private boolean peekToken(TokenKind possible1,TokenKind possible2, TokenKind possible3) { - if (!moreTokens()) return false; - Token t = peekToken(); - return t.kind==possible1 || t.kind==possible2 || t.kind==possible3; - } - - private boolean peekIdentifierToken(String identifierString) { - if (!moreTokens()) { - return false; - } - Token t = peekToken(); - return t.kind==TokenKind.IDENTIFIER && t.stringValue().equalsIgnoreCase(identifierString); - } - - private boolean peekSelectToken() { - if (!moreTokens()) return false; - Token t = peekToken(); - return t.kind==TokenKind.SELECT || t.kind==TokenKind.SELECT_FIRST || t.kind==TokenKind.SELECT_LAST; - } - - - private boolean moreTokens() { - return tokenStreamPointer=tokenStreamLength) { - return null; - } - return tokenStream.get(tokenStreamPointer++); - } - - private Token peekToken() { - if (tokenStreamPointer>=tokenStreamLength) { - return null; - } - return tokenStream.get(tokenStreamPointer); - } - - private void raiseInternalException(int pos, SpelMessage message,Object... inserts) { - throw new InternalParseException(new SpelParseException(expressionString,pos,message,inserts)); - } - - public String toString(Token t) { - if (t.getKind().hasPayload()) { - return t.stringValue(); - } else { - return t.kind.toString().toLowerCase(); - } - } - - private void checkRightOperand(Token token, SpelNodeImpl operandExpression) { - if (operandExpression==null) { - raiseInternalException(token.startpos,SpelMessage.RIGHT_OPERAND_PROBLEM); - } - } - - /** - * Compress the start and end of a token into a single int - */ - private int toPos(Token t) { - return (t.startpos<<16)+t.endpos; - } - - private int toPos(int start,int end) { - return (start<<16)+end; - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel.standard; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +import org.springframework.expression.ParseException; +import org.springframework.expression.ParserContext; +import org.springframework.expression.common.TemplateAwareExpressionParser; +import org.springframework.expression.spel.InternalParseException; +import org.springframework.expression.spel.SpelMessage; +import org.springframework.expression.spel.SpelParseException; +import org.springframework.expression.spel.SpelParserConfiguration; +import org.springframework.expression.spel.ast.Assign; +import org.springframework.expression.spel.ast.BeanReference; +import org.springframework.expression.spel.ast.BooleanLiteral; +import org.springframework.expression.spel.ast.CompoundExpression; +import org.springframework.expression.spel.ast.ConstructorReference; +import org.springframework.expression.spel.ast.Elvis; +import org.springframework.expression.spel.ast.FunctionReference; +import org.springframework.expression.spel.ast.Identifier; +import org.springframework.expression.spel.ast.Indexer; +import org.springframework.expression.spel.ast.InlineList; +import org.springframework.expression.spel.ast.Literal; +import org.springframework.expression.spel.ast.MethodReference; +import org.springframework.expression.spel.ast.NullLiteral; +import org.springframework.expression.spel.ast.OpAnd; +import org.springframework.expression.spel.ast.OpDivide; +import org.springframework.expression.spel.ast.OpEQ; +import org.springframework.expression.spel.ast.OpGE; +import org.springframework.expression.spel.ast.OpGT; +import org.springframework.expression.spel.ast.OpLE; +import org.springframework.expression.spel.ast.OpLT; +import org.springframework.expression.spel.ast.OpMinus; +import org.springframework.expression.spel.ast.OpModulus; +import org.springframework.expression.spel.ast.OpMultiply; +import org.springframework.expression.spel.ast.OpNE; +import org.springframework.expression.spel.ast.OpOr; +import org.springframework.expression.spel.ast.OpPlus; +import org.springframework.expression.spel.ast.OperatorInstanceof; +import org.springframework.expression.spel.ast.OperatorMatches; +import org.springframework.expression.spel.ast.OperatorNot; +import org.springframework.expression.spel.ast.OperatorPower; +import org.springframework.expression.spel.ast.Projection; +import org.springframework.expression.spel.ast.PropertyOrFieldReference; +import org.springframework.expression.spel.ast.QualifiedIdentifier; +import org.springframework.expression.spel.ast.Selection; +import org.springframework.expression.spel.ast.SpelNodeImpl; +import org.springframework.expression.spel.ast.StringLiteral; +import org.springframework.expression.spel.ast.Ternary; +import org.springframework.expression.spel.ast.TypeReference; +import org.springframework.expression.spel.ast.VariableReference; +import org.springframework.util.Assert; + +/** + * Hand written SpEL parser. Instances are reusable but are not thread safe. + * + * @author Andy Clement + * @since 3.0 + */ +class InternalSpelExpressionParser extends TemplateAwareExpressionParser { + + // The expression being parsed + private String expressionString; + + // The token stream constructed from that expression string + private List tokenStream; + + // length of a populated token stream + private int tokenStreamLength; + + // Current location in the token stream when processing tokens + private int tokenStreamPointer; + + // For rules that build nodes, they are stacked here for return + private Stack constructedNodes = new Stack(); + + private SpelParserConfiguration configuration; + + + /** + * Create a parser with some configured behavior. + * @param configuration custom configuration options + */ + public InternalSpelExpressionParser(SpelParserConfiguration configuration) { + this.configuration = configuration; + } + + + @Override + protected SpelExpression doParseExpression(String expressionString, ParserContext context) throws ParseException { + try { + this.expressionString = expressionString; + Tokenizer tokenizer = new Tokenizer(expressionString); + tokenizer.process(); + tokenStream = tokenizer.getTokens(); + tokenStreamLength = tokenStream.size(); + tokenStreamPointer = 0; + constructedNodes.clear(); + SpelNodeImpl ast = eatExpression(); + if (moreTokens()) { + throw new SpelParseException(peekToken().startpos,SpelMessage.MORE_INPUT,toString(nextToken())); + } + Assert.isTrue(constructedNodes.isEmpty()); + return new SpelExpression(expressionString, ast, configuration); + } + catch (InternalParseException ipe) { + throw ipe.getCause(); + } + } + + // expression + // : logicalOrExpression + // ( (ASSIGN^ logicalOrExpression) + // | (DEFAULT^ logicalOrExpression) + // | (QMARK^ expression COLON! expression) + // | (ELVIS^ expression))?; + private SpelNodeImpl eatExpression() { + SpelNodeImpl expr = eatLogicalOrExpression(); + if (moreTokens()) { + Token t = peekToken(); + if (t.kind==TokenKind.ASSIGN) { // a=b + if (expr==null) { + expr = new NullLiteral(toPos(t.startpos-1,t.endpos-1)); + } + nextToken(); + SpelNodeImpl assignedValue = eatLogicalOrExpression(); + return new Assign(toPos(t),expr,assignedValue); + } else if (t.kind==TokenKind.ELVIS) { // a?:b (a if it isn't null, otherwise b) + if (expr==null) { + expr = new NullLiteral(toPos(t.startpos-1,t.endpos-2)); + } + nextToken(); // elvis has left the building + SpelNodeImpl valueIfNull = eatExpression(); + if (valueIfNull==null) { + valueIfNull = new NullLiteral(toPos(t.startpos+1,t.endpos+1)); + } + return new Elvis(toPos(t),expr,valueIfNull); + } else if (t.kind==TokenKind.QMARK) { // a?b:c + if (expr==null) { + expr = new NullLiteral(toPos(t.startpos-1,t.endpos-1)); + } + nextToken(); + SpelNodeImpl ifTrueExprValue = eatExpression(); + eatToken(TokenKind.COLON); + SpelNodeImpl ifFalseExprValue = eatExpression(); + return new Ternary(toPos(t),expr,ifTrueExprValue,ifFalseExprValue); + } + } + return expr; + } + + //logicalOrExpression : logicalAndExpression (OR^ logicalAndExpression)*; + private SpelNodeImpl eatLogicalOrExpression() { + SpelNodeImpl expr = eatLogicalAndExpression(); + while (peekIdentifierToken("or")) { + Token t = nextToken(); //consume OR + SpelNodeImpl rhExpr = eatLogicalAndExpression(); + checkRightOperand(t,rhExpr); + expr = new OpOr(toPos(t),expr,rhExpr); + } + return expr; + } + + // logicalAndExpression : relationalExpression (AND^ relationalExpression)*; + private SpelNodeImpl eatLogicalAndExpression() { + SpelNodeImpl expr = eatRelationalExpression(); + while (peekIdentifierToken("and")) { + Token t = nextToken();// consume 'AND' + SpelNodeImpl rhExpr = eatRelationalExpression(); + checkRightOperand(t,rhExpr); + expr = new OpAnd(toPos(t),expr,rhExpr); + } + return expr; + } + + // relationalExpression : sumExpression (relationalOperator^ sumExpression)?; + private SpelNodeImpl eatRelationalExpression() { + SpelNodeImpl expr = eatSumExpression(); + Token relationalOperatorToken = maybeEatRelationalOperator(); + if (relationalOperatorToken != null) { + Token t = nextToken(); //consume relational operator token + SpelNodeImpl rhExpr = eatSumExpression(); + checkRightOperand(t,rhExpr); + TokenKind tk = relationalOperatorToken.kind; + if (relationalOperatorToken.isNumericRelationalOperator()) { + int pos = toPos(t); + if (tk==TokenKind.GT) { + return new OpGT(pos,expr,rhExpr); + } else if (tk==TokenKind.LT) { + return new OpLT(pos,expr,rhExpr); + } else if (tk==TokenKind.LE) { + return new OpLE(pos,expr,rhExpr); + } else if (tk==TokenKind.GE) { + return new OpGE(pos,expr,rhExpr); + } else if (tk == TokenKind.EQ) { + return new OpEQ(pos,expr,rhExpr); + } else { + Assert.isTrue(tk == TokenKind.NE); + return new OpNE(pos,expr,rhExpr); + } + } + if (tk==TokenKind.INSTANCEOF) { + return new OperatorInstanceof(toPos(t),expr,rhExpr); + } else if (tk==TokenKind.MATCHES) { + return new OperatorMatches(toPos(t),expr,rhExpr); + } else { + Assert.isTrue(tk==TokenKind.BETWEEN); + return new org.springframework.expression.spel.ast.OperatorBetween(toPos(t),expr,rhExpr); + } + } + return expr; + } + + //sumExpression: productExpression ( (PLUS^ | MINUS^) productExpression)*; + private SpelNodeImpl eatSumExpression() { + SpelNodeImpl expr = eatProductExpression(); + while (peekToken(TokenKind.PLUS,TokenKind.MINUS)) { + Token t = nextToken();//consume PLUS or MINUS + SpelNodeImpl rhExpr = eatProductExpression(); + checkRightOperand(t,rhExpr); + if (t.kind==TokenKind.PLUS) { + expr = new OpPlus(toPos(t),expr,rhExpr); + } else { + Assert.isTrue(t.kind==TokenKind.MINUS); + expr = new OpMinus(toPos(t),expr,rhExpr); + } + } + return expr; + } + + // productExpression: powerExpr ((STAR^ | DIV^| MOD^) powerExpr)* ; + private SpelNodeImpl eatProductExpression() { + SpelNodeImpl expr = eatPowerExpression(); + while (peekToken(TokenKind.STAR,TokenKind.DIV,TokenKind.MOD)) { + Token t = nextToken(); // consume STAR/DIV/MOD + SpelNodeImpl rhExpr = eatPowerExpression(); + checkRightOperand(t,rhExpr); + if (t.kind==TokenKind.STAR) { + expr = new OpMultiply(toPos(t),expr,rhExpr); + } else if (t.kind==TokenKind.DIV) { + expr = new OpDivide(toPos(t),expr,rhExpr); + } else { + Assert.isTrue(t.kind==TokenKind.MOD); + expr = new OpModulus(toPos(t),expr,rhExpr); + } + } + return expr; + } + + // powerExpr : unaryExpression (POWER^ unaryExpression)? ; + private SpelNodeImpl eatPowerExpression() { + SpelNodeImpl expr = eatUnaryExpression(); + if (peekToken(TokenKind.POWER)) { + Token t = nextToken();//consume POWER + SpelNodeImpl rhExpr = eatUnaryExpression(); + checkRightOperand(t,rhExpr); + return new OperatorPower(toPos(t),expr, rhExpr); + } + return expr; + } + + // unaryExpression: (PLUS^ | MINUS^ | BANG^) unaryExpression | primaryExpression ; + private SpelNodeImpl eatUnaryExpression() { + if (peekToken(TokenKind.PLUS,TokenKind.MINUS,TokenKind.NOT)) { + Token t = nextToken(); + SpelNodeImpl expr = eatUnaryExpression(); + if (t.kind==TokenKind.NOT) { + return new OperatorNot(toPos(t),expr); + } else if (t.kind==TokenKind.PLUS) { + return new OpPlus(toPos(t),expr); + } else { + Assert.isTrue(t.kind==TokenKind.MINUS); + return new OpMinus(toPos(t),expr); + } + } else { + return eatPrimaryExpression(); + } + } + + // primaryExpression : startNode (node)? -> ^(EXPRESSION startNode (node)?); + private SpelNodeImpl eatPrimaryExpression() { + List nodes = new ArrayList(); + SpelNodeImpl start = eatStartNode(); // always a start node + nodes.add(start); + while (maybeEatNode()) { + nodes.add(pop()); + } + if (nodes.size()==1) { + return nodes.get(0); + } else { + return new CompoundExpression(toPos(start.getStartPosition(),nodes.get(nodes.size()-1).getEndPosition()),nodes.toArray(new SpelNodeImpl[nodes.size()])); + } + } + + // node : ((DOT dottedNode) | (SAFE_NAVI dottedNode) | nonDottedNode)+; + private boolean maybeEatNode() { + SpelNodeImpl expr = null; + if (peekToken(TokenKind.DOT,TokenKind.SAFE_NAVI)) { + expr = eatDottedNode(); + } else { + expr = maybeEatNonDottedNode(); + } + if (expr==null) { + return false; + } else { + push(expr); + return true; + } + } + + // nonDottedNode: indexer; + private SpelNodeImpl maybeEatNonDottedNode() { + if (peekToken(TokenKind.LSQUARE)) { + if (maybeEatIndexer()) { + return pop(); + } + } + return null; + } + + //dottedNode + // : ((methodOrProperty + // | functionOrVar + // | projection + // | selection + // | firstSelection + // | lastSelection + // )) + // ; + private SpelNodeImpl eatDottedNode() { + Token t = nextToken();// it was a '.' or a '?.' + boolean nullSafeNavigation = t.kind==TokenKind.SAFE_NAVI; + if (maybeEatMethodOrProperty(nullSafeNavigation) || maybeEatFunctionOrVar() || maybeEatProjection(nullSafeNavigation) || maybeEatSelection(nullSafeNavigation)) { + return pop(); + } + if (peekToken()==null) { + // unexpectedly ran out of data + raiseInternalException(t.startpos,SpelMessage.OOD); + } else { + raiseInternalException(t.startpos,SpelMessage.UNEXPECTED_DATA_AFTER_DOT,toString(peekToken())); + } + return null; + } + + // functionOrVar + // : (POUND ID LPAREN) => function + // | var + // + // function : POUND id=ID methodArgs -> ^(FUNCTIONREF[$id] methodArgs); + // var : POUND id=ID -> ^(VARIABLEREF[$id]); + private boolean maybeEatFunctionOrVar() { + if (!peekToken(TokenKind.HASH)) { + return false; + } + Token t = nextToken(); + Token functionOrVariableName = eatToken(TokenKind.IDENTIFIER); + SpelNodeImpl[] args = maybeEatMethodArgs(); + if (args==null) { + push(new VariableReference(functionOrVariableName.data,toPos(t.startpos,functionOrVariableName.endpos))); + return true; + } else { + push(new FunctionReference(functionOrVariableName.data,toPos(t.startpos,functionOrVariableName.endpos),args)); + return true; + } + } + + // methodArgs : LPAREN! (argument (COMMA! argument)* (COMMA!)?)? RPAREN!; + private SpelNodeImpl[] maybeEatMethodArgs() { + if (!peekToken(TokenKind.LPAREN)) { + return null; + } + List args = new ArrayList(); + consumeArguments(args); + eatToken(TokenKind.RPAREN); + return args.toArray(new SpelNodeImpl[args.size()]); + } + + private void eatConstructorArgs(List accumulatedArguments) { + if (!peekToken(TokenKind.LPAREN)) { + throw new InternalParseException(new SpelParseException(expressionString,positionOf(peekToken()),SpelMessage.MISSING_CONSTRUCTOR_ARGS)); + } + consumeArguments(accumulatedArguments); + eatToken(TokenKind.RPAREN); + } + + /** + * Used for consuming arguments for either a method or a constructor call + */ + private void consumeArguments(List accumulatedArguments) { + int pos = peekToken().startpos; + Token next = null; + do { + nextToken();// consume ( (first time through) or comma (subsequent times) + Token t = peekToken(); + if (t==null) { + raiseInternalException(pos,SpelMessage.RUN_OUT_OF_ARGUMENTS); + } + if (t.kind!=TokenKind.RPAREN) { + accumulatedArguments.add(eatExpression()); + } + next = peekToken(); + } while (next!=null && next.kind==TokenKind.COMMA); + if (next==null) { + raiseInternalException(pos,SpelMessage.RUN_OUT_OF_ARGUMENTS); + } + } + + private int positionOf(Token t) { + if (t==null) { + // if null assume the problem is because the right token was + // not found at the end of the expression + return expressionString.length(); + } else { + return t.startpos; + } + } + + + //startNode + // : parenExpr | literal + // | type + // | methodOrProperty + // | functionOrVar + // | projection + // | selection + // | firstSelection + // | lastSelection + // | indexer + // | constructor + private SpelNodeImpl eatStartNode() { + if (maybeEatLiteral()) { + return pop(); + } else if (maybeEatParenExpression()) { + return pop(); + } else if (maybeEatTypeReference() || maybeEatNullReference() || maybeEatConstructorReference() || maybeEatMethodOrProperty(false) || maybeEatFunctionOrVar()) { + return pop(); + } else if (maybeEatBeanReference()) { + return pop(); + } else if (maybeEatProjection(false) || maybeEatSelection(false) || maybeEatIndexer()) { + return pop(); + } else if (maybeEatInlineList()) { + return pop(); + } else { + return null; + } + } + + // parse: @beanname @'bean.name' + // quoted if dotted + private boolean maybeEatBeanReference() { + if (peekToken(TokenKind.BEAN_REF)) { + Token beanRefToken = nextToken(); + Token beanNameToken = null; + String beanname = null; + if (peekToken(TokenKind.IDENTIFIER)) { + beanNameToken = eatToken(TokenKind.IDENTIFIER); + beanname = beanNameToken.data; + } else if (peekToken(TokenKind.LITERAL_STRING)) { + beanNameToken = eatToken(TokenKind.LITERAL_STRING); + beanname = beanNameToken.stringValue(); + beanname = beanname.substring(1, beanname.length() - 1); + } else { + raiseInternalException(beanRefToken.startpos,SpelMessage.INVALID_BEAN_REFERENCE); + } + + BeanReference beanReference = new BeanReference(toPos(beanNameToken),beanname); + constructedNodes.push(beanReference); + return true; + } + return false; + } + + private boolean maybeEatTypeReference() { + if (peekToken(TokenKind.IDENTIFIER)) { + Token typeName = peekToken(); + if (!typeName.stringValue().equals("T")) { + return false; + } + nextToken(); + eatToken(TokenKind.LPAREN); + SpelNodeImpl node = eatPossiblyQualifiedId(); + // dotted qualified id + eatToken(TokenKind.RPAREN); + constructedNodes.push(new TypeReference(toPos(typeName),node)); + return true; + } + return false; + } + + private boolean maybeEatNullReference() { + if (peekToken(TokenKind.IDENTIFIER)) { + Token nullToken = peekToken(); + if (!nullToken.stringValue().equals("null")) { + return false; + } + nextToken(); + constructedNodes.push(new NullLiteral(toPos(nullToken))); + return true; + } + return false; + } + + //projection: PROJECT^ expression RCURLY!; + private boolean maybeEatProjection(boolean nullSafeNavigation) { + Token t = peekToken(); + if (!peekToken(TokenKind.PROJECT,true)) { + return false; + } + SpelNodeImpl expr = eatExpression(); + eatToken(TokenKind.RSQUARE); + constructedNodes.push(new Projection(nullSafeNavigation, toPos(t), expr)); + return true; + } + + // list = LCURLY (element (COMMA element)*) RCURLY + private boolean maybeEatInlineList() { + Token t = peekToken(); + if (!peekToken(TokenKind.LCURLY,true)) { + return false; + } + SpelNodeImpl expr = null; + Token closingCurly = peekToken(); + if (peekToken(TokenKind.RCURLY,true)) { + // empty list '[]' + expr = new InlineList(toPos(t.startpos,closingCurly.endpos)); + } else { + List listElements = new ArrayList(); + do { + listElements.add(eatExpression()); + } while (peekToken(TokenKind.COMMA,true)); + closingCurly = eatToken(TokenKind.RCURLY); + expr = new InlineList(toPos(t.startpos,closingCurly.endpos),listElements.toArray(new SpelNodeImpl[listElements.size()])); + } + constructedNodes.push(expr); + return true; + } + + private boolean maybeEatIndexer() { + Token t = peekToken(); + if (!peekToken(TokenKind.LSQUARE,true)) { + return false; + } + SpelNodeImpl expr = eatExpression(); + eatToken(TokenKind.RSQUARE); + constructedNodes.push(new Indexer(toPos(t),expr)); + return true; + } + + private boolean maybeEatSelection(boolean nullSafeNavigation) { + Token t = peekToken(); + if (!peekSelectToken()) { + return false; + } + nextToken(); + SpelNodeImpl expr = eatExpression(); + eatToken(TokenKind.RSQUARE); + if (t.kind==TokenKind.SELECT_FIRST) { + constructedNodes.push(new Selection(nullSafeNavigation,Selection.FIRST,toPos(t),expr)); + } else if (t.kind==TokenKind.SELECT_LAST) { + constructedNodes.push(new Selection(nullSafeNavigation,Selection.LAST,toPos(t),expr)); + } else { + constructedNodes.push(new Selection(nullSafeNavigation,Selection.ALL,toPos(t),expr)); + } + return true; + } + + /** + * Eat an identifier, possibly qualified (meaning that it is dotted). + * TODO AndyC Could create complete identifiers (a.b.c) here rather than a sequence of them? (a, b, c) + */ + private SpelNodeImpl eatPossiblyQualifiedId() { + List qualifiedIdPieces = new ArrayList(); + Token startnode = eatToken(TokenKind.IDENTIFIER); + qualifiedIdPieces.add(new Identifier(startnode.stringValue(),toPos(startnode))); + while (peekToken(TokenKind.DOT,true)) { + Token node = eatToken(TokenKind.IDENTIFIER); + qualifiedIdPieces.add(new Identifier(node.stringValue(),toPos(node))); + } + return new QualifiedIdentifier(toPos(startnode.startpos,qualifiedIdPieces.get(qualifiedIdPieces.size()-1).getEndPosition()),qualifiedIdPieces.toArray(new SpelNodeImpl[qualifiedIdPieces.size()])); + } + + // This is complicated due to the support for dollars in identifiers. Dollars are normally separate tokens but + // there we want to combine a series of identifiers and dollars into a single identifier + private boolean maybeEatMethodOrProperty(boolean nullSafeNavigation) { + if (peekToken(TokenKind.IDENTIFIER)) { + Token methodOrPropertyName = nextToken(); + SpelNodeImpl[] args = maybeEatMethodArgs(); + if (args==null) { + // property + push(new PropertyOrFieldReference(nullSafeNavigation, methodOrPropertyName.data,toPos(methodOrPropertyName))); + return true; + } else { + // methodreference + push(new MethodReference(nullSafeNavigation, methodOrPropertyName.data,toPos(methodOrPropertyName),args)); + // TODO what is the end position for a method reference? the name or the last arg? + return true; + } + } + return false; + + } + + //constructor + //: ('new' qualifiedId LPAREN) => 'new' qualifiedId ctorArgs -> ^(CONSTRUCTOR qualifiedId ctorArgs) + private boolean maybeEatConstructorReference() { + if (peekIdentifierToken("new")) { + Token newToken = nextToken(); + SpelNodeImpl possiblyQualifiedConstructorName = eatPossiblyQualifiedId(); + List nodes = new ArrayList(); + nodes.add(possiblyQualifiedConstructorName); + if (peekToken(TokenKind.LSQUARE)) { + // array initializer + List dimensions = new ArrayList(); + while (peekToken(TokenKind.LSQUARE,true)) { + if (!peekToken(TokenKind.RSQUARE)) { + dimensions.add(eatExpression()); + } else { + dimensions.add(null); + } + eatToken(TokenKind.RSQUARE); + } + if (maybeEatInlineList()) { + nodes.add(pop()); + } + push(new ConstructorReference(toPos(newToken), dimensions.toArray(new SpelNodeImpl[dimensions.size()]), + nodes.toArray(new SpelNodeImpl[nodes.size()]))); + } else { + // regular constructor invocation + eatConstructorArgs(nodes); + // TODO correct end position? + push(new ConstructorReference(toPos(newToken), nodes.toArray(new SpelNodeImpl[nodes.size()]))); + } + return true; + } + return false; + } + + private void push(SpelNodeImpl newNode) { + constructedNodes.push(newNode); + } + + private SpelNodeImpl pop() { + return constructedNodes.pop(); + } + + // literal + // : INTEGER_LITERAL + // | boolLiteral + // | STRING_LITERAL + // | HEXADECIMAL_INTEGER_LITERAL + // | REAL_LITERAL + // | DQ_STRING_LITERAL + // | NULL_LITERAL + private boolean maybeEatLiteral() { + Token t = peekToken(); + if (t==null) { + return false; + } + if (t.kind==TokenKind.LITERAL_INT) { + push(Literal.getIntLiteral(t.data, toPos(t), 10)); + } else if (t.kind==TokenKind.LITERAL_LONG) { + push(Literal.getLongLiteral(t.data, toPos(t), 10)); + } else if (t.kind==TokenKind.LITERAL_HEXINT) { + push(Literal.getIntLiteral(t.data, toPos(t), 16)); + } else if (t.kind==TokenKind.LITERAL_HEXLONG) { + push(Literal.getLongLiteral(t.data, toPos(t), 16)); + } else if (t.kind==TokenKind.LITERAL_REAL) { + push(Literal.getRealLiteral(t.data, toPos(t),false)); + } else if (t.kind==TokenKind.LITERAL_REAL_FLOAT) { + push(Literal.getRealLiteral(t.data, toPos(t), true)); + } else if (peekIdentifierToken("true")) { + push(new BooleanLiteral(t.data,toPos(t),true)); + } else if (peekIdentifierToken("false")) { + push(new BooleanLiteral(t.data,toPos(t),false)); + } else if (t.kind==TokenKind.LITERAL_STRING) { + push(new StringLiteral(t.data,toPos(t),t.data)); + } else { + return false; + } + nextToken(); + return true; + } + + //parenExpr : LPAREN! expression RPAREN!; + private boolean maybeEatParenExpression() { + if (peekToken(TokenKind.LPAREN)) { + nextToken(); + SpelNodeImpl expr = eatExpression(); + eatToken(TokenKind.RPAREN); + push(expr); + return true; + } else { + return false; + } + } + + // relationalOperator + // : EQUAL | NOT_EQUAL | LESS_THAN | LESS_THAN_OR_EQUAL | GREATER_THAN + // | GREATER_THAN_OR_EQUAL | INSTANCEOF | BETWEEN | MATCHES + private Token maybeEatRelationalOperator() { + Token t = peekToken(); + if (t==null) { + return null; + } + if (t.isNumericRelationalOperator()) { + return t; + } + if (t.isIdentifier()) { + String idString = t.stringValue(); + if (idString.equalsIgnoreCase("instanceof")) { + return t.asInstanceOfToken(); + } else if (idString.equalsIgnoreCase("matches")) { + return t.asMatchesToken(); + } else if (idString.equalsIgnoreCase("between")) { + return t.asBetweenToken(); + } + } + return null; + } + + private Token eatToken(TokenKind expectedKind) { + Token t = nextToken(); + if (t==null) { + raiseInternalException( expressionString.length(), SpelMessage.OOD); + } + if (t.kind!=expectedKind) { + raiseInternalException(t.startpos,SpelMessage.NOT_EXPECTED_TOKEN, expectedKind.toString().toLowerCase(),t.getKind().toString().toLowerCase()); + } + return t; + } + + private boolean peekToken(TokenKind desiredTokenKind) { + return peekToken(desiredTokenKind,false); + } + + private boolean peekToken(TokenKind desiredTokenKind, boolean consumeIfMatched) { + if (!moreTokens()) { + return false; + } + Token t = peekToken(); + if (t.kind==desiredTokenKind) { + if (consumeIfMatched) { + tokenStreamPointer++; + } + return true; + } else { + if (desiredTokenKind == TokenKind.IDENTIFIER) { + // might be one of the textual forms of the operators (e.g. NE for != ) - in which case we can treat it as an identifier + // The list is represented here: Tokenizer.alternativeOperatorNames and those ones are in order in the TokenKind enum + if (t.kind.ordinal()>=TokenKind.DIV.ordinal() && t.kind.ordinal()<=TokenKind.NOT.ordinal() && t.data!=null) { + // if t.data were null, we'd know it wasn't the textual form, it was the symbol form + return true; + } + } + return false; + } + } + + private boolean peekToken(TokenKind possible1,TokenKind possible2) { + if (!moreTokens()) return false; + Token t = peekToken(); + return t.kind==possible1 || t.kind==possible2; + } + + private boolean peekToken(TokenKind possible1,TokenKind possible2, TokenKind possible3) { + if (!moreTokens()) return false; + Token t = peekToken(); + return t.kind==possible1 || t.kind==possible2 || t.kind==possible3; + } + + private boolean peekIdentifierToken(String identifierString) { + if (!moreTokens()) { + return false; + } + Token t = peekToken(); + return t.kind==TokenKind.IDENTIFIER && t.stringValue().equalsIgnoreCase(identifierString); + } + + private boolean peekSelectToken() { + if (!moreTokens()) return false; + Token t = peekToken(); + return t.kind==TokenKind.SELECT || t.kind==TokenKind.SELECT_FIRST || t.kind==TokenKind.SELECT_LAST; + } + + + private boolean moreTokens() { + return tokenStreamPointer=tokenStreamLength) { + return null; + } + return tokenStream.get(tokenStreamPointer++); + } + + private Token peekToken() { + if (tokenStreamPointer>=tokenStreamLength) { + return null; + } + return tokenStream.get(tokenStreamPointer); + } + + private void raiseInternalException(int pos, SpelMessage message,Object... inserts) { + throw new InternalParseException(new SpelParseException(expressionString,pos,message,inserts)); + } + + public String toString(Token t) { + if (t.getKind().hasPayload()) { + return t.stringValue(); + } else { + return t.kind.toString().toLowerCase(); + } + } + + private void checkRightOperand(Token token, SpelNodeImpl operandExpression) { + if (operandExpression==null) { + raiseInternalException(token.startpos,SpelMessage.RIGHT_OPERAND_PROBLEM); + } + } + + /** + * Compress the start and end of a token into a single int + */ + private int toPos(Token t) { + return (t.startpos<<16)+t.endpos; + } + + private int toPos(int start,int end) { + return (start<<16)+end; + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/SpelExpressionParser.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/SpelExpressionParser.java index 1ec39ebaaf..7c6c6f987e 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/SpelExpressionParser.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/SpelExpressionParser.java @@ -1,63 +1,63 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel.standard; - -import org.springframework.expression.ParseException; -import org.springframework.expression.ParserContext; -import org.springframework.expression.common.TemplateAwareExpressionParser; -import org.springframework.expression.spel.SpelParserConfiguration; -import org.springframework.util.Assert; - -/** - * SpEL parser. Instances are reusable and thread-safe. - * - * @author Andy Clement - * @author Juergen Hoeller - * @since 3.0 - */ -public class SpelExpressionParser extends TemplateAwareExpressionParser { - - private final SpelParserConfiguration configuration; - - - /** - * Create a parser with standard configuration. - */ - public SpelExpressionParser() { - this.configuration = new SpelParserConfiguration(false, false); - } - - /** - * Create a parser with some configured behavior. - * @param configuration custom configuration options - */ - public SpelExpressionParser(SpelParserConfiguration configuration) { - Assert.notNull(configuration, "SpelParserConfiguration must not be null"); - this.configuration = configuration; - } - - - @Override - protected SpelExpression doParseExpression(String expressionString, ParserContext context) throws ParseException { - return new InternalSpelExpressionParser(this.configuration).doParseExpression(expressionString, context); - } - - public SpelExpression parseRaw(String expressionString) throws ParseException { - return doParseExpression(expressionString, null); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel.standard; + +import org.springframework.expression.ParseException; +import org.springframework.expression.ParserContext; +import org.springframework.expression.common.TemplateAwareExpressionParser; +import org.springframework.expression.spel.SpelParserConfiguration; +import org.springframework.util.Assert; + +/** + * SpEL parser. Instances are reusable and thread-safe. + * + * @author Andy Clement + * @author Juergen Hoeller + * @since 3.0 + */ +public class SpelExpressionParser extends TemplateAwareExpressionParser { + + private final SpelParserConfiguration configuration; + + + /** + * Create a parser with standard configuration. + */ + public SpelExpressionParser() { + this.configuration = new SpelParserConfiguration(false, false); + } + + /** + * Create a parser with some configured behavior. + * @param configuration custom configuration options + */ + public SpelExpressionParser(SpelParserConfiguration configuration) { + Assert.notNull(configuration, "SpelParserConfiguration must not be null"); + this.configuration = configuration; + } + + + @Override + protected SpelExpression doParseExpression(String expressionString, ParserContext context) throws ParseException { + return new InternalSpelExpressionParser(this.configuration).doParseExpression(expressionString, context); + } + + public SpelExpression parseRaw(String expressionString) throws ParseException { + return doParseExpression(expressionString, null); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/Token.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/Token.java index 1700cd6b92..5d3d248fa0 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/Token.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/Token.java @@ -1,87 +1,87 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel.standard; - -/** - * Holder for a kind of token, the associated data and its position in the input data stream (start/end). - * - * @author Andy Clement - * @since 3.0 - */ -class Token { - - TokenKind kind; - String data; - int startpos; // index of first character - int endpos; // index of char after the last character - - /** - * Constructor for use when there is no particular data for the token (eg. TRUE or '+') - * @param startpos the exact start - * @param endpos the index to the last character - */ - Token(TokenKind tokenKind, int startpos, int endpos) { - this.kind = tokenKind; - this.startpos = startpos; - this.endpos = endpos; - } - - Token(TokenKind tokenKind, char[] tokenData, int pos, int endpos) { - this(tokenKind,pos,endpos); - this.data = new String(tokenData); - } - - - public TokenKind getKind() { - return kind; - } - - public String toString() { - StringBuilder s = new StringBuilder(); - s.append("[").append(kind.toString()); - if (kind.hasPayload()) { - s.append(":").append(data); - } - s.append("]"); - s.append("(").append(startpos).append(",").append(endpos).append(")"); - return s.toString(); - } - - public boolean isIdentifier() { - return kind==TokenKind.IDENTIFIER; - } - - public boolean isNumericRelationalOperator() { - return kind==TokenKind.GT || kind==TokenKind.GE || kind==TokenKind.LT || kind==TokenKind.LE || kind==TokenKind.EQ || kind==TokenKind.NE; - } - - public String stringValue() { - return data; - } - - public Token asInstanceOfToken() { - return new Token(TokenKind.INSTANCEOF,startpos,endpos); - } - - public Token asMatchesToken() { - return new Token(TokenKind.MATCHES,startpos,endpos); - } - - public Token asBetweenToken() { - return new Token(TokenKind.BETWEEN,startpos,endpos); - } +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel.standard; + +/** + * Holder for a kind of token, the associated data and its position in the input data stream (start/end). + * + * @author Andy Clement + * @since 3.0 + */ +class Token { + + TokenKind kind; + String data; + int startpos; // index of first character + int endpos; // index of char after the last character + + /** + * Constructor for use when there is no particular data for the token (eg. TRUE or '+') + * @param startpos the exact start + * @param endpos the index to the last character + */ + Token(TokenKind tokenKind, int startpos, int endpos) { + this.kind = tokenKind; + this.startpos = startpos; + this.endpos = endpos; + } + + Token(TokenKind tokenKind, char[] tokenData, int pos, int endpos) { + this(tokenKind,pos,endpos); + this.data = new String(tokenData); + } + + + public TokenKind getKind() { + return kind; + } + + public String toString() { + StringBuilder s = new StringBuilder(); + s.append("[").append(kind.toString()); + if (kind.hasPayload()) { + s.append(":").append(data); + } + s.append("]"); + s.append("(").append(startpos).append(",").append(endpos).append(")"); + return s.toString(); + } + + public boolean isIdentifier() { + return kind==TokenKind.IDENTIFIER; + } + + public boolean isNumericRelationalOperator() { + return kind==TokenKind.GT || kind==TokenKind.GE || kind==TokenKind.LT || kind==TokenKind.LE || kind==TokenKind.EQ || kind==TokenKind.NE; + } + + public String stringValue() { + return data; + } + + public Token asInstanceOfToken() { + return new Token(TokenKind.INSTANCEOF,startpos,endpos); + } + + public Token asMatchesToken() { + return new Token(TokenKind.MATCHES,startpos,endpos); + } + + public Token asBetweenToken() { + return new Token(TokenKind.BETWEEN,startpos,endpos); + } } \ No newline at end of file diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/TokenKind.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/TokenKind.java index c697396175..78be627e7c 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/TokenKind.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/TokenKind.java @@ -1,58 +1,58 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.expression.spel.standard; - -/** - * @author Andy Clement - * @since 3.0 - */ -enum TokenKind { - // ordered by priority - operands first - LITERAL_INT, LITERAL_LONG, LITERAL_HEXINT, LITERAL_HEXLONG, LITERAL_STRING, LITERAL_REAL, LITERAL_REAL_FLOAT, - LPAREN("("), RPAREN(")"), COMMA(","), IDENTIFIER, - COLON(":"),HASH("#"),RSQUARE("]"), LSQUARE("["), - LCURLY("{"),RCURLY("}"), - DOT("."), PLUS("+"), STAR("*"), MINUS("-"), SELECT_FIRST("^["), SELECT_LAST("$["), QMARK("?"), PROJECT("!["), - DIV("/"), GE(">="), GT(">"), LE("<="), LT("<"), EQ("=="), NE("!="), - MOD("%"), NOT("!"), ASSIGN("="), INSTANCEOF("instanceof"), MATCHES("matches"), BETWEEN("between"), - SELECT("?["), POWER("^"), - ELVIS("?:"), SAFE_NAVI("?."), BEAN_REF("@") - ; - - char[] tokenChars; - private boolean hasPayload; // is there more to this token than simply the kind - - private TokenKind(String tokenString) { - tokenChars = tokenString.toCharArray(); - hasPayload = tokenChars.length==0; - } - - private TokenKind() { - this(""); - } - - public String toString() { - return this.name()+(tokenChars.length!=0?"("+new String(tokenChars)+")":""); - } - - public boolean hasPayload() { - return hasPayload; - } - - public int getLength() { - return tokenChars.length; - } +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.expression.spel.standard; + +/** + * @author Andy Clement + * @since 3.0 + */ +enum TokenKind { + // ordered by priority - operands first + LITERAL_INT, LITERAL_LONG, LITERAL_HEXINT, LITERAL_HEXLONG, LITERAL_STRING, LITERAL_REAL, LITERAL_REAL_FLOAT, + LPAREN("("), RPAREN(")"), COMMA(","), IDENTIFIER, + COLON(":"),HASH("#"),RSQUARE("]"), LSQUARE("["), + LCURLY("{"),RCURLY("}"), + DOT("."), PLUS("+"), STAR("*"), MINUS("-"), SELECT_FIRST("^["), SELECT_LAST("$["), QMARK("?"), PROJECT("!["), + DIV("/"), GE(">="), GT(">"), LE("<="), LT("<"), EQ("=="), NE("!="), + MOD("%"), NOT("!"), ASSIGN("="), INSTANCEOF("instanceof"), MATCHES("matches"), BETWEEN("between"), + SELECT("?["), POWER("^"), + ELVIS("?:"), SAFE_NAVI("?."), BEAN_REF("@") + ; + + char[] tokenChars; + private boolean hasPayload; // is there more to this token than simply the kind + + private TokenKind(String tokenString) { + tokenChars = tokenString.toCharArray(); + hasPayload = tokenChars.length==0; + } + + private TokenKind() { + this(""); + } + + public String toString() { + return this.name()+(tokenChars.length!=0?"("+new String(tokenChars)+")":""); + } + + public boolean hasPayload() { + return hasPayload; + } + + public int getLength() { + return tokenChars.length; + } } \ No newline at end of file diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java index 3811fde747..b2e01f90e8 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/Tokenizer.java @@ -1,507 +1,507 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel.standard; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.springframework.expression.spel.InternalParseException; -import org.springframework.expression.spel.SpelMessage; -import org.springframework.expression.spel.SpelParseException; -import org.springframework.util.Assert; - -/** - * Lex some input data into a stream of tokens that can then be parsed. - * - * @author Andy Clement - * @since 3.0 - */ -class Tokenizer { - - String expressionString; - char[] toProcess; - int pos; - int max; - List tokens = new ArrayList(); - - public Tokenizer(String inputdata) { - this.expressionString = inputdata; - this.toProcess = (inputdata+"\0").toCharArray(); - this.max = toProcess.length; - this.pos = 0; - process(); - } - - public void process() { - while (pos': - if (isTwoCharToken(TokenKind.GE)) { - pushPairToken(TokenKind.GE); - } else { - pushCharToken(TokenKind.GT); - } - break; - case '<': - if (isTwoCharToken(TokenKind.LE)) { - pushPairToken(TokenKind.LE); - } else { - pushCharToken(TokenKind.LT); - } - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - lexNumericLiteral(ch=='0'); - break; - case ' ': - case '\t': - case '\r': - case '\n': - // drift over white space - pos++; - break; - case '\'': - lexQuotedStringLiteral(); - break; - case '"': - lexDoubleQuotedStringLiteral(); - break; - case 0: - // hit sentinel at end of value - pos++; // will take us to the end - break; - default: - throw new IllegalStateException("Cannot handle ("+Integer.valueOf(ch)+") '"+ch+"'"); - } - } - } - } - - public List getTokens() { - return tokens; - } - - - // STRING_LITERAL: '\''! (APOS|~'\'')* '\''!; - private void lexQuotedStringLiteral() { - int start = pos; - boolean terminated = false; - while (!terminated) { - pos++; - char ch = toProcess[pos]; - if (ch=='\'') { - // may not be the end if the char after is also a ' - if (toProcess[pos+1]=='\'') { - pos++; // skip over that too, and continue - } else { - terminated = true; - } - } - if (ch==0) { - throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessage.NON_TERMINATING_QUOTED_STRING)); - } - } - pos++; - tokens.add(new Token(TokenKind.LITERAL_STRING, subarray(start,pos), start, pos)); - } - - // DQ_STRING_LITERAL: '"'! (~'"')* '"'!; - private void lexDoubleQuotedStringLiteral() { - int start = pos; - boolean terminated = false; - while (!terminated) { - pos++; - char ch = toProcess[pos]; - if (ch=='"') { - terminated = true; - } - if (ch==0) { - throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessage.NON_TERMINATING_DOUBLE_QUOTED_STRING)); - } - } - pos++; - tokens.add(new Token(TokenKind.LITERAL_STRING, subarray(start,pos), start, pos)); - } - - -// REAL_LITERAL : -// ('.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) | -// ((DECIMAL_DIGIT)+ '.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) | -// ((DECIMAL_DIGIT)+ (EXPONENT_PART) (REAL_TYPE_SUFFIX)?) | -// ((DECIMAL_DIGIT)+ (REAL_TYPE_SUFFIX)); -// fragment INTEGER_TYPE_SUFFIX : ( 'L' | 'l' ); -// fragment HEX_DIGIT : '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'A'|'B'|'C'|'D'|'E'|'F'|'a'|'b'|'c'|'d'|'e'|'f'; -// -// fragment EXPONENT_PART : 'e' (SIGN)* (DECIMAL_DIGIT)+ | 'E' (SIGN)* (DECIMAL_DIGIT)+ ; -// fragment SIGN : '+' | '-' ; -// fragment REAL_TYPE_SUFFIX : 'F' | 'f' | 'D' | 'd'; -// INTEGER_LITERAL -// : (DECIMAL_DIGIT)+ (INTEGER_TYPE_SUFFIX)?; - - private void lexNumericLiteral(boolean firstCharIsZero) { - boolean isReal = false; - int start = pos; - char ch = toProcess[pos+1]; - boolean isHex = ch=='x' || ch=='X'; - - // deal with hexadecimal - if (firstCharIsZero && isHex) { - pos=pos+1; - do { - pos++; - } while (isHexadecimalDigit(toProcess[pos])); - if (isChar('L','l')) { - pushHexIntToken(subarray(start+2,pos),true, start, pos); - pos++; - } else { - pushHexIntToken(subarray(start+2,pos),false, start, pos); - } - return; - } - - // real numbers must have leading digits - - // Consume first part of number - do { - pos++; - } while (isDigit(toProcess[pos])); - - // a '.' indicates this number is a real - ch = toProcess[pos]; - if (ch=='.') { - isReal = true; - // carry on consuming digits - do { - pos++; - } while (isDigit(toProcess[pos])); - } - - int endOfNumber = pos; - - // Now there may or may not be an exponent - - // is it a long ? - if (isChar('L','l')) { - if (isReal) { // 3.4L - not allowed - throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessage.REAL_CANNOT_BE_LONG)); - } - pushIntToken(subarray(start, endOfNumber), true, start, endOfNumber); - pos++; - } else if (isExponentChar(toProcess[pos])) { - isReal = true; // if it wasnt before, it is now - pos++; - char possibleSign = toProcess[pos]; - if (isSign(possibleSign)) { - pos++; - } - - // exponent digits - do { - pos++; - } while (isDigit(toProcess[pos])); - boolean isFloat = false; - if (isFloatSuffix(toProcess[pos])) { - isFloat = true; - endOfNumber = ++pos; - } else if (isDoubleSuffix(toProcess[pos])) { - endOfNumber = ++pos; - } - pushRealToken(subarray(start,pos), isFloat, start, pos); - } else { - ch = toProcess[pos]; - boolean isFloat = false; - if (isFloatSuffix(ch)) { - isReal = true; - isFloat = true; - endOfNumber = ++pos; - } else if (isDoubleSuffix(ch)) { - isReal = true; - endOfNumber = ++pos; - } - if (isReal) { - pushRealToken(subarray(start,endOfNumber), isFloat, start, endOfNumber); - } else { - pushIntToken(subarray(start,endOfNumber), false, start, endOfNumber); - } - } - } - - // if this is changed, it must remain sorted - private static final String[] alternativeOperatorNames = { "DIV","EQ","GE","GT","LE","LT","MOD","NE","NOT"}; - - private void lexIdentifier() { - int start = pos; - do { - pos++; - } while (isIdentifier(toProcess[pos])); - char[] subarray = subarray(start,pos); - - // Check if this is the alternative (textual) representation of an operator (see alternativeOperatorNames) - if ((pos-start)==2 || (pos-start)==3) { - String asString = new String(subarray).toUpperCase(); - int idx = Arrays.binarySearch(alternativeOperatorNames,asString); - if (idx>=0) { - pushOneCharOrTwoCharToken(TokenKind.valueOf(asString),start,subarray); - return; - } - } - tokens.add(new Token(TokenKind.IDENTIFIER,subarray,start,pos)); - } - - private void pushIntToken(char[] data,boolean isLong, int start, int end) { - if (isLong) { - tokens.add(new Token(TokenKind.LITERAL_LONG,data, start, end)); - } else { - tokens.add(new Token(TokenKind.LITERAL_INT,data, start, end)); - } - } - - private void pushHexIntToken(char[] data,boolean isLong, int start, int end) { - if (data.length==0) { - if (isLong) { - throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessage.NOT_A_LONG,expressionString.substring(start,end+1))); - } else { - throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessage.NOT_AN_INTEGER,expressionString.substring(start,end))); - } - } - if (isLong) { - tokens.add(new Token(TokenKind.LITERAL_HEXLONG, data, start, end)); - } else { - tokens.add(new Token(TokenKind.LITERAL_HEXINT, data, start, end)); - } - } - - private void pushRealToken(char[] data, boolean isFloat, int start, int end) { - if (isFloat) { - tokens.add(new Token(TokenKind.LITERAL_REAL_FLOAT, data, start, end)); - } else { - tokens.add(new Token(TokenKind.LITERAL_REAL, data, start, end)); - } - } - - private char[] subarray(int start, int end) { - char[] result = new char[end - start]; - System.arraycopy(toProcess, start, result, 0, end - start); - return result; - } - - /** - * Check if this might be a two character token. - */ - private boolean isTwoCharToken(TokenKind kind) { - Assert.isTrue(kind.tokenChars.length == 2); - Assert.isTrue(toProcess[pos] == kind.tokenChars[0]); - return toProcess[pos+1] == kind.tokenChars[1]; - } - - /** - * Push a token of just one character in length. - */ - private void pushCharToken(TokenKind kind) { - tokens.add(new Token(kind,pos,pos+1)); - pos++; - } - - /** - * Push a token of two characters in length. - */ - private void pushPairToken(TokenKind kind) { - tokens.add(new Token(kind,pos,pos+2)); - pos+=2; - } - - private void pushOneCharOrTwoCharToken(TokenKind kind, int pos, char[] data) { - tokens.add(new Token(kind,data,pos,pos+kind.getLength())); - } - - // ID: ('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'$'|'0'..'9'|DOT_ESCAPED)*; - private boolean isIdentifier(char ch) { - return isAlphabetic(ch) || isDigit(ch) || ch=='_' || ch=='$'; - } - - private boolean isChar(char a,char b) { - char ch = toProcess[pos]; - return ch==a || ch==b; - } - - private boolean isExponentChar(char ch) { - return ch=='e' || ch=='E'; - } - - private boolean isFloatSuffix(char ch) { - return ch=='f' || ch=='F'; - } - - private boolean isDoubleSuffix(char ch) { - return ch=='d' || ch=='D'; - } - - private boolean isSign(char ch) { - return ch=='+' || ch=='-'; - } - - private boolean isDigit(char ch) { - if (ch>255) { - return false; - } - return (flags[ch] & IS_DIGIT)!=0; - } - - private boolean isAlphabetic(char ch) { - if (ch>255) { - return false; - } - return (flags[ch] & IS_ALPHA)!=0; - } - - private boolean isHexadecimalDigit(char ch) { - if (ch>255) { - return false; - } - return (flags[ch] & IS_HEXDIGIT)!=0; - } - - private static final byte flags[] = new byte[256]; - private static final byte IS_DIGIT=0x01; - private static final byte IS_HEXDIGIT=0x02; - private static final byte IS_ALPHA=0x04; - - static { - for (int ch='0';ch<='9';ch++) { - flags[ch]|=IS_DIGIT | IS_HEXDIGIT; - } - for (int ch='A';ch<='F';ch++) { - flags[ch]|= IS_HEXDIGIT; - } - for (int ch='a';ch<='f';ch++) { - flags[ch]|= IS_HEXDIGIT; - } - for (int ch='A';ch<='Z';ch++) { - flags[ch]|= IS_ALPHA; - } - for (int ch='a';ch<='z';ch++) { - flags[ch]|= IS_ALPHA; - } - } - - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel.standard; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.springframework.expression.spel.InternalParseException; +import org.springframework.expression.spel.SpelMessage; +import org.springframework.expression.spel.SpelParseException; +import org.springframework.util.Assert; + +/** + * Lex some input data into a stream of tokens that can then be parsed. + * + * @author Andy Clement + * @since 3.0 + */ +class Tokenizer { + + String expressionString; + char[] toProcess; + int pos; + int max; + List tokens = new ArrayList(); + + public Tokenizer(String inputdata) { + this.expressionString = inputdata; + this.toProcess = (inputdata+"\0").toCharArray(); + this.max = toProcess.length; + this.pos = 0; + process(); + } + + public void process() { + while (pos': + if (isTwoCharToken(TokenKind.GE)) { + pushPairToken(TokenKind.GE); + } else { + pushCharToken(TokenKind.GT); + } + break; + case '<': + if (isTwoCharToken(TokenKind.LE)) { + pushPairToken(TokenKind.LE); + } else { + pushCharToken(TokenKind.LT); + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + lexNumericLiteral(ch=='0'); + break; + case ' ': + case '\t': + case '\r': + case '\n': + // drift over white space + pos++; + break; + case '\'': + lexQuotedStringLiteral(); + break; + case '"': + lexDoubleQuotedStringLiteral(); + break; + case 0: + // hit sentinel at end of value + pos++; // will take us to the end + break; + default: + throw new IllegalStateException("Cannot handle ("+Integer.valueOf(ch)+") '"+ch+"'"); + } + } + } + } + + public List getTokens() { + return tokens; + } + + + // STRING_LITERAL: '\''! (APOS|~'\'')* '\''!; + private void lexQuotedStringLiteral() { + int start = pos; + boolean terminated = false; + while (!terminated) { + pos++; + char ch = toProcess[pos]; + if (ch=='\'') { + // may not be the end if the char after is also a ' + if (toProcess[pos+1]=='\'') { + pos++; // skip over that too, and continue + } else { + terminated = true; + } + } + if (ch==0) { + throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessage.NON_TERMINATING_QUOTED_STRING)); + } + } + pos++; + tokens.add(new Token(TokenKind.LITERAL_STRING, subarray(start,pos), start, pos)); + } + + // DQ_STRING_LITERAL: '"'! (~'"')* '"'!; + private void lexDoubleQuotedStringLiteral() { + int start = pos; + boolean terminated = false; + while (!terminated) { + pos++; + char ch = toProcess[pos]; + if (ch=='"') { + terminated = true; + } + if (ch==0) { + throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessage.NON_TERMINATING_DOUBLE_QUOTED_STRING)); + } + } + pos++; + tokens.add(new Token(TokenKind.LITERAL_STRING, subarray(start,pos), start, pos)); + } + + +// REAL_LITERAL : +// ('.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) | +// ((DECIMAL_DIGIT)+ '.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) | +// ((DECIMAL_DIGIT)+ (EXPONENT_PART) (REAL_TYPE_SUFFIX)?) | +// ((DECIMAL_DIGIT)+ (REAL_TYPE_SUFFIX)); +// fragment INTEGER_TYPE_SUFFIX : ( 'L' | 'l' ); +// fragment HEX_DIGIT : '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'A'|'B'|'C'|'D'|'E'|'F'|'a'|'b'|'c'|'d'|'e'|'f'; +// +// fragment EXPONENT_PART : 'e' (SIGN)* (DECIMAL_DIGIT)+ | 'E' (SIGN)* (DECIMAL_DIGIT)+ ; +// fragment SIGN : '+' | '-' ; +// fragment REAL_TYPE_SUFFIX : 'F' | 'f' | 'D' | 'd'; +// INTEGER_LITERAL +// : (DECIMAL_DIGIT)+ (INTEGER_TYPE_SUFFIX)?; + + private void lexNumericLiteral(boolean firstCharIsZero) { + boolean isReal = false; + int start = pos; + char ch = toProcess[pos+1]; + boolean isHex = ch=='x' || ch=='X'; + + // deal with hexadecimal + if (firstCharIsZero && isHex) { + pos=pos+1; + do { + pos++; + } while (isHexadecimalDigit(toProcess[pos])); + if (isChar('L','l')) { + pushHexIntToken(subarray(start+2,pos),true, start, pos); + pos++; + } else { + pushHexIntToken(subarray(start+2,pos),false, start, pos); + } + return; + } + + // real numbers must have leading digits + + // Consume first part of number + do { + pos++; + } while (isDigit(toProcess[pos])); + + // a '.' indicates this number is a real + ch = toProcess[pos]; + if (ch=='.') { + isReal = true; + // carry on consuming digits + do { + pos++; + } while (isDigit(toProcess[pos])); + } + + int endOfNumber = pos; + + // Now there may or may not be an exponent + + // is it a long ? + if (isChar('L','l')) { + if (isReal) { // 3.4L - not allowed + throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessage.REAL_CANNOT_BE_LONG)); + } + pushIntToken(subarray(start, endOfNumber), true, start, endOfNumber); + pos++; + } else if (isExponentChar(toProcess[pos])) { + isReal = true; // if it wasnt before, it is now + pos++; + char possibleSign = toProcess[pos]; + if (isSign(possibleSign)) { + pos++; + } + + // exponent digits + do { + pos++; + } while (isDigit(toProcess[pos])); + boolean isFloat = false; + if (isFloatSuffix(toProcess[pos])) { + isFloat = true; + endOfNumber = ++pos; + } else if (isDoubleSuffix(toProcess[pos])) { + endOfNumber = ++pos; + } + pushRealToken(subarray(start,pos), isFloat, start, pos); + } else { + ch = toProcess[pos]; + boolean isFloat = false; + if (isFloatSuffix(ch)) { + isReal = true; + isFloat = true; + endOfNumber = ++pos; + } else if (isDoubleSuffix(ch)) { + isReal = true; + endOfNumber = ++pos; + } + if (isReal) { + pushRealToken(subarray(start,endOfNumber), isFloat, start, endOfNumber); + } else { + pushIntToken(subarray(start,endOfNumber), false, start, endOfNumber); + } + } + } + + // if this is changed, it must remain sorted + private static final String[] alternativeOperatorNames = { "DIV","EQ","GE","GT","LE","LT","MOD","NE","NOT"}; + + private void lexIdentifier() { + int start = pos; + do { + pos++; + } while (isIdentifier(toProcess[pos])); + char[] subarray = subarray(start,pos); + + // Check if this is the alternative (textual) representation of an operator (see alternativeOperatorNames) + if ((pos-start)==2 || (pos-start)==3) { + String asString = new String(subarray).toUpperCase(); + int idx = Arrays.binarySearch(alternativeOperatorNames,asString); + if (idx>=0) { + pushOneCharOrTwoCharToken(TokenKind.valueOf(asString),start,subarray); + return; + } + } + tokens.add(new Token(TokenKind.IDENTIFIER,subarray,start,pos)); + } + + private void pushIntToken(char[] data,boolean isLong, int start, int end) { + if (isLong) { + tokens.add(new Token(TokenKind.LITERAL_LONG,data, start, end)); + } else { + tokens.add(new Token(TokenKind.LITERAL_INT,data, start, end)); + } + } + + private void pushHexIntToken(char[] data,boolean isLong, int start, int end) { + if (data.length==0) { + if (isLong) { + throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessage.NOT_A_LONG,expressionString.substring(start,end+1))); + } else { + throw new InternalParseException(new SpelParseException(expressionString,start,SpelMessage.NOT_AN_INTEGER,expressionString.substring(start,end))); + } + } + if (isLong) { + tokens.add(new Token(TokenKind.LITERAL_HEXLONG, data, start, end)); + } else { + tokens.add(new Token(TokenKind.LITERAL_HEXINT, data, start, end)); + } + } + + private void pushRealToken(char[] data, boolean isFloat, int start, int end) { + if (isFloat) { + tokens.add(new Token(TokenKind.LITERAL_REAL_FLOAT, data, start, end)); + } else { + tokens.add(new Token(TokenKind.LITERAL_REAL, data, start, end)); + } + } + + private char[] subarray(int start, int end) { + char[] result = new char[end - start]; + System.arraycopy(toProcess, start, result, 0, end - start); + return result; + } + + /** + * Check if this might be a two character token. + */ + private boolean isTwoCharToken(TokenKind kind) { + Assert.isTrue(kind.tokenChars.length == 2); + Assert.isTrue(toProcess[pos] == kind.tokenChars[0]); + return toProcess[pos+1] == kind.tokenChars[1]; + } + + /** + * Push a token of just one character in length. + */ + private void pushCharToken(TokenKind kind) { + tokens.add(new Token(kind,pos,pos+1)); + pos++; + } + + /** + * Push a token of two characters in length. + */ + private void pushPairToken(TokenKind kind) { + tokens.add(new Token(kind,pos,pos+2)); + pos+=2; + } + + private void pushOneCharOrTwoCharToken(TokenKind kind, int pos, char[] data) { + tokens.add(new Token(kind,data,pos,pos+kind.getLength())); + } + + // ID: ('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'$'|'0'..'9'|DOT_ESCAPED)*; + private boolean isIdentifier(char ch) { + return isAlphabetic(ch) || isDigit(ch) || ch=='_' || ch=='$'; + } + + private boolean isChar(char a,char b) { + char ch = toProcess[pos]; + return ch==a || ch==b; + } + + private boolean isExponentChar(char ch) { + return ch=='e' || ch=='E'; + } + + private boolean isFloatSuffix(char ch) { + return ch=='f' || ch=='F'; + } + + private boolean isDoubleSuffix(char ch) { + return ch=='d' || ch=='D'; + } + + private boolean isSign(char ch) { + return ch=='+' || ch=='-'; + } + + private boolean isDigit(char ch) { + if (ch>255) { + return false; + } + return (flags[ch] & IS_DIGIT)!=0; + } + + private boolean isAlphabetic(char ch) { + if (ch>255) { + return false; + } + return (flags[ch] & IS_ALPHA)!=0; + } + + private boolean isHexadecimalDigit(char ch) { + if (ch>255) { + return false; + } + return (flags[ch] & IS_HEXDIGIT)!=0; + } + + private static final byte flags[] = new byte[256]; + private static final byte IS_DIGIT=0x01; + private static final byte IS_HEXDIGIT=0x02; + private static final byte IS_ALPHA=0x04; + + static { + for (int ch='0';ch<='9';ch++) { + flags[ch]|=IS_DIGIT | IS_HEXDIGIT; + } + for (int ch='A';ch<='F';ch++) { + flags[ch]|= IS_HEXDIGIT; + } + for (int ch='a';ch<='f';ch++) { + flags[ch]|= IS_HEXDIGIT; + } + for (int ch='A';ch<='Z';ch++) { + flags[ch]|= IS_ALPHA; + } + for (int ch='a';ch<='z';ch++) { + flags[ch]|= IS_ALPHA; + } + } + + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/BooleanTypedValue.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/BooleanTypedValue.java index bf350081b5..b397f1ac04 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/BooleanTypedValue.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/BooleanTypedValue.java @@ -1,46 +1,46 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel.support; - -import org.springframework.expression.TypedValue; - -/** - * @author Andy Clement - * @since 3.0 - */ -public class BooleanTypedValue extends TypedValue { - - public static final BooleanTypedValue TRUE = new BooleanTypedValue(true); - - public static final BooleanTypedValue FALSE = new BooleanTypedValue(false); - - - private BooleanTypedValue(boolean b) { - super(b); - } - - - public static BooleanTypedValue forValue(boolean b) { - if (b) { - return TRUE; - } - else { - return FALSE; - } - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel.support; + +import org.springframework.expression.TypedValue; + +/** + * @author Andy Clement + * @since 3.0 + */ +public class BooleanTypedValue extends TypedValue { + + public static final BooleanTypedValue TRUE = new BooleanTypedValue(true); + + public static final BooleanTypedValue FALSE = new BooleanTypedValue(false); + + + private BooleanTypedValue(boolean b) { + super(b); + } + + + public static BooleanTypedValue forValue(boolean b) { + if (b) { + return TRUE; + } + else { + return FALSE; + } + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectionHelper.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectionHelper.java index 9a8a35c60b..40dcbc2ca7 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectionHelper.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectionHelper.java @@ -1,507 +1,507 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel.support; - -import java.lang.reflect.Array; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; - -import org.springframework.core.MethodParameter; -import org.springframework.core.convert.TypeDescriptor; -import org.springframework.expression.EvaluationException; -import org.springframework.expression.TypeConverter; -import org.springframework.expression.spel.SpelEvaluationException; -import org.springframework.expression.spel.SpelMessage; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; -import org.springframework.util.MethodInvoker; - -/** - * Utility methods used by the reflection resolver code to discover the appropriate - * methods/constructors and fields that should be used in expressions. - * - * @author Andy Clement - * @author Juergen Hoeller - * @since 3.0 - */ -public class ReflectionHelper { - - /** - * Compare argument arrays and return information about whether they match. A supplied type converter - * and conversionAllowed flag allow for matches to take into account that a type may be transformed - * into a different type by the converter. - * @param expectedArgTypes the array of types the method/constructor is expecting - * @param suppliedArgTypes the array of types that are being supplied at the point of invocation - * @param typeConverter a registered type converter - * @return a MatchInfo object indicating what kind of match it was or null if it was not a match - */ - static ArgumentsMatchInfo compareArguments( - List expectedArgTypes, List suppliedArgTypes, TypeConverter typeConverter) { - - Assert.isTrue(expectedArgTypes.size() == suppliedArgTypes.size(), - "Expected argument types and supplied argument types should be arrays of same length"); - - ArgsMatchKind match = ArgsMatchKind.EXACT; - List argsRequiringConversion = null; - for (int i = 0; i < expectedArgTypes.size() && match != null; i++) { - TypeDescriptor suppliedArg = suppliedArgTypes.get(i); - TypeDescriptor expectedArg = expectedArgTypes.get(i); - if (!expectedArg.equals(suppliedArg)) { - // The user may supply null - and that will be ok unless a primitive is expected - if (suppliedArg == null) { - if (expectedArg.isPrimitive()) { - match = null; - } - } - else { - if (suppliedArg.isAssignableTo(expectedArg)) { - if (match != ArgsMatchKind.REQUIRES_CONVERSION) { - match = ArgsMatchKind.CLOSE; - } - } - else if (typeConverter.canConvert(suppliedArg, expectedArg)) { - if (argsRequiringConversion == null) { - argsRequiringConversion = new ArrayList(); - } - argsRequiringConversion.add(i); - match = ArgsMatchKind.REQUIRES_CONVERSION; - } - else { - match = null; - } - } - } - } - if (match == null) { - return null; - } - else { - if (match == ArgsMatchKind.REQUIRES_CONVERSION) { - int[] argsArray = new int[argsRequiringConversion.size()]; - for (int i = 0; i < argsRequiringConversion.size(); i++) { - argsArray[i] = argsRequiringConversion.get(i); - } - return new ArgumentsMatchInfo(match, argsArray); - } - else { - return new ArgumentsMatchInfo(match); - } - } - } - - /** - * Based on {@link MethodInvoker#getTypeDifferenceWeight(Class[], Object[])} but operates on TypeDescriptors. - */ - public static int getTypeDifferenceWeight(List paramTypes, List argTypes) { - int result = 0; - for (int i = 0,max=paramTypes.size(); i < max; i++) { - TypeDescriptor argType = argTypes.get(i); - TypeDescriptor paramType = paramTypes.get(i); - if (argType == null) { - if (paramType.isPrimitive()) { - return Integer.MAX_VALUE; - } - } - if (!ClassUtils.isAssignable(paramType.getClass(), argType.getClass())) { - return Integer.MAX_VALUE; - } - if (argType != null) { - Class paramTypeClazz = paramType.getType(); - if (paramTypeClazz.isPrimitive()) { - paramTypeClazz = Object.class; - } - Class superClass = argType.getClass().getSuperclass(); - while (superClass != null) { - if (paramType.equals(superClass)) { - result = result + 2; - superClass = null; - } - else if (ClassUtils.isAssignable(paramTypeClazz, superClass)) { - result = result + 2; - superClass = superClass.getSuperclass(); - } - else { - superClass = null; - } - } - if (paramTypeClazz.isInterface()) { - result = result + 1; - } - } - } - return result; - } - - /** - * Compare argument arrays and return information about whether they match. A supplied type converter and - * conversionAllowed flag allow for matches to take into account that a type may be transformed into a different - * type by the converter. This variant of compareArguments also allows for a varargs match. - * @param expectedArgTypes the array of types the method/constructor is expecting - * @param suppliedArgTypes the array of types that are being supplied at the point of invocation - * @param typeConverter a registered type converter - * @return a MatchInfo object indicating what kind of match it was or null if it was not a match - */ - static ArgumentsMatchInfo compareArgumentsVarargs( - List expectedArgTypes, List suppliedArgTypes, TypeConverter typeConverter) { - - Assert.isTrue(expectedArgTypes != null && expectedArgTypes.size() > 0, - "Expected arguments must at least include one array (the vargargs parameter)"); - Assert.isTrue(expectedArgTypes.get(expectedArgTypes.size() - 1).isArray(), - "Final expected argument should be array type (the varargs parameter)"); - - ArgsMatchKind match = ArgsMatchKind.EXACT; - List argsRequiringConversion = null; - - // Check up until the varargs argument: - - // Deal with the arguments up to 'expected number' - 1 (that is everything but the varargs argument) - int argCountUpToVarargs = expectedArgTypes.size() - 1; - for (int i = 0; i < argCountUpToVarargs && match != null; i++) { - TypeDescriptor suppliedArg = suppliedArgTypes.get(i); - TypeDescriptor expectedArg = expectedArgTypes.get(i); - if (suppliedArg == null) { - if (expectedArg.isPrimitive()) { - match = null; - } - } - else { - if (!expectedArg.equals(suppliedArg)) { - if (suppliedArg.isAssignableTo(expectedArg)) { - if (match != ArgsMatchKind.REQUIRES_CONVERSION) { - match = ArgsMatchKind.CLOSE; - } - } - else if (typeConverter.canConvert(suppliedArg, expectedArg)) { - if (argsRequiringConversion == null) { - argsRequiringConversion = new ArrayList(); - } - argsRequiringConversion.add(i); - match = ArgsMatchKind.REQUIRES_CONVERSION; - } - else { - match = null; - } - } - } - } - // If already confirmed it cannot be a match, then return - if (match == null) { - return null; - } - - if (suppliedArgTypes.size() == expectedArgTypes.size() && - expectedArgTypes.get(expectedArgTypes.size() - 1).equals( - suppliedArgTypes.get(suppliedArgTypes.size() - 1))) { - // Special case: there is one parameter left and it is an array and it matches the varargs - // expected argument - that is a match, the caller has already built the array. Proceed with it. - } - else { - // Now... we have the final argument in the method we are checking as a match and we have 0 or more other - // arguments left to pass to it. - Class varargsParameterType = expectedArgTypes.get(expectedArgTypes.size() - 1).getElementTypeDescriptor().getType(); - - // All remaining parameters must be of this type or convertable to this type - for (int i = expectedArgTypes.size() - 1; i < suppliedArgTypes.size(); i++) { - TypeDescriptor suppliedArg = suppliedArgTypes.get(i); - if (suppliedArg == null) { - if (varargsParameterType.isPrimitive()) { - match = null; - } - } else { - if (varargsParameterType != suppliedArg.getType()) { - if (ClassUtils.isAssignable(varargsParameterType, suppliedArg.getType())) { - if (match != ArgsMatchKind.REQUIRES_CONVERSION) { - match = ArgsMatchKind.CLOSE; - } - } - else if (typeConverter.canConvert(suppliedArg, TypeDescriptor.valueOf(varargsParameterType))) { - if (argsRequiringConversion == null) { - argsRequiringConversion = new ArrayList(); - } - argsRequiringConversion.add(i); - match = ArgsMatchKind.REQUIRES_CONVERSION; - } - else { - match = null; - } - } - } - } - } - - if (match == null) { - return null; - } - else { - if (match == ArgsMatchKind.REQUIRES_CONVERSION) { - int[] argsArray = new int[argsRequiringConversion.size()]; - for (int i = 0; i < argsRequiringConversion.size(); i++) { - argsArray[i] = argsRequiringConversion.get(i); - } - return new ArgumentsMatchInfo(match, argsArray); - } - else { - return new ArgumentsMatchInfo(match); - } - } - } - - /** - * Takes an input set of argument values and, following the positions specified in the int array, - * it converts them to the types specified as the required parameter types. The arguments are - * converted 'in-place' in the input array. - * @param converter the type converter to use for attempting conversions - * @param arguments the actual arguments that need conversion - * @param methodOrCtor the target Method or Constructor - * @param argumentsRequiringConversion details which of the input arguments for sure need conversion - * @param varargsPosition the known position of the varargs argument, if any - * @throws EvaluationException if a problem occurs during conversion - */ - static void convertArguments(TypeConverter converter, Object[] arguments, Object methodOrCtor, - int[] argumentsRequiringConversion, Integer varargsPosition) throws EvaluationException { - if (varargsPosition == null) { - for (int i = 0; i < arguments.length; i++) { - TypeDescriptor targetType = new TypeDescriptor(MethodParameter.forMethodOrConstructor(methodOrCtor, i)); - Object argument = arguments[i]; - arguments[i] = converter.convertValue(argument, TypeDescriptor.forObject(argument), targetType); - } - } else { - for (int i = 0; i < varargsPosition; i++) { - TypeDescriptor targetType = new TypeDescriptor(MethodParameter.forMethodOrConstructor(methodOrCtor, i)); - Object argument = arguments[i]; - arguments[i] = converter.convertValue(argument, TypeDescriptor.forObject(argument), targetType); - } - MethodParameter methodParam = MethodParameter.forMethodOrConstructor(methodOrCtor, varargsPosition); - if (varargsPosition == arguments.length - 1) { - TypeDescriptor targetType = new TypeDescriptor(methodParam); - Object argument = arguments[varargsPosition]; - arguments[varargsPosition] = converter.convertValue(argument, TypeDescriptor.forObject(argument), targetType); - } else { - TypeDescriptor targetType = TypeDescriptor.nested(methodParam, 1); - for (int i = varargsPosition; i < arguments.length; i++) { - Object argument = arguments[i]; - arguments[i] = converter.convertValue(argument, TypeDescriptor.forObject(argument), targetType); - } - } - } - } - - /** - * Convert a supplied set of arguments into the requested types. If the parameterTypes are related to - * a varargs method then the final entry in the parameterTypes array is going to be an array itself whose - * component type should be used as the conversion target for extraneous arguments. (For example, if the - * parameterTypes are {Integer, String[]} and the input arguments are {Integer, boolean, float} then both - * the boolean and float must be converted to strings). This method does not repackage the arguments - * into a form suitable for the varargs invocation - * @param converter the converter to use for type conversions - * @param arguments the arguments to convert to the requested parameter types - * @param method the target Method - * @throws SpelEvaluationException if there is a problem with conversion - */ - public static void convertAllArguments(TypeConverter converter, Object[] arguments, Method method) throws SpelEvaluationException { - Integer varargsPosition = null; - if (method.isVarArgs()) { - Class[] paramTypes = method.getParameterTypes(); - varargsPosition = paramTypes.length - 1; - } - for (int argPosition = 0; argPosition < arguments.length; argPosition++) { - TypeDescriptor targetType; - if (varargsPosition != null && argPosition >= varargsPosition) { - MethodParameter methodParam = new MethodParameter(method, varargsPosition); - targetType = TypeDescriptor.nested(methodParam, 1); - } - else { - targetType = new TypeDescriptor(new MethodParameter(method, argPosition)); - } - try { - Object argument = arguments[argPosition]; - if (argument != null && !targetType.getObjectType().isInstance(argument)) { - if (converter == null) { - throw new SpelEvaluationException(SpelMessage.TYPE_CONVERSION_ERROR, argument.getClass().getName(), targetType); - } - arguments[argPosition] = converter.convertValue(argument, TypeDescriptor.forObject(argument), targetType); - } - } - catch (EvaluationException ex) { - // allows for another type converter throwing a different kind of EvaluationException - if (ex instanceof SpelEvaluationException) { - throw (SpelEvaluationException)ex; - } - else { - throw new SpelEvaluationException(ex, SpelMessage.TYPE_CONVERSION_ERROR,arguments[argPosition].getClass().getName(), targetType); - } - } - } - } - - /** - * Package up the arguments so that they correctly match what is expected in parameterTypes. For example, if - * parameterTypes is (int, String[]) because the second parameter was declared String... then if arguments is - * [1,"a","b"] then it must be repackaged as [1,new String[]{"a","b"}] in order to match the expected - * parameterTypes. - * @param requiredParameterTypes the types of the parameters for the invocation - * @param args the arguments to be setup ready for the invocation - * @return a repackaged array of arguments where any varargs setup has been done - */ - public static Object[] setupArgumentsForVarargsInvocation(Class[] requiredParameterTypes, Object... args) { - // Check if array already built for final argument - int parameterCount = requiredParameterTypes.length; - int argumentCount = args.length; - - // Check if repackaging is needed: - if (parameterCount != args.length || - requiredParameterTypes[parameterCount - 1] != - (args[argumentCount - 1] == null ? null : args[argumentCount - 1].getClass())) { - int arraySize = 0; // zero size array if nothing to pass as the varargs parameter - if (argumentCount >= parameterCount) { - arraySize = argumentCount - (parameterCount - 1); - } - - // Create an array for the varargs arguments - Object[] newArgs = new Object[parameterCount]; - for (int i = 0; i < newArgs.length - 1; i++) { - newArgs[i] = args[i]; - } - // Now sort out the final argument, which is the varargs one. Before entering this - // method the arguments should have been converted to the box form of the required type. - Class componentType = requiredParameterTypes[parameterCount-1].getComponentType(); - if (componentType.isPrimitive()) { - if (componentType==Integer.TYPE) { - int[] repackagedArguments = (int[]) Array.newInstance(componentType, arraySize); - for (int i = 0; i < arraySize; i++) { - repackagedArguments[i] = ((Integer)args[parameterCount + i - 1]).intValue(); - } - newArgs[newArgs.length - 1] = repackagedArguments; - } else if(componentType==Float.TYPE) { - float[] repackagedArguments = (float[]) Array.newInstance(componentType, arraySize); - for (int i = 0; i < arraySize; i++) { - repackagedArguments[i] = ((Float)args[parameterCount + i - 1]).floatValue(); - } - newArgs[newArgs.length - 1] = repackagedArguments; - } else if(componentType==Double.TYPE) { - double[] repackagedArguments = (double[]) Array.newInstance(componentType, arraySize); - for (int i = 0; i < arraySize; i++) { - repackagedArguments[i] = ((Double)args[parameterCount + i - 1]).doubleValue(); - } - newArgs[newArgs.length - 1] = repackagedArguments; - } else if(componentType==Short.TYPE) { - short[] repackagedArguments = (short[]) Array.newInstance(componentType, arraySize); - for (int i = 0; i < arraySize; i++) { - repackagedArguments[i] = ((Short)args[parameterCount + i - 1]).shortValue(); - } - newArgs[newArgs.length - 1] = repackagedArguments; - } else if(componentType==Character.TYPE) { - char[] repackagedArguments = (char[]) Array.newInstance(componentType, arraySize); - for (int i = 0; i < arraySize; i++) { - repackagedArguments[i] = ((Character)args[parameterCount + i - 1]).charValue(); - } - newArgs[newArgs.length - 1] = repackagedArguments; - } else if(componentType==Byte.TYPE) { - byte[] repackagedArguments = (byte[]) Array.newInstance(componentType, arraySize); - for (int i = 0; i < arraySize; i++) { - repackagedArguments[i] = ((Byte)args[parameterCount + i - 1]).byteValue(); - } - newArgs[newArgs.length - 1] = repackagedArguments; - } else if(componentType==Boolean.TYPE) { - boolean[] repackagedArguments = (boolean[]) Array.newInstance(componentType, arraySize); - for (int i = 0; i < arraySize; i++) { - repackagedArguments[i] = ((Boolean)args[parameterCount + i - 1]).booleanValue(); - } - newArgs[newArgs.length - 1] = repackagedArguments; - } else if(componentType==Long.TYPE) { - long[] repackagedArguments = (long[]) Array.newInstance(componentType, arraySize); - for (int i = 0; i < arraySize; i++) { - repackagedArguments[i] = ((Long)args[parameterCount + i - 1]).longValue(); - } - newArgs[newArgs.length - 1] = repackagedArguments; - } - } else { - Object[] repackagedArguments = (Object[]) Array.newInstance(componentType, arraySize); - // Copy all but the varargs arguments - for (int i = 0; i < arraySize; i++) { - repackagedArguments[i] = args[parameterCount + i - 1]; - } - newArgs[newArgs.length - 1] = repackagedArguments; - } - return newArgs; - } - return args; - } - - - public static enum ArgsMatchKind { - // An exact match is where the parameter types exactly match what the method/constructor being invoked is expecting - EXACT, - // A close match is where the parameter types either exactly match or are assignment compatible with the method/constructor being invoked - CLOSE, - // A conversion match is where the type converter must be used to transform some of the parameter types - REQUIRES_CONVERSION - } - - - /** - * An instance of ArgumentsMatchInfo describes what kind of match was achieved between two sets of arguments - the set that a - * method/constructor is expecting and the set that are being supplied at the point of invocation. If the kind - * indicates that conversion is required for some of the arguments then the arguments that require conversion are - * listed in the argsRequiringConversion array. - */ - public static class ArgumentsMatchInfo { - - public final ArgsMatchKind kind; - - public int[] argsRequiringConversion; - - ArgumentsMatchInfo(ArgsMatchKind kind, int[] integers) { - this.kind = kind; - this.argsRequiringConversion = integers; - } - - ArgumentsMatchInfo(ArgsMatchKind kind) { - this.kind = kind; - } - - public boolean isExactMatch() { - return (this.kind == ArgsMatchKind.EXACT); - } - - public boolean isCloseMatch() { - return (this.kind == ArgsMatchKind.CLOSE); - } - - public boolean isMatchRequiringConversion() { - return (this.kind == ArgsMatchKind.REQUIRES_CONVERSION); - } - - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("ArgumentMatch: ").append(this.kind); - if (this.argsRequiringConversion != null) { - sb.append(" (argsForConversion:"); - for (int i = 0; i < this.argsRequiringConversion.length;i++) { - if (i > 0) { - sb.append(","); - } - sb.append(this.argsRequiringConversion[i]); - } - sb.append(")"); - } - return sb.toString(); - } - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel.support; + +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import org.springframework.core.MethodParameter; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.TypeConverter; +import org.springframework.expression.spel.SpelEvaluationException; +import org.springframework.expression.spel.SpelMessage; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.MethodInvoker; + +/** + * Utility methods used by the reflection resolver code to discover the appropriate + * methods/constructors and fields that should be used in expressions. + * + * @author Andy Clement + * @author Juergen Hoeller + * @since 3.0 + */ +public class ReflectionHelper { + + /** + * Compare argument arrays and return information about whether they match. A supplied type converter + * and conversionAllowed flag allow for matches to take into account that a type may be transformed + * into a different type by the converter. + * @param expectedArgTypes the array of types the method/constructor is expecting + * @param suppliedArgTypes the array of types that are being supplied at the point of invocation + * @param typeConverter a registered type converter + * @return a MatchInfo object indicating what kind of match it was or null if it was not a match + */ + static ArgumentsMatchInfo compareArguments( + List expectedArgTypes, List suppliedArgTypes, TypeConverter typeConverter) { + + Assert.isTrue(expectedArgTypes.size() == suppliedArgTypes.size(), + "Expected argument types and supplied argument types should be arrays of same length"); + + ArgsMatchKind match = ArgsMatchKind.EXACT; + List argsRequiringConversion = null; + for (int i = 0; i < expectedArgTypes.size() && match != null; i++) { + TypeDescriptor suppliedArg = suppliedArgTypes.get(i); + TypeDescriptor expectedArg = expectedArgTypes.get(i); + if (!expectedArg.equals(suppliedArg)) { + // The user may supply null - and that will be ok unless a primitive is expected + if (suppliedArg == null) { + if (expectedArg.isPrimitive()) { + match = null; + } + } + else { + if (suppliedArg.isAssignableTo(expectedArg)) { + if (match != ArgsMatchKind.REQUIRES_CONVERSION) { + match = ArgsMatchKind.CLOSE; + } + } + else if (typeConverter.canConvert(suppliedArg, expectedArg)) { + if (argsRequiringConversion == null) { + argsRequiringConversion = new ArrayList(); + } + argsRequiringConversion.add(i); + match = ArgsMatchKind.REQUIRES_CONVERSION; + } + else { + match = null; + } + } + } + } + if (match == null) { + return null; + } + else { + if (match == ArgsMatchKind.REQUIRES_CONVERSION) { + int[] argsArray = new int[argsRequiringConversion.size()]; + for (int i = 0; i < argsRequiringConversion.size(); i++) { + argsArray[i] = argsRequiringConversion.get(i); + } + return new ArgumentsMatchInfo(match, argsArray); + } + else { + return new ArgumentsMatchInfo(match); + } + } + } + + /** + * Based on {@link MethodInvoker#getTypeDifferenceWeight(Class[], Object[])} but operates on TypeDescriptors. + */ + public static int getTypeDifferenceWeight(List paramTypes, List argTypes) { + int result = 0; + for (int i = 0,max=paramTypes.size(); i < max; i++) { + TypeDescriptor argType = argTypes.get(i); + TypeDescriptor paramType = paramTypes.get(i); + if (argType == null) { + if (paramType.isPrimitive()) { + return Integer.MAX_VALUE; + } + } + if (!ClassUtils.isAssignable(paramType.getClass(), argType.getClass())) { + return Integer.MAX_VALUE; + } + if (argType != null) { + Class paramTypeClazz = paramType.getType(); + if (paramTypeClazz.isPrimitive()) { + paramTypeClazz = Object.class; + } + Class superClass = argType.getClass().getSuperclass(); + while (superClass != null) { + if (paramType.equals(superClass)) { + result = result + 2; + superClass = null; + } + else if (ClassUtils.isAssignable(paramTypeClazz, superClass)) { + result = result + 2; + superClass = superClass.getSuperclass(); + } + else { + superClass = null; + } + } + if (paramTypeClazz.isInterface()) { + result = result + 1; + } + } + } + return result; + } + + /** + * Compare argument arrays and return information about whether they match. A supplied type converter and + * conversionAllowed flag allow for matches to take into account that a type may be transformed into a different + * type by the converter. This variant of compareArguments also allows for a varargs match. + * @param expectedArgTypes the array of types the method/constructor is expecting + * @param suppliedArgTypes the array of types that are being supplied at the point of invocation + * @param typeConverter a registered type converter + * @return a MatchInfo object indicating what kind of match it was or null if it was not a match + */ + static ArgumentsMatchInfo compareArgumentsVarargs( + List expectedArgTypes, List suppliedArgTypes, TypeConverter typeConverter) { + + Assert.isTrue(expectedArgTypes != null && expectedArgTypes.size() > 0, + "Expected arguments must at least include one array (the vargargs parameter)"); + Assert.isTrue(expectedArgTypes.get(expectedArgTypes.size() - 1).isArray(), + "Final expected argument should be array type (the varargs parameter)"); + + ArgsMatchKind match = ArgsMatchKind.EXACT; + List argsRequiringConversion = null; + + // Check up until the varargs argument: + + // Deal with the arguments up to 'expected number' - 1 (that is everything but the varargs argument) + int argCountUpToVarargs = expectedArgTypes.size() - 1; + for (int i = 0; i < argCountUpToVarargs && match != null; i++) { + TypeDescriptor suppliedArg = suppliedArgTypes.get(i); + TypeDescriptor expectedArg = expectedArgTypes.get(i); + if (suppliedArg == null) { + if (expectedArg.isPrimitive()) { + match = null; + } + } + else { + if (!expectedArg.equals(suppliedArg)) { + if (suppliedArg.isAssignableTo(expectedArg)) { + if (match != ArgsMatchKind.REQUIRES_CONVERSION) { + match = ArgsMatchKind.CLOSE; + } + } + else if (typeConverter.canConvert(suppliedArg, expectedArg)) { + if (argsRequiringConversion == null) { + argsRequiringConversion = new ArrayList(); + } + argsRequiringConversion.add(i); + match = ArgsMatchKind.REQUIRES_CONVERSION; + } + else { + match = null; + } + } + } + } + // If already confirmed it cannot be a match, then return + if (match == null) { + return null; + } + + if (suppliedArgTypes.size() == expectedArgTypes.size() && + expectedArgTypes.get(expectedArgTypes.size() - 1).equals( + suppliedArgTypes.get(suppliedArgTypes.size() - 1))) { + // Special case: there is one parameter left and it is an array and it matches the varargs + // expected argument - that is a match, the caller has already built the array. Proceed with it. + } + else { + // Now... we have the final argument in the method we are checking as a match and we have 0 or more other + // arguments left to pass to it. + Class varargsParameterType = expectedArgTypes.get(expectedArgTypes.size() - 1).getElementTypeDescriptor().getType(); + + // All remaining parameters must be of this type or convertable to this type + for (int i = expectedArgTypes.size() - 1; i < suppliedArgTypes.size(); i++) { + TypeDescriptor suppliedArg = suppliedArgTypes.get(i); + if (suppliedArg == null) { + if (varargsParameterType.isPrimitive()) { + match = null; + } + } else { + if (varargsParameterType != suppliedArg.getType()) { + if (ClassUtils.isAssignable(varargsParameterType, suppliedArg.getType())) { + if (match != ArgsMatchKind.REQUIRES_CONVERSION) { + match = ArgsMatchKind.CLOSE; + } + } + else if (typeConverter.canConvert(suppliedArg, TypeDescriptor.valueOf(varargsParameterType))) { + if (argsRequiringConversion == null) { + argsRequiringConversion = new ArrayList(); + } + argsRequiringConversion.add(i); + match = ArgsMatchKind.REQUIRES_CONVERSION; + } + else { + match = null; + } + } + } + } + } + + if (match == null) { + return null; + } + else { + if (match == ArgsMatchKind.REQUIRES_CONVERSION) { + int[] argsArray = new int[argsRequiringConversion.size()]; + for (int i = 0; i < argsRequiringConversion.size(); i++) { + argsArray[i] = argsRequiringConversion.get(i); + } + return new ArgumentsMatchInfo(match, argsArray); + } + else { + return new ArgumentsMatchInfo(match); + } + } + } + + /** + * Takes an input set of argument values and, following the positions specified in the int array, + * it converts them to the types specified as the required parameter types. The arguments are + * converted 'in-place' in the input array. + * @param converter the type converter to use for attempting conversions + * @param arguments the actual arguments that need conversion + * @param methodOrCtor the target Method or Constructor + * @param argumentsRequiringConversion details which of the input arguments for sure need conversion + * @param varargsPosition the known position of the varargs argument, if any + * @throws EvaluationException if a problem occurs during conversion + */ + static void convertArguments(TypeConverter converter, Object[] arguments, Object methodOrCtor, + int[] argumentsRequiringConversion, Integer varargsPosition) throws EvaluationException { + if (varargsPosition == null) { + for (int i = 0; i < arguments.length; i++) { + TypeDescriptor targetType = new TypeDescriptor(MethodParameter.forMethodOrConstructor(methodOrCtor, i)); + Object argument = arguments[i]; + arguments[i] = converter.convertValue(argument, TypeDescriptor.forObject(argument), targetType); + } + } else { + for (int i = 0; i < varargsPosition; i++) { + TypeDescriptor targetType = new TypeDescriptor(MethodParameter.forMethodOrConstructor(methodOrCtor, i)); + Object argument = arguments[i]; + arguments[i] = converter.convertValue(argument, TypeDescriptor.forObject(argument), targetType); + } + MethodParameter methodParam = MethodParameter.forMethodOrConstructor(methodOrCtor, varargsPosition); + if (varargsPosition == arguments.length - 1) { + TypeDescriptor targetType = new TypeDescriptor(methodParam); + Object argument = arguments[varargsPosition]; + arguments[varargsPosition] = converter.convertValue(argument, TypeDescriptor.forObject(argument), targetType); + } else { + TypeDescriptor targetType = TypeDescriptor.nested(methodParam, 1); + for (int i = varargsPosition; i < arguments.length; i++) { + Object argument = arguments[i]; + arguments[i] = converter.convertValue(argument, TypeDescriptor.forObject(argument), targetType); + } + } + } + } + + /** + * Convert a supplied set of arguments into the requested types. If the parameterTypes are related to + * a varargs method then the final entry in the parameterTypes array is going to be an array itself whose + * component type should be used as the conversion target for extraneous arguments. (For example, if the + * parameterTypes are {Integer, String[]} and the input arguments are {Integer, boolean, float} then both + * the boolean and float must be converted to strings). This method does not repackage the arguments + * into a form suitable for the varargs invocation + * @param converter the converter to use for type conversions + * @param arguments the arguments to convert to the requested parameter types + * @param method the target Method + * @throws SpelEvaluationException if there is a problem with conversion + */ + public static void convertAllArguments(TypeConverter converter, Object[] arguments, Method method) throws SpelEvaluationException { + Integer varargsPosition = null; + if (method.isVarArgs()) { + Class[] paramTypes = method.getParameterTypes(); + varargsPosition = paramTypes.length - 1; + } + for (int argPosition = 0; argPosition < arguments.length; argPosition++) { + TypeDescriptor targetType; + if (varargsPosition != null && argPosition >= varargsPosition) { + MethodParameter methodParam = new MethodParameter(method, varargsPosition); + targetType = TypeDescriptor.nested(methodParam, 1); + } + else { + targetType = new TypeDescriptor(new MethodParameter(method, argPosition)); + } + try { + Object argument = arguments[argPosition]; + if (argument != null && !targetType.getObjectType().isInstance(argument)) { + if (converter == null) { + throw new SpelEvaluationException(SpelMessage.TYPE_CONVERSION_ERROR, argument.getClass().getName(), targetType); + } + arguments[argPosition] = converter.convertValue(argument, TypeDescriptor.forObject(argument), targetType); + } + } + catch (EvaluationException ex) { + // allows for another type converter throwing a different kind of EvaluationException + if (ex instanceof SpelEvaluationException) { + throw (SpelEvaluationException)ex; + } + else { + throw new SpelEvaluationException(ex, SpelMessage.TYPE_CONVERSION_ERROR,arguments[argPosition].getClass().getName(), targetType); + } + } + } + } + + /** + * Package up the arguments so that they correctly match what is expected in parameterTypes. For example, if + * parameterTypes is (int, String[]) because the second parameter was declared String... then if arguments is + * [1,"a","b"] then it must be repackaged as [1,new String[]{"a","b"}] in order to match the expected + * parameterTypes. + * @param requiredParameterTypes the types of the parameters for the invocation + * @param args the arguments to be setup ready for the invocation + * @return a repackaged array of arguments where any varargs setup has been done + */ + public static Object[] setupArgumentsForVarargsInvocation(Class[] requiredParameterTypes, Object... args) { + // Check if array already built for final argument + int parameterCount = requiredParameterTypes.length; + int argumentCount = args.length; + + // Check if repackaging is needed: + if (parameterCount != args.length || + requiredParameterTypes[parameterCount - 1] != + (args[argumentCount - 1] == null ? null : args[argumentCount - 1].getClass())) { + int arraySize = 0; // zero size array if nothing to pass as the varargs parameter + if (argumentCount >= parameterCount) { + arraySize = argumentCount - (parameterCount - 1); + } + + // Create an array for the varargs arguments + Object[] newArgs = new Object[parameterCount]; + for (int i = 0; i < newArgs.length - 1; i++) { + newArgs[i] = args[i]; + } + // Now sort out the final argument, which is the varargs one. Before entering this + // method the arguments should have been converted to the box form of the required type. + Class componentType = requiredParameterTypes[parameterCount-1].getComponentType(); + if (componentType.isPrimitive()) { + if (componentType==Integer.TYPE) { + int[] repackagedArguments = (int[]) Array.newInstance(componentType, arraySize); + for (int i = 0; i < arraySize; i++) { + repackagedArguments[i] = ((Integer)args[parameterCount + i - 1]).intValue(); + } + newArgs[newArgs.length - 1] = repackagedArguments; + } else if(componentType==Float.TYPE) { + float[] repackagedArguments = (float[]) Array.newInstance(componentType, arraySize); + for (int i = 0; i < arraySize; i++) { + repackagedArguments[i] = ((Float)args[parameterCount + i - 1]).floatValue(); + } + newArgs[newArgs.length - 1] = repackagedArguments; + } else if(componentType==Double.TYPE) { + double[] repackagedArguments = (double[]) Array.newInstance(componentType, arraySize); + for (int i = 0; i < arraySize; i++) { + repackagedArguments[i] = ((Double)args[parameterCount + i - 1]).doubleValue(); + } + newArgs[newArgs.length - 1] = repackagedArguments; + } else if(componentType==Short.TYPE) { + short[] repackagedArguments = (short[]) Array.newInstance(componentType, arraySize); + for (int i = 0; i < arraySize; i++) { + repackagedArguments[i] = ((Short)args[parameterCount + i - 1]).shortValue(); + } + newArgs[newArgs.length - 1] = repackagedArguments; + } else if(componentType==Character.TYPE) { + char[] repackagedArguments = (char[]) Array.newInstance(componentType, arraySize); + for (int i = 0; i < arraySize; i++) { + repackagedArguments[i] = ((Character)args[parameterCount + i - 1]).charValue(); + } + newArgs[newArgs.length - 1] = repackagedArguments; + } else if(componentType==Byte.TYPE) { + byte[] repackagedArguments = (byte[]) Array.newInstance(componentType, arraySize); + for (int i = 0; i < arraySize; i++) { + repackagedArguments[i] = ((Byte)args[parameterCount + i - 1]).byteValue(); + } + newArgs[newArgs.length - 1] = repackagedArguments; + } else if(componentType==Boolean.TYPE) { + boolean[] repackagedArguments = (boolean[]) Array.newInstance(componentType, arraySize); + for (int i = 0; i < arraySize; i++) { + repackagedArguments[i] = ((Boolean)args[parameterCount + i - 1]).booleanValue(); + } + newArgs[newArgs.length - 1] = repackagedArguments; + } else if(componentType==Long.TYPE) { + long[] repackagedArguments = (long[]) Array.newInstance(componentType, arraySize); + for (int i = 0; i < arraySize; i++) { + repackagedArguments[i] = ((Long)args[parameterCount + i - 1]).longValue(); + } + newArgs[newArgs.length - 1] = repackagedArguments; + } + } else { + Object[] repackagedArguments = (Object[]) Array.newInstance(componentType, arraySize); + // Copy all but the varargs arguments + for (int i = 0; i < arraySize; i++) { + repackagedArguments[i] = args[parameterCount + i - 1]; + } + newArgs[newArgs.length - 1] = repackagedArguments; + } + return newArgs; + } + return args; + } + + + public static enum ArgsMatchKind { + // An exact match is where the parameter types exactly match what the method/constructor being invoked is expecting + EXACT, + // A close match is where the parameter types either exactly match or are assignment compatible with the method/constructor being invoked + CLOSE, + // A conversion match is where the type converter must be used to transform some of the parameter types + REQUIRES_CONVERSION + } + + + /** + * An instance of ArgumentsMatchInfo describes what kind of match was achieved between two sets of arguments - the set that a + * method/constructor is expecting and the set that are being supplied at the point of invocation. If the kind + * indicates that conversion is required for some of the arguments then the arguments that require conversion are + * listed in the argsRequiringConversion array. + */ + public static class ArgumentsMatchInfo { + + public final ArgsMatchKind kind; + + public int[] argsRequiringConversion; + + ArgumentsMatchInfo(ArgsMatchKind kind, int[] integers) { + this.kind = kind; + this.argsRequiringConversion = integers; + } + + ArgumentsMatchInfo(ArgsMatchKind kind) { + this.kind = kind; + } + + public boolean isExactMatch() { + return (this.kind == ArgsMatchKind.EXACT); + } + + public boolean isCloseMatch() { + return (this.kind == ArgsMatchKind.CLOSE); + } + + public boolean isMatchRequiringConversion() { + return (this.kind == ArgsMatchKind.REQUIRES_CONVERSION); + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("ArgumentMatch: ").append(this.kind); + if (this.argsRequiringConversion != null) { + sb.append(" (argsForConversion:"); + for (int i = 0; i < this.argsRequiringConversion.length;i++) { + if (i > 0) { + sb.append(","); + } + sb.append(this.argsRequiringConversion[i]); + } + sb.append(")"); + } + return sb.toString(); + } + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorExecutor.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorExecutor.java index 6623f45f45..6c1d3c5a17 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorExecutor.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorExecutor.java @@ -1,74 +1,74 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel.support; - -import java.lang.reflect.Constructor; - -import org.springframework.expression.AccessException; -import org.springframework.expression.ConstructorExecutor; -import org.springframework.expression.EvaluationContext; -import org.springframework.expression.TypedValue; -import org.springframework.util.ReflectionUtils; - -/** - * A simple ConstructorExecutor implementation that runs a constructor using reflective invocation. - * - * @author Andy Clement - * @author Juergen Hoeller - * @since 3.0 - */ -class ReflectiveConstructorExecutor implements ConstructorExecutor { - - private final Constructor ctor; - - private final Integer varargsPosition; - - // When the constructor was found, we will have determined if arguments need to be converted for it - // to be invoked. Conversion won't be cheap so let's only do it if necessary. - private final int[] argsRequiringConversion; - - - public ReflectiveConstructorExecutor(Constructor ctor, int[] argsRequiringConversion) { - this.ctor = ctor; - if (ctor.isVarArgs()) { - Class[] paramTypes = ctor.getParameterTypes(); - this.varargsPosition = paramTypes.length - 1; - } - else { - this.varargsPosition = null; - } - this.argsRequiringConversion = argsRequiringConversion; - } - - public TypedValue execute(EvaluationContext context, Object... arguments) throws AccessException { - try { - if (arguments != null) { - ReflectionHelper.convertArguments(context.getTypeConverter(), arguments, - this.ctor, this.argsRequiringConversion, this.varargsPosition); - } - if (this.ctor.isVarArgs()) { - arguments = ReflectionHelper.setupArgumentsForVarargsInvocation(this.ctor.getParameterTypes(), arguments); - } - ReflectionUtils.makeAccessible(this.ctor); - return new TypedValue(this.ctor.newInstance(arguments)); - } - catch (Exception ex) { - throw new AccessException("Problem invoking constructor: " + this.ctor, ex); - } - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel.support; + +import java.lang.reflect.Constructor; + +import org.springframework.expression.AccessException; +import org.springframework.expression.ConstructorExecutor; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.TypedValue; +import org.springframework.util.ReflectionUtils; + +/** + * A simple ConstructorExecutor implementation that runs a constructor using reflective invocation. + * + * @author Andy Clement + * @author Juergen Hoeller + * @since 3.0 + */ +class ReflectiveConstructorExecutor implements ConstructorExecutor { + + private final Constructor ctor; + + private final Integer varargsPosition; + + // When the constructor was found, we will have determined if arguments need to be converted for it + // to be invoked. Conversion won't be cheap so let's only do it if necessary. + private final int[] argsRequiringConversion; + + + public ReflectiveConstructorExecutor(Constructor ctor, int[] argsRequiringConversion) { + this.ctor = ctor; + if (ctor.isVarArgs()) { + Class[] paramTypes = ctor.getParameterTypes(); + this.varargsPosition = paramTypes.length - 1; + } + else { + this.varargsPosition = null; + } + this.argsRequiringConversion = argsRequiringConversion; + } + + public TypedValue execute(EvaluationContext context, Object... arguments) throws AccessException { + try { + if (arguments != null) { + ReflectionHelper.convertArguments(context.getTypeConverter(), arguments, + this.ctor, this.argsRequiringConversion, this.varargsPosition); + } + if (this.ctor.isVarArgs()) { + arguments = ReflectionHelper.setupArgumentsForVarargsInvocation(this.ctor.getParameterTypes(), arguments); + } + ReflectionUtils.makeAccessible(this.ctor); + return new TypedValue(this.ctor.newInstance(arguments)); + } + catch (Exception ex) { + throw new AccessException("Problem invoking constructor: " + this.ctor, ex); + } + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorResolver.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorResolver.java index 91efdd2536..a2768fc099 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorResolver.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectiveConstructorResolver.java @@ -1,120 +1,120 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel.support; - -import java.lang.reflect.Constructor; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.List; - -import org.springframework.core.MethodParameter; -import org.springframework.core.convert.TypeDescriptor; -import org.springframework.expression.AccessException; -import org.springframework.expression.ConstructorExecutor; -import org.springframework.expression.ConstructorResolver; -import org.springframework.expression.EvaluationContext; -import org.springframework.expression.EvaluationException; -import org.springframework.expression.TypeConverter; - -/** - * A constructor resolver that uses reflection to locate the constructor that should be invoked - * - * @author Andy Clement - * @author Juergen Hoeller - * @since 3.0 - */ -public class ReflectiveConstructorResolver implements ConstructorResolver { - - /** - * Locate a constructor on the type. There are three kinds of match that might occur: - *
    - *
  1. An exact match where the types of the arguments match the types of the constructor - *
  2. An in-exact match where the types we are looking for are subtypes of those defined on the constructor - *
  3. A match where we are able to convert the arguments into those expected by the constructor, according to the - * registered type converter. - *
- */ - public ConstructorExecutor resolve(EvaluationContext context, String typename, List argumentTypes) - throws AccessException { - - try { - TypeConverter typeConverter = context.getTypeConverter(); - Class type = context.getTypeLocator().findType(typename); - Constructor[] ctors = type.getConstructors(); - - Arrays.sort(ctors, new Comparator() { - public int compare(Constructor c1, Constructor c2) { - int c1pl = c1.getParameterTypes().length; - int c2pl = c2.getParameterTypes().length; - return (new Integer(c1pl)).compareTo(c2pl); - } - }); - - Constructor closeMatch = null; - int[] argsToConvert = null; - Constructor matchRequiringConversion = null; - - for (Constructor ctor : ctors) { - Class[] paramTypes = ctor.getParameterTypes(); - List paramDescriptors = new ArrayList(paramTypes.length); - for (int i = 0; i < paramTypes.length; i++) { - paramDescriptors.add(new TypeDescriptor(new MethodParameter(ctor, i))); - } - ReflectionHelper.ArgumentsMatchInfo matchInfo = null; - if (ctor.isVarArgs() && argumentTypes.size() >= (paramTypes.length - 1)) { - // *sigh* complicated - // Basically.. we have to have all parameters match up until the varargs one, then the rest of what is - // being provided should be - // the same type whilst the final argument to the method must be an array of that (oh, how easy...not) - - // or the final parameter - // we are supplied does match exactly (it is an array already). - matchInfo = ReflectionHelper.compareArgumentsVarargs(paramDescriptors, argumentTypes, typeConverter); - } - else if (paramTypes.length == argumentTypes.size()) { - // worth a closer look - matchInfo = ReflectionHelper.compareArguments(paramDescriptors, argumentTypes, typeConverter); - } - if (matchInfo != null) { - if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.EXACT) { - return new ReflectiveConstructorExecutor(ctor, null); - } - else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.CLOSE) { - closeMatch = ctor; - } - else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.REQUIRES_CONVERSION) { - argsToConvert = matchInfo.argsRequiringConversion; - matchRequiringConversion = ctor; - } - } - } - if (closeMatch != null) { - return new ReflectiveConstructorExecutor(closeMatch, null); - } - else if (matchRequiringConversion != null) { - return new ReflectiveConstructorExecutor(matchRequiringConversion, argsToConvert); - } - else { - return null; - } - } - catch (EvaluationException ex) { - throw new AccessException("Failed to resolve constructor", ex); - } - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel.support; + +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +import org.springframework.core.MethodParameter; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.expression.AccessException; +import org.springframework.expression.ConstructorExecutor; +import org.springframework.expression.ConstructorResolver; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.TypeConverter; + +/** + * A constructor resolver that uses reflection to locate the constructor that should be invoked + * + * @author Andy Clement + * @author Juergen Hoeller + * @since 3.0 + */ +public class ReflectiveConstructorResolver implements ConstructorResolver { + + /** + * Locate a constructor on the type. There are three kinds of match that might occur: + *
    + *
  1. An exact match where the types of the arguments match the types of the constructor + *
  2. An in-exact match where the types we are looking for are subtypes of those defined on the constructor + *
  3. A match where we are able to convert the arguments into those expected by the constructor, according to the + * registered type converter. + *
+ */ + public ConstructorExecutor resolve(EvaluationContext context, String typename, List argumentTypes) + throws AccessException { + + try { + TypeConverter typeConverter = context.getTypeConverter(); + Class type = context.getTypeLocator().findType(typename); + Constructor[] ctors = type.getConstructors(); + + Arrays.sort(ctors, new Comparator() { + public int compare(Constructor c1, Constructor c2) { + int c1pl = c1.getParameterTypes().length; + int c2pl = c2.getParameterTypes().length; + return (new Integer(c1pl)).compareTo(c2pl); + } + }); + + Constructor closeMatch = null; + int[] argsToConvert = null; + Constructor matchRequiringConversion = null; + + for (Constructor ctor : ctors) { + Class[] paramTypes = ctor.getParameterTypes(); + List paramDescriptors = new ArrayList(paramTypes.length); + for (int i = 0; i < paramTypes.length; i++) { + paramDescriptors.add(new TypeDescriptor(new MethodParameter(ctor, i))); + } + ReflectionHelper.ArgumentsMatchInfo matchInfo = null; + if (ctor.isVarArgs() && argumentTypes.size() >= (paramTypes.length - 1)) { + // *sigh* complicated + // Basically.. we have to have all parameters match up until the varargs one, then the rest of what is + // being provided should be + // the same type whilst the final argument to the method must be an array of that (oh, how easy...not) - + // or the final parameter + // we are supplied does match exactly (it is an array already). + matchInfo = ReflectionHelper.compareArgumentsVarargs(paramDescriptors, argumentTypes, typeConverter); + } + else if (paramTypes.length == argumentTypes.size()) { + // worth a closer look + matchInfo = ReflectionHelper.compareArguments(paramDescriptors, argumentTypes, typeConverter); + } + if (matchInfo != null) { + if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.EXACT) { + return new ReflectiveConstructorExecutor(ctor, null); + } + else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.CLOSE) { + closeMatch = ctor; + } + else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.REQUIRES_CONVERSION) { + argsToConvert = matchInfo.argsRequiringConversion; + matchRequiringConversion = ctor; + } + } + } + if (closeMatch != null) { + return new ReflectiveConstructorExecutor(closeMatch, null); + } + else if (matchRequiringConversion != null) { + return new ReflectiveConstructorExecutor(matchRequiringConversion, argsToConvert); + } + else { + return null; + } + } + catch (EvaluationException ex) { + throw new AccessException("Failed to resolve constructor", ex); + } + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodExecutor.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodExecutor.java index f12cb28a6d..a54dbac7bc 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodExecutor.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodExecutor.java @@ -1,77 +1,77 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel.support; - -import java.lang.reflect.Method; - -import org.springframework.core.MethodParameter; -import org.springframework.core.convert.TypeDescriptor; -import org.springframework.expression.AccessException; -import org.springframework.expression.EvaluationContext; -import org.springframework.expression.MethodExecutor; -import org.springframework.expression.TypedValue; -import org.springframework.util.ReflectionUtils; - -/** - * @author Andy Clement - * @author Juergen Hoeller - * @since 3.0 - */ -class ReflectiveMethodExecutor implements MethodExecutor { - - private final Method method; - - private final Integer varargsPosition; - - // When the method was found, we will have determined if arguments need to be converted for it - // to be invoked. Conversion won't be cheap so let's only do it if necessary. - private final int[] argsRequiringConversion; - - - public ReflectiveMethodExecutor(Method theMethod, int[] argumentsRequiringConversion) { - this.method = theMethod; - if (theMethod.isVarArgs()) { - Class[] paramTypes = theMethod.getParameterTypes(); - this.varargsPosition = paramTypes.length - 1; - } - else { - this.varargsPosition = null; - } - this.argsRequiringConversion = argumentsRequiringConversion; - } - - - public TypedValue execute(EvaluationContext context, Object target, Object... arguments) throws AccessException { - try { - if (arguments != null) { - ReflectionHelper.convertArguments( - context.getTypeConverter(), arguments, this.method, - this.argsRequiringConversion, this.varargsPosition); - } - if (this.method.isVarArgs()) { - arguments = ReflectionHelper.setupArgumentsForVarargsInvocation(this.method.getParameterTypes(), arguments); - } - ReflectionUtils.makeAccessible(this.method); - Object value = this.method.invoke(target, arguments); - return new TypedValue(value, new TypeDescriptor(new MethodParameter(this.method, -1)).narrow(value)); - } - catch (Exception ex) { - throw new AccessException("Problem invoking method: " + this.method, ex); - } - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel.support; + +import java.lang.reflect.Method; + +import org.springframework.core.MethodParameter; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.MethodExecutor; +import org.springframework.expression.TypedValue; +import org.springframework.util.ReflectionUtils; + +/** + * @author Andy Clement + * @author Juergen Hoeller + * @since 3.0 + */ +class ReflectiveMethodExecutor implements MethodExecutor { + + private final Method method; + + private final Integer varargsPosition; + + // When the method was found, we will have determined if arguments need to be converted for it + // to be invoked. Conversion won't be cheap so let's only do it if necessary. + private final int[] argsRequiringConversion; + + + public ReflectiveMethodExecutor(Method theMethod, int[] argumentsRequiringConversion) { + this.method = theMethod; + if (theMethod.isVarArgs()) { + Class[] paramTypes = theMethod.getParameterTypes(); + this.varargsPosition = paramTypes.length - 1; + } + else { + this.varargsPosition = null; + } + this.argsRequiringConversion = argumentsRequiringConversion; + } + + + public TypedValue execute(EvaluationContext context, Object target, Object... arguments) throws AccessException { + try { + if (arguments != null) { + ReflectionHelper.convertArguments( + context.getTypeConverter(), arguments, this.method, + this.argsRequiringConversion, this.varargsPosition); + } + if (this.method.isVarArgs()) { + arguments = ReflectionHelper.setupArgumentsForVarargsInvocation(this.method.getParameterTypes(), arguments); + } + ReflectionUtils.makeAccessible(this.method); + Object value = this.method.invoke(target, arguments); + return new TypedValue(value, new TypeDescriptor(new MethodParameter(this.method, -1)).narrow(value)); + } + catch (Exception ex) { + throw new AccessException("Problem invoking method: " + this.method, ex); + } + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java index c606e854fa..d40daa3cba 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectiveMethodResolver.java @@ -1,197 +1,197 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel.support; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.springframework.core.MethodParameter; -import org.springframework.core.convert.TypeDescriptor; -import org.springframework.expression.AccessException; -import org.springframework.expression.EvaluationContext; -import org.springframework.expression.EvaluationException; -import org.springframework.expression.MethodExecutor; -import org.springframework.expression.MethodFilter; -import org.springframework.expression.MethodResolver; -import org.springframework.expression.TypeConverter; -import org.springframework.expression.spel.SpelEvaluationException; -import org.springframework.expression.spel.SpelMessage; -import org.springframework.util.CollectionUtils; - -/** - * A method resolver that uses reflection to locate the method that should be invoked. - * - * @author Andy Clement - * @author Juergen Hoeller - * @since 3.0 - */ -public class ReflectiveMethodResolver implements MethodResolver { - - private static Method[] NO_METHODS = new Method[0]; - - private Map, MethodFilter> filters = null; - - // Using distance will ensure a more accurate match is discovered, - // more closely following the Java rules. - private boolean useDistance = false; - - - public ReflectiveMethodResolver() { - - } - - /** - * This constructors allows the ReflectiveMethodResolver to be configured such that it will - * use a distance computation to check which is the better of two close matches (when there - * are multiple matches). Using the distance computation is intended to ensure matches - * are more closely representative of what a Java compiler would do when taking into - * account boxing/unboxing and whether the method candidates are declared to handle a - * supertype of the type (of the argument) being passed in. - * @param useDistance true if distance computation should be used when calculating matches - */ - public ReflectiveMethodResolver(boolean useDistance) { - this.useDistance = useDistance; - } - - /** - * Locate a method on a type. There are three kinds of match that might occur: - *
    - *
  1. An exact match where the types of the arguments match the types of the constructor - *
  2. An in-exact match where the types we are looking for are subtypes of those defined on the constructor - *
  3. A match where we are able to convert the arguments into those expected by the constructor, - * according to the registered type converter. - *
- */ - public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name, - List argumentTypes) throws AccessException { - - try { - TypeConverter typeConverter = context.getTypeConverter(); - Class type = (targetObject instanceof Class ? (Class) targetObject : targetObject.getClass()); - Method[] methods = type.getMethods(); - - // If a filter is registered for this type, call it - MethodFilter filter = (this.filters != null ? this.filters.get(type) : null); - if (filter != null) { - List methodsForFiltering = new ArrayList(); - for (Method method: methods) { - methodsForFiltering.add(method); - } - List methodsFiltered = filter.filter(methodsForFiltering); - if (CollectionUtils.isEmpty(methodsFiltered)) { - methods = NO_METHODS; - } - else { - methods = methodsFiltered.toArray(new Method[methodsFiltered.size()]); - } - } - - Arrays.sort(methods, new Comparator() { - public int compare(Method m1, Method m2) { - int m1pl = m1.getParameterTypes().length; - int m2pl = m2.getParameterTypes().length; - return (new Integer(m1pl)).compareTo(m2pl); - } - }); - - Method closeMatch = null; - int closeMatchDistance = Integer.MAX_VALUE; - int[] argsToConvert = null; - Method matchRequiringConversion = null; - boolean multipleOptions = false; - - for (Method method : methods) { - if (method.isBridge()) { - continue; - } - if (method.getName().equals(name)) { - Class[] paramTypes = method.getParameterTypes(); - List paramDescriptors = new ArrayList(paramTypes.length); - for (int i = 0; i < paramTypes.length; i++) { - paramDescriptors.add(new TypeDescriptor(new MethodParameter(method, i))); - } - ReflectionHelper.ArgumentsMatchInfo matchInfo = null; - if (method.isVarArgs() && argumentTypes.size() >= (paramTypes.length - 1)) { - // *sigh* complicated - matchInfo = ReflectionHelper.compareArgumentsVarargs(paramDescriptors, argumentTypes, typeConverter); - } - else if (paramTypes.length == argumentTypes.size()) { - // name and parameter number match, check the arguments - matchInfo = ReflectionHelper.compareArguments(paramDescriptors, argumentTypes, typeConverter); - } - if (matchInfo != null) { - if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.EXACT) { - return new ReflectiveMethodExecutor(method, null); - } - else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.CLOSE) { - if (!useDistance) { - closeMatch = method; - } else { - int matchDistance = ReflectionHelper.getTypeDifferenceWeight(paramDescriptors, argumentTypes); - if (matchDistance type, MethodFilter filter) { - if (this.filters == null) { - this.filters = new HashMap, MethodFilter>(); - } - if (filter == null) { - this.filters.remove(type); - } - else { - this.filters.put(type,filter); - } - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel.support; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.core.MethodParameter; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.MethodExecutor; +import org.springframework.expression.MethodFilter; +import org.springframework.expression.MethodResolver; +import org.springframework.expression.TypeConverter; +import org.springframework.expression.spel.SpelEvaluationException; +import org.springframework.expression.spel.SpelMessage; +import org.springframework.util.CollectionUtils; + +/** + * A method resolver that uses reflection to locate the method that should be invoked. + * + * @author Andy Clement + * @author Juergen Hoeller + * @since 3.0 + */ +public class ReflectiveMethodResolver implements MethodResolver { + + private static Method[] NO_METHODS = new Method[0]; + + private Map, MethodFilter> filters = null; + + // Using distance will ensure a more accurate match is discovered, + // more closely following the Java rules. + private boolean useDistance = false; + + + public ReflectiveMethodResolver() { + + } + + /** + * This constructors allows the ReflectiveMethodResolver to be configured such that it will + * use a distance computation to check which is the better of two close matches (when there + * are multiple matches). Using the distance computation is intended to ensure matches + * are more closely representative of what a Java compiler would do when taking into + * account boxing/unboxing and whether the method candidates are declared to handle a + * supertype of the type (of the argument) being passed in. + * @param useDistance true if distance computation should be used when calculating matches + */ + public ReflectiveMethodResolver(boolean useDistance) { + this.useDistance = useDistance; + } + + /** + * Locate a method on a type. There are three kinds of match that might occur: + *
    + *
  1. An exact match where the types of the arguments match the types of the constructor + *
  2. An in-exact match where the types we are looking for are subtypes of those defined on the constructor + *
  3. A match where we are able to convert the arguments into those expected by the constructor, + * according to the registered type converter. + *
+ */ + public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name, + List argumentTypes) throws AccessException { + + try { + TypeConverter typeConverter = context.getTypeConverter(); + Class type = (targetObject instanceof Class ? (Class) targetObject : targetObject.getClass()); + Method[] methods = type.getMethods(); + + // If a filter is registered for this type, call it + MethodFilter filter = (this.filters != null ? this.filters.get(type) : null); + if (filter != null) { + List methodsForFiltering = new ArrayList(); + for (Method method: methods) { + methodsForFiltering.add(method); + } + List methodsFiltered = filter.filter(methodsForFiltering); + if (CollectionUtils.isEmpty(methodsFiltered)) { + methods = NO_METHODS; + } + else { + methods = methodsFiltered.toArray(new Method[methodsFiltered.size()]); + } + } + + Arrays.sort(methods, new Comparator() { + public int compare(Method m1, Method m2) { + int m1pl = m1.getParameterTypes().length; + int m2pl = m2.getParameterTypes().length; + return (new Integer(m1pl)).compareTo(m2pl); + } + }); + + Method closeMatch = null; + int closeMatchDistance = Integer.MAX_VALUE; + int[] argsToConvert = null; + Method matchRequiringConversion = null; + boolean multipleOptions = false; + + for (Method method : methods) { + if (method.isBridge()) { + continue; + } + if (method.getName().equals(name)) { + Class[] paramTypes = method.getParameterTypes(); + List paramDescriptors = new ArrayList(paramTypes.length); + for (int i = 0; i < paramTypes.length; i++) { + paramDescriptors.add(new TypeDescriptor(new MethodParameter(method, i))); + } + ReflectionHelper.ArgumentsMatchInfo matchInfo = null; + if (method.isVarArgs() && argumentTypes.size() >= (paramTypes.length - 1)) { + // *sigh* complicated + matchInfo = ReflectionHelper.compareArgumentsVarargs(paramDescriptors, argumentTypes, typeConverter); + } + else if (paramTypes.length == argumentTypes.size()) { + // name and parameter number match, check the arguments + matchInfo = ReflectionHelper.compareArguments(paramDescriptors, argumentTypes, typeConverter); + } + if (matchInfo != null) { + if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.EXACT) { + return new ReflectiveMethodExecutor(method, null); + } + else if (matchInfo.kind == ReflectionHelper.ArgsMatchKind.CLOSE) { + if (!useDistance) { + closeMatch = method; + } else { + int matchDistance = ReflectionHelper.getTypeDifferenceWeight(paramDescriptors, argumentTypes); + if (matchDistance type, MethodFilter filter) { + if (this.filters == null) { + this.filters = new HashMap, MethodFilter>(); + } + if (filter == null) { + this.filters.remove(type); + } + else { + this.filters.put(type,filter); + } + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java index e6cd374082..621db0ec37 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java @@ -1,527 +1,527 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel.support; - -import java.lang.reflect.Array; -import java.lang.reflect.Field; -import java.lang.reflect.Member; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.springframework.core.MethodParameter; -import org.springframework.core.convert.Property; -import org.springframework.core.convert.TypeDescriptor; -import org.springframework.expression.AccessException; -import org.springframework.expression.EvaluationContext; -import org.springframework.expression.EvaluationException; -import org.springframework.expression.PropertyAccessor; -import org.springframework.expression.TypedValue; -import org.springframework.util.ReflectionUtils; -import org.springframework.util.StringUtils; - -/** - * Simple PropertyAccessor that uses reflection to access properties for reading and writing. A property can be accessed - * if it is accessible as a field on the object or through a getter (if being read) or a setter (if being written). - * - * @author Andy Clement - * @author Juergen Hoeller - * @since 3.0 - */ -public class ReflectivePropertyAccessor implements PropertyAccessor { - - protected final Map readerCache = new ConcurrentHashMap(); - - protected final Map writerCache = new ConcurrentHashMap(); - - protected final Map typeDescriptorCache = new ConcurrentHashMap(); - - - /** - * @return null which means this is a general purpose accessor - */ - public Class[] getSpecificTargetClasses() { - return null; - } - - public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { - if (target == null) { - return false; - } - Class type = (target instanceof Class ? (Class) target : target.getClass()); - if (type.isArray() && name.equals("length")) { - return true; - } - CacheKey cacheKey = new CacheKey(type, name); - if (this.readerCache.containsKey(cacheKey)) { - return true; - } - Method method = findGetterForProperty(name, type, target instanceof Class); - if (method != null) { - // Treat it like a property - // The readerCache will only contain gettable properties (let's not worry about setters for now) - Property property = new Property(type, method, null); - TypeDescriptor typeDescriptor = new TypeDescriptor(property); - this.readerCache.put(cacheKey, new InvokerPair(method, typeDescriptor)); - this.typeDescriptorCache.put(cacheKey, typeDescriptor); - return true; - } - else { - Field field = findField(name, type, target instanceof Class); - if (field != null) { - TypeDescriptor typeDescriptor = new TypeDescriptor(field); - this.readerCache.put(cacheKey, new InvokerPair(field,typeDescriptor)); - this.typeDescriptorCache.put(cacheKey, typeDescriptor); - return true; - } - } - return false; - } - - public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { - if (target == null) { - throw new AccessException("Cannot read property of null target"); - } - Class type = (target instanceof Class ? (Class) target : target.getClass()); - - if (type.isArray() && name.equals("length")) { - if (target instanceof Class) { - throw new AccessException("Cannot access length on array class itself"); - } - return new TypedValue(Array.getLength(target)); - } - - CacheKey cacheKey = new CacheKey(type, name); - InvokerPair invoker = this.readerCache.get(cacheKey); - - if (invoker == null || invoker.member instanceof Method) { - Method method = (Method) (invoker != null ? invoker.member : null); - if (method == null) { - method = findGetterForProperty(name, type, target instanceof Class); - if (method != null) { - // TODO remove the duplication here between canRead and read - // Treat it like a property - // The readerCache will only contain gettable properties (let's not worry about setters for now) - Property property = new Property(type, method, null); - TypeDescriptor typeDescriptor = new TypeDescriptor(property); - invoker = new InvokerPair(method, typeDescriptor); - this.readerCache.put(cacheKey, invoker); - } - } - if (method != null) { - try { - ReflectionUtils.makeAccessible(method); - Object value = method.invoke(target); - return new TypedValue(value, invoker.typeDescriptor.narrow(value)); - } - catch (Exception ex) { - throw new AccessException("Unable to access property '" + name + "' through getter", ex); - } - } - } - - if (invoker == null || invoker.member instanceof Field) { - Field field = (Field) (invoker == null ? null : invoker.member); - if (field == null) { - field = findField(name, type, target instanceof Class); - if (field != null) { - invoker = new InvokerPair(field, new TypeDescriptor(field)); - this.readerCache.put(cacheKey, invoker); - } - } - if (field != null) { - try { - ReflectionUtils.makeAccessible(field); - Object value = field.get(target); - return new TypedValue(value, invoker.typeDescriptor.narrow(value)); - } - catch (Exception ex) { - throw new AccessException("Unable to access field: " + name, ex); - } - } - } - - throw new AccessException("Neither getter nor field found for property '" + name + "'"); - } - - public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { - if (target == null) { - return false; - } - Class type = (target instanceof Class ? (Class) target : target.getClass()); - CacheKey cacheKey = new CacheKey(type, name); - if (this.writerCache.containsKey(cacheKey)) { - return true; - } - Method method = findSetterForProperty(name, type, target instanceof Class); - if (method != null) { - // Treat it like a property - Property property = new Property(type, null, method); - TypeDescriptor typeDescriptor = new TypeDescriptor(property); - this.writerCache.put(cacheKey, method); - this.typeDescriptorCache.put(cacheKey, typeDescriptor); - return true; - } - else { - Field field = findField(name, type, target instanceof Class); - if (field != null) { - this.writerCache.put(cacheKey, field); - this.typeDescriptorCache.put(cacheKey, new TypeDescriptor(field)); - return true; - } - } - return false; - } - - public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { - if (target == null) { - throw new AccessException("Cannot write property on null target"); - } - Class type = (target instanceof Class ? (Class) target : target.getClass()); - - Object possiblyConvertedNewValue = newValue; - TypeDescriptor typeDescriptor = getTypeDescriptor(context, target, name); - if (typeDescriptor != null) { - try { - possiblyConvertedNewValue = context.getTypeConverter().convertValue( - newValue, TypeDescriptor.forObject(newValue), typeDescriptor); - } - catch (EvaluationException evaluationException) { - throw new AccessException("Type conversion failure",evaluationException); - } - } - CacheKey cacheKey = new CacheKey(type, name); - Member cachedMember = this.writerCache.get(cacheKey); - - if (cachedMember == null || cachedMember instanceof Method) { - Method method = (Method) cachedMember; - if (method == null) { - method = findSetterForProperty(name, type, target instanceof Class); - if (method != null) { - cachedMember = method; - this.writerCache.put(cacheKey, cachedMember); - } - } - if (method != null) { - try { - ReflectionUtils.makeAccessible(method); - method.invoke(target, possiblyConvertedNewValue); - return; - } - catch (Exception ex) { - throw new AccessException("Unable to access property '" + name + "' through setter", ex); - } - } - } - - if (cachedMember == null || cachedMember instanceof Field) { - Field field = (Field) cachedMember; - if (field == null) { - field = findField(name, type, target instanceof Class); - if (field != null) { - cachedMember = field; - this.writerCache.put(cacheKey, cachedMember); - } - } - if (field != null) { - try { - ReflectionUtils.makeAccessible(field); - field.set(target, possiblyConvertedNewValue); - return; - } - catch (Exception ex) { - throw new AccessException("Unable to access field: " + name, ex); - } - } - } - - throw new AccessException("Neither setter nor field found for property '" + name + "'"); - } - - private TypeDescriptor getTypeDescriptor(EvaluationContext context, Object target, String name) { - if (target == null) { - return null; - } - Class type = (target instanceof Class ? (Class) target : target.getClass()); - - if (type.isArray() && name.equals("length")) { - return TypeDescriptor.valueOf(Integer.TYPE); - } - CacheKey cacheKey = new CacheKey(type, name); - TypeDescriptor typeDescriptor = this.typeDescriptorCache.get(cacheKey); - if (typeDescriptor == null) { - // attempt to populate the cache entry - try { - if (canRead(context, target, name)) { - typeDescriptor = this.typeDescriptorCache.get(cacheKey); - } - else if (canWrite(context, target, name)) { - typeDescriptor = this.typeDescriptorCache.get(cacheKey); - } - } - catch (AccessException ex) { - // continue with null type descriptor - } - } - return typeDescriptor; - } - - /** - * Find a getter method for the specified property. A getter is defined as a method whose name start with the prefix - * 'get' and the rest of the name is the same as the property name (with the first character uppercased). - */ - protected Method findGetterForProperty(String propertyName, Class clazz, boolean mustBeStatic) { - Method[] ms = clazz.getMethods(); - // Try "get*" method... - String getterName = "get" + StringUtils.capitalize(propertyName); - for (Method method : ms) { - if (method.getName().equals(getterName) && method.getParameterTypes().length == 0 && - (!mustBeStatic || Modifier.isStatic(method.getModifiers()))) { - return method; - } - } - // Try "is*" method... - getterName = "is" + StringUtils.capitalize(propertyName); - for (Method method : ms) { - if (method.getName().equals(getterName) && method.getParameterTypes().length == 0 && - boolean.class.equals(method.getReturnType()) && - (!mustBeStatic || Modifier.isStatic(method.getModifiers()))) { - return method; - } - } - return null; - } - - /** - * Find a setter method for the specified property. - */ - protected Method findSetterForProperty(String propertyName, Class clazz, boolean mustBeStatic) { - Method[] methods = clazz.getMethods(); - String setterName = "set" + StringUtils.capitalize(propertyName); - for (Method method : methods) { - if (method.getName().equals(setterName) && method.getParameterTypes().length == 1 && - (!mustBeStatic || Modifier.isStatic(method.getModifiers()))) { - return method; - } - } - return null; - } - - /** - * Find a field of a certain name on a specified class - */ - protected Field findField(String name, Class clazz, boolean mustBeStatic) { - Field[] fields = clazz.getFields(); - for (Field field : fields) { - if (field.getName().equals(name) && (!mustBeStatic || Modifier.isStatic(field.getModifiers()))) { - return field; - } - } - return null; - } - - /** - * Captures the member (method/field) to call reflectively to access a property value and the type descriptor for the - * value returned by the reflective call. - */ - private static class InvokerPair { - - final Member member; - - final TypeDescriptor typeDescriptor; - - public InvokerPair(Member member, TypeDescriptor typeDescriptor) { - this.member = member; - this.typeDescriptor = typeDescriptor; - } - - } - - private static class CacheKey { - - private final Class clazz; - - private final String name; - - public CacheKey(Class clazz, String name) { - this.clazz = clazz; - this.name = name; - } - - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - if (!(other instanceof CacheKey)) { - return false; - } - CacheKey otherKey = (CacheKey) other; - return (this.clazz.equals(otherKey.clazz) && this.name.equals(otherKey.name)); - } - - @Override - public int hashCode() { - return this.clazz.hashCode() * 29 + this.name.hashCode(); - } - } - - /** - * Attempt to create an optimized property accessor tailored for a property of a particular name on - * a particular class. The general ReflectivePropertyAccessor will always work but is not optimal - * due to the need to lookup which reflective member (method/field) to use each time read() is called. - * This method will just return the ReflectivePropertyAccessor instance if it is unable to build - * something more optimal. - */ - public PropertyAccessor createOptimalAccessor(EvaluationContext eContext, Object target, String name) { - // Don't be clever for arrays or null target - if (target == null) { - return this; - } - Class type = (target instanceof Class ? (Class) target : target.getClass()); - if (type.isArray()) { - return this; - } - - CacheKey cacheKey = new CacheKey(type, name); - InvokerPair invocationTarget = this.readerCache.get(cacheKey); - - if (invocationTarget == null || invocationTarget.member instanceof Method) { - Method method = (Method) (invocationTarget==null?null:invocationTarget.member); - if (method == null) { - method = findGetterForProperty(name, type, target instanceof Class); - if (method != null) { - invocationTarget = new InvokerPair(method,new TypeDescriptor(new MethodParameter(method,-1))); - ReflectionUtils.makeAccessible(method); - this.readerCache.put(cacheKey, invocationTarget); - } - } - if (method != null) { - return new OptimalPropertyAccessor(invocationTarget); - } - } - - if (invocationTarget == null || invocationTarget.member instanceof Field) { - Field field = (Field) (invocationTarget==null?null:invocationTarget.member); - if (field == null) { - field = findField(name, type, target instanceof Class); - if (field != null) { - invocationTarget = new InvokerPair(field, new TypeDescriptor(field)); - ReflectionUtils.makeAccessible(field); - this.readerCache.put(cacheKey, invocationTarget); - } - } - if (field != null) { - return new OptimalPropertyAccessor(invocationTarget); - } - } - return this; - } - - /** - * An optimized form of a PropertyAccessor that will use reflection but only knows how to access a particular property - * on a particular class. This is unlike the general ReflectivePropertyResolver which manages a cache of methods/fields that - * may be invoked to access different properties on different classes. This optimal accessor exists because looking up - * the appropriate reflective object by class/name on each read is not cheap. - */ - static class OptimalPropertyAccessor implements PropertyAccessor { - private final Member member; - private final TypeDescriptor typeDescriptor; - private final boolean needsToBeMadeAccessible; - - OptimalPropertyAccessor(InvokerPair target) { - this.member = target.member; - this.typeDescriptor = target.typeDescriptor; - if (this.member instanceof Field) { - Field field = (Field)member; - needsToBeMadeAccessible = (!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())) - && !field.isAccessible(); - } - else { - Method method = (Method)member; - needsToBeMadeAccessible = ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) - && !method.isAccessible()); - } - } - - public Class[] getSpecificTargetClasses() { - throw new UnsupportedOperationException("Should not be called on an OptimalPropertyAccessor"); - } - - public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { - if (target == null) { - return false; - } - Class type = (target instanceof Class ? (Class) target : target.getClass()); - if (type.isArray()) { - return false; - } - if (member instanceof Method) { - Method method = (Method)member; - String getterName = "get" + StringUtils.capitalize(name); - if (getterName.equals(method.getName())) { - return true; - } - getterName = "is" + StringUtils.capitalize(name); - return getterName.equals(method.getName()); - } - else { - Field field = (Field)member; - return field.getName().equals(name); - } - } - - public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { - if (member instanceof Method) { - try { - if (needsToBeMadeAccessible) { - ReflectionUtils.makeAccessible((Method) member); - } - Object value = ((Method) member).invoke(target); - return new TypedValue(value, typeDescriptor.narrow(value)); - } - catch (Exception ex) { - throw new AccessException("Unable to access property '" + name + "' through getter", ex); - } - } - if (member instanceof Field) { - try { - if (needsToBeMadeAccessible) { - ReflectionUtils.makeAccessible((Field)member); - } - Object value = ((Field)member).get(target); - return new TypedValue(value, typeDescriptor.narrow(value)); - } - catch (Exception ex) { - throw new AccessException("Unable to access field: " + name, ex); - } - } - throw new AccessException("Neither getter nor field found for property '" + name + "'"); - } - - public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { - throw new UnsupportedOperationException("Should not be called on an OptimalPropertyAccessor"); - } - - public void write(EvaluationContext context, Object target, String name, Object newValue) - throws AccessException { - throw new UnsupportedOperationException("Should not be called on an OptimalPropertyAccessor"); - } - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel.support; + +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.springframework.core.MethodParameter; +import org.springframework.core.convert.Property; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.TypedValue; +import org.springframework.util.ReflectionUtils; +import org.springframework.util.StringUtils; + +/** + * Simple PropertyAccessor that uses reflection to access properties for reading and writing. A property can be accessed + * if it is accessible as a field on the object or through a getter (if being read) or a setter (if being written). + * + * @author Andy Clement + * @author Juergen Hoeller + * @since 3.0 + */ +public class ReflectivePropertyAccessor implements PropertyAccessor { + + protected final Map readerCache = new ConcurrentHashMap(); + + protected final Map writerCache = new ConcurrentHashMap(); + + protected final Map typeDescriptorCache = new ConcurrentHashMap(); + + + /** + * @return null which means this is a general purpose accessor + */ + public Class[] getSpecificTargetClasses() { + return null; + } + + public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { + if (target == null) { + return false; + } + Class type = (target instanceof Class ? (Class) target : target.getClass()); + if (type.isArray() && name.equals("length")) { + return true; + } + CacheKey cacheKey = new CacheKey(type, name); + if (this.readerCache.containsKey(cacheKey)) { + return true; + } + Method method = findGetterForProperty(name, type, target instanceof Class); + if (method != null) { + // Treat it like a property + // The readerCache will only contain gettable properties (let's not worry about setters for now) + Property property = new Property(type, method, null); + TypeDescriptor typeDescriptor = new TypeDescriptor(property); + this.readerCache.put(cacheKey, new InvokerPair(method, typeDescriptor)); + this.typeDescriptorCache.put(cacheKey, typeDescriptor); + return true; + } + else { + Field field = findField(name, type, target instanceof Class); + if (field != null) { + TypeDescriptor typeDescriptor = new TypeDescriptor(field); + this.readerCache.put(cacheKey, new InvokerPair(field,typeDescriptor)); + this.typeDescriptorCache.put(cacheKey, typeDescriptor); + return true; + } + } + return false; + } + + public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { + if (target == null) { + throw new AccessException("Cannot read property of null target"); + } + Class type = (target instanceof Class ? (Class) target : target.getClass()); + + if (type.isArray() && name.equals("length")) { + if (target instanceof Class) { + throw new AccessException("Cannot access length on array class itself"); + } + return new TypedValue(Array.getLength(target)); + } + + CacheKey cacheKey = new CacheKey(type, name); + InvokerPair invoker = this.readerCache.get(cacheKey); + + if (invoker == null || invoker.member instanceof Method) { + Method method = (Method) (invoker != null ? invoker.member : null); + if (method == null) { + method = findGetterForProperty(name, type, target instanceof Class); + if (method != null) { + // TODO remove the duplication here between canRead and read + // Treat it like a property + // The readerCache will only contain gettable properties (let's not worry about setters for now) + Property property = new Property(type, method, null); + TypeDescriptor typeDescriptor = new TypeDescriptor(property); + invoker = new InvokerPair(method, typeDescriptor); + this.readerCache.put(cacheKey, invoker); + } + } + if (method != null) { + try { + ReflectionUtils.makeAccessible(method); + Object value = method.invoke(target); + return new TypedValue(value, invoker.typeDescriptor.narrow(value)); + } + catch (Exception ex) { + throw new AccessException("Unable to access property '" + name + "' through getter", ex); + } + } + } + + if (invoker == null || invoker.member instanceof Field) { + Field field = (Field) (invoker == null ? null : invoker.member); + if (field == null) { + field = findField(name, type, target instanceof Class); + if (field != null) { + invoker = new InvokerPair(field, new TypeDescriptor(field)); + this.readerCache.put(cacheKey, invoker); + } + } + if (field != null) { + try { + ReflectionUtils.makeAccessible(field); + Object value = field.get(target); + return new TypedValue(value, invoker.typeDescriptor.narrow(value)); + } + catch (Exception ex) { + throw new AccessException("Unable to access field: " + name, ex); + } + } + } + + throw new AccessException("Neither getter nor field found for property '" + name + "'"); + } + + public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { + if (target == null) { + return false; + } + Class type = (target instanceof Class ? (Class) target : target.getClass()); + CacheKey cacheKey = new CacheKey(type, name); + if (this.writerCache.containsKey(cacheKey)) { + return true; + } + Method method = findSetterForProperty(name, type, target instanceof Class); + if (method != null) { + // Treat it like a property + Property property = new Property(type, null, method); + TypeDescriptor typeDescriptor = new TypeDescriptor(property); + this.writerCache.put(cacheKey, method); + this.typeDescriptorCache.put(cacheKey, typeDescriptor); + return true; + } + else { + Field field = findField(name, type, target instanceof Class); + if (field != null) { + this.writerCache.put(cacheKey, field); + this.typeDescriptorCache.put(cacheKey, new TypeDescriptor(field)); + return true; + } + } + return false; + } + + public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { + if (target == null) { + throw new AccessException("Cannot write property on null target"); + } + Class type = (target instanceof Class ? (Class) target : target.getClass()); + + Object possiblyConvertedNewValue = newValue; + TypeDescriptor typeDescriptor = getTypeDescriptor(context, target, name); + if (typeDescriptor != null) { + try { + possiblyConvertedNewValue = context.getTypeConverter().convertValue( + newValue, TypeDescriptor.forObject(newValue), typeDescriptor); + } + catch (EvaluationException evaluationException) { + throw new AccessException("Type conversion failure",evaluationException); + } + } + CacheKey cacheKey = new CacheKey(type, name); + Member cachedMember = this.writerCache.get(cacheKey); + + if (cachedMember == null || cachedMember instanceof Method) { + Method method = (Method) cachedMember; + if (method == null) { + method = findSetterForProperty(name, type, target instanceof Class); + if (method != null) { + cachedMember = method; + this.writerCache.put(cacheKey, cachedMember); + } + } + if (method != null) { + try { + ReflectionUtils.makeAccessible(method); + method.invoke(target, possiblyConvertedNewValue); + return; + } + catch (Exception ex) { + throw new AccessException("Unable to access property '" + name + "' through setter", ex); + } + } + } + + if (cachedMember == null || cachedMember instanceof Field) { + Field field = (Field) cachedMember; + if (field == null) { + field = findField(name, type, target instanceof Class); + if (field != null) { + cachedMember = field; + this.writerCache.put(cacheKey, cachedMember); + } + } + if (field != null) { + try { + ReflectionUtils.makeAccessible(field); + field.set(target, possiblyConvertedNewValue); + return; + } + catch (Exception ex) { + throw new AccessException("Unable to access field: " + name, ex); + } + } + } + + throw new AccessException("Neither setter nor field found for property '" + name + "'"); + } + + private TypeDescriptor getTypeDescriptor(EvaluationContext context, Object target, String name) { + if (target == null) { + return null; + } + Class type = (target instanceof Class ? (Class) target : target.getClass()); + + if (type.isArray() && name.equals("length")) { + return TypeDescriptor.valueOf(Integer.TYPE); + } + CacheKey cacheKey = new CacheKey(type, name); + TypeDescriptor typeDescriptor = this.typeDescriptorCache.get(cacheKey); + if (typeDescriptor == null) { + // attempt to populate the cache entry + try { + if (canRead(context, target, name)) { + typeDescriptor = this.typeDescriptorCache.get(cacheKey); + } + else if (canWrite(context, target, name)) { + typeDescriptor = this.typeDescriptorCache.get(cacheKey); + } + } + catch (AccessException ex) { + // continue with null type descriptor + } + } + return typeDescriptor; + } + + /** + * Find a getter method for the specified property. A getter is defined as a method whose name start with the prefix + * 'get' and the rest of the name is the same as the property name (with the first character uppercased). + */ + protected Method findGetterForProperty(String propertyName, Class clazz, boolean mustBeStatic) { + Method[] ms = clazz.getMethods(); + // Try "get*" method... + String getterName = "get" + StringUtils.capitalize(propertyName); + for (Method method : ms) { + if (method.getName().equals(getterName) && method.getParameterTypes().length == 0 && + (!mustBeStatic || Modifier.isStatic(method.getModifiers()))) { + return method; + } + } + // Try "is*" method... + getterName = "is" + StringUtils.capitalize(propertyName); + for (Method method : ms) { + if (method.getName().equals(getterName) && method.getParameterTypes().length == 0 && + boolean.class.equals(method.getReturnType()) && + (!mustBeStatic || Modifier.isStatic(method.getModifiers()))) { + return method; + } + } + return null; + } + + /** + * Find a setter method for the specified property. + */ + protected Method findSetterForProperty(String propertyName, Class clazz, boolean mustBeStatic) { + Method[] methods = clazz.getMethods(); + String setterName = "set" + StringUtils.capitalize(propertyName); + for (Method method : methods) { + if (method.getName().equals(setterName) && method.getParameterTypes().length == 1 && + (!mustBeStatic || Modifier.isStatic(method.getModifiers()))) { + return method; + } + } + return null; + } + + /** + * Find a field of a certain name on a specified class + */ + protected Field findField(String name, Class clazz, boolean mustBeStatic) { + Field[] fields = clazz.getFields(); + for (Field field : fields) { + if (field.getName().equals(name) && (!mustBeStatic || Modifier.isStatic(field.getModifiers()))) { + return field; + } + } + return null; + } + + /** + * Captures the member (method/field) to call reflectively to access a property value and the type descriptor for the + * value returned by the reflective call. + */ + private static class InvokerPair { + + final Member member; + + final TypeDescriptor typeDescriptor; + + public InvokerPair(Member member, TypeDescriptor typeDescriptor) { + this.member = member; + this.typeDescriptor = typeDescriptor; + } + + } + + private static class CacheKey { + + private final Class clazz; + + private final String name; + + public CacheKey(Class clazz, String name) { + this.clazz = clazz; + this.name = name; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof CacheKey)) { + return false; + } + CacheKey otherKey = (CacheKey) other; + return (this.clazz.equals(otherKey.clazz) && this.name.equals(otherKey.name)); + } + + @Override + public int hashCode() { + return this.clazz.hashCode() * 29 + this.name.hashCode(); + } + } + + /** + * Attempt to create an optimized property accessor tailored for a property of a particular name on + * a particular class. The general ReflectivePropertyAccessor will always work but is not optimal + * due to the need to lookup which reflective member (method/field) to use each time read() is called. + * This method will just return the ReflectivePropertyAccessor instance if it is unable to build + * something more optimal. + */ + public PropertyAccessor createOptimalAccessor(EvaluationContext eContext, Object target, String name) { + // Don't be clever for arrays or null target + if (target == null) { + return this; + } + Class type = (target instanceof Class ? (Class) target : target.getClass()); + if (type.isArray()) { + return this; + } + + CacheKey cacheKey = new CacheKey(type, name); + InvokerPair invocationTarget = this.readerCache.get(cacheKey); + + if (invocationTarget == null || invocationTarget.member instanceof Method) { + Method method = (Method) (invocationTarget==null?null:invocationTarget.member); + if (method == null) { + method = findGetterForProperty(name, type, target instanceof Class); + if (method != null) { + invocationTarget = new InvokerPair(method,new TypeDescriptor(new MethodParameter(method,-1))); + ReflectionUtils.makeAccessible(method); + this.readerCache.put(cacheKey, invocationTarget); + } + } + if (method != null) { + return new OptimalPropertyAccessor(invocationTarget); + } + } + + if (invocationTarget == null || invocationTarget.member instanceof Field) { + Field field = (Field) (invocationTarget==null?null:invocationTarget.member); + if (field == null) { + field = findField(name, type, target instanceof Class); + if (field != null) { + invocationTarget = new InvokerPair(field, new TypeDescriptor(field)); + ReflectionUtils.makeAccessible(field); + this.readerCache.put(cacheKey, invocationTarget); + } + } + if (field != null) { + return new OptimalPropertyAccessor(invocationTarget); + } + } + return this; + } + + /** + * An optimized form of a PropertyAccessor that will use reflection but only knows how to access a particular property + * on a particular class. This is unlike the general ReflectivePropertyResolver which manages a cache of methods/fields that + * may be invoked to access different properties on different classes. This optimal accessor exists because looking up + * the appropriate reflective object by class/name on each read is not cheap. + */ + static class OptimalPropertyAccessor implements PropertyAccessor { + private final Member member; + private final TypeDescriptor typeDescriptor; + private final boolean needsToBeMadeAccessible; + + OptimalPropertyAccessor(InvokerPair target) { + this.member = target.member; + this.typeDescriptor = target.typeDescriptor; + if (this.member instanceof Field) { + Field field = (Field)member; + needsToBeMadeAccessible = (!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())) + && !field.isAccessible(); + } + else { + Method method = (Method)member; + needsToBeMadeAccessible = ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) + && !method.isAccessible()); + } + } + + public Class[] getSpecificTargetClasses() { + throw new UnsupportedOperationException("Should not be called on an OptimalPropertyAccessor"); + } + + public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { + if (target == null) { + return false; + } + Class type = (target instanceof Class ? (Class) target : target.getClass()); + if (type.isArray()) { + return false; + } + if (member instanceof Method) { + Method method = (Method)member; + String getterName = "get" + StringUtils.capitalize(name); + if (getterName.equals(method.getName())) { + return true; + } + getterName = "is" + StringUtils.capitalize(name); + return getterName.equals(method.getName()); + } + else { + Field field = (Field)member; + return field.getName().equals(name); + } + } + + public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { + if (member instanceof Method) { + try { + if (needsToBeMadeAccessible) { + ReflectionUtils.makeAccessible((Method) member); + } + Object value = ((Method) member).invoke(target); + return new TypedValue(value, typeDescriptor.narrow(value)); + } + catch (Exception ex) { + throw new AccessException("Unable to access property '" + name + "' through getter", ex); + } + } + if (member instanceof Field) { + try { + if (needsToBeMadeAccessible) { + ReflectionUtils.makeAccessible((Field)member); + } + Object value = ((Field)member).get(target); + return new TypedValue(value, typeDescriptor.narrow(value)); + } + catch (Exception ex) { + throw new AccessException("Unable to access field: " + name, ex); + } + } + throw new AccessException("Neither getter nor field found for property '" + name + "'"); + } + + public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { + throw new UnsupportedOperationException("Should not be called on an OptimalPropertyAccessor"); + } + + public void write(EvaluationContext context, Object target, String name, Object newValue) + throws AccessException { + throw new UnsupportedOperationException("Should not be called on an OptimalPropertyAccessor"); + } + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/StandardOperatorOverloader.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/StandardOperatorOverloader.java index 0b03aa702a..5b42d0a010 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/StandardOperatorOverloader.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/StandardOperatorOverloader.java @@ -1,38 +1,38 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel.support; - -import org.springframework.expression.EvaluationException; -import org.springframework.expression.Operation; -import org.springframework.expression.OperatorOverloader; - -/** - * @author Juergen Hoeller - * @since 3.0 - */ -public class StandardOperatorOverloader implements OperatorOverloader { - - public boolean overridesOperation(Operation operation, Object leftOperand, Object rightOperand) - throws EvaluationException { - return false; - } - - public Object operate(Operation operation, Object leftOperand, Object rightOperand) throws EvaluationException { - throw new EvaluationException("No operation overloaded by default"); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel.support; + +import org.springframework.expression.EvaluationException; +import org.springframework.expression.Operation; +import org.springframework.expression.OperatorOverloader; + +/** + * @author Juergen Hoeller + * @since 3.0 + */ +public class StandardOperatorOverloader implements OperatorOverloader { + + public boolean overridesOperation(Operation operation, Object leftOperand, Object rightOperand) + throws EvaluationException { + return false; + } + + public Object operate(Operation operation, Object leftOperand, Object rightOperand) throws EvaluationException { + throw new EvaluationException("No operation overloaded by default"); + } + +} diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/StandardTypeConverter.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/StandardTypeConverter.java index 52039e35c7..49c0b3c2bd 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/StandardTypeConverter.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/StandardTypeConverter.java @@ -1,76 +1,76 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel.support; - -import org.springframework.core.convert.ConversionException; -import org.springframework.core.convert.ConversionService; -import org.springframework.core.convert.ConverterNotFoundException; -import org.springframework.core.convert.TypeDescriptor; -import org.springframework.core.convert.support.DefaultConversionService; -import org.springframework.expression.TypeConverter; -import org.springframework.expression.spel.SpelEvaluationException; -import org.springframework.expression.spel.SpelMessage; -import org.springframework.util.Assert; - -/** - * Default implementation of the {@link TypeConverter} interface, - * delegating to a core Spring {@link ConversionService}. - * - * @author Juergen Hoeller - * @author Andy Clement - * @since 3.0 - * @see org.springframework.core.convert.ConversionService - */ -public class StandardTypeConverter implements TypeConverter { - - private static ConversionService defaultConversionService; - - private final ConversionService conversionService; - - - public StandardTypeConverter() { - synchronized (this) { - if (defaultConversionService == null) { - defaultConversionService = new DefaultConversionService(); - } - } - this.conversionService = defaultConversionService; - } - - public StandardTypeConverter(ConversionService conversionService) { - Assert.notNull(conversionService, "ConversionService must not be null"); - this.conversionService = conversionService; - } - - - public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) { - return this.conversionService.canConvert(sourceType, targetType); - } - - public Object convertValue(Object value, TypeDescriptor sourceType, TypeDescriptor targetType) { - try { - return this.conversionService.convert(value, sourceType, targetType); - } - catch (ConverterNotFoundException cenfe) { - throw new SpelEvaluationException(cenfe, SpelMessage.TYPE_CONVERSION_ERROR, sourceType.toString(), targetType.toString()); - } - catch (ConversionException ce) { - throw new SpelEvaluationException(ce, SpelMessage.TYPE_CONVERSION_ERROR, sourceType.toString(), targetType.toString()); - } - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel.support; + +import org.springframework.core.convert.ConversionException; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.ConverterNotFoundException; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.core.convert.support.DefaultConversionService; +import org.springframework.expression.TypeConverter; +import org.springframework.expression.spel.SpelEvaluationException; +import org.springframework.expression.spel.SpelMessage; +import org.springframework.util.Assert; + +/** + * Default implementation of the {@link TypeConverter} interface, + * delegating to a core Spring {@link ConversionService}. + * + * @author Juergen Hoeller + * @author Andy Clement + * @since 3.0 + * @see org.springframework.core.convert.ConversionService + */ +public class StandardTypeConverter implements TypeConverter { + + private static ConversionService defaultConversionService; + + private final ConversionService conversionService; + + + public StandardTypeConverter() { + synchronized (this) { + if (defaultConversionService == null) { + defaultConversionService = new DefaultConversionService(); + } + } + this.conversionService = defaultConversionService; + } + + public StandardTypeConverter(ConversionService conversionService) { + Assert.notNull(conversionService, "ConversionService must not be null"); + this.conversionService = conversionService; + } + + + public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) { + return this.conversionService.canConvert(sourceType, targetType); + } + + public Object convertValue(Object value, TypeDescriptor sourceType, TypeDescriptor targetType) { + try { + return this.conversionService.convert(value, sourceType, targetType); + } + catch (ConverterNotFoundException cenfe) { + throw new SpelEvaluationException(cenfe, SpelMessage.TYPE_CONVERSION_ERROR, sourceType.toString(), targetType.toString()); + } + catch (ConversionException ce) { + throw new SpelEvaluationException(ce, SpelMessage.TYPE_CONVERSION_ERROR, sourceType.toString(), targetType.toString()); + } + } + +} diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/SpelUtilities.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/SpelUtilities.java index 6190834328..1833cc983a 100644 --- a/org.springframework.expression/src/test/java/org/springframework/expression/spel/SpelUtilities.java +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/SpelUtilities.java @@ -1,58 +1,58 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel; - -import java.io.PrintStream; - -import org.springframework.expression.Expression; -import org.springframework.expression.spel.standard.SpelExpression; - -/** - * Utilities for working with Spring Expressions. - * - * @author Andy Clement - */ -public class SpelUtilities { - - /** - * Output an indented representation of the expression syntax tree to the specified output stream. - * @param printStream the output stream to print into - * @param expression the expression to be displayed - */ - public static void printAbstractSyntaxTree(PrintStream printStream, Expression expression) { - printStream.println("===> Expression '" + expression.getExpressionString() + "' - AST start"); - printAST(printStream, ((SpelExpression) expression).getAST(), ""); - printStream.println("===> Expression '" + expression.getExpressionString() + "' - AST end"); - } - - /* - * Helper method for printing the AST with indentation - */ - private static void printAST(PrintStream out, SpelNode t, String indent) { - if (t != null) { - StringBuilder sb = new StringBuilder(); - sb.append(indent).append(t.getClass().getSimpleName()); - sb.append(" value:").append(t.toStringAST()); - sb.append(t.getChildCount() < 2 ? "" : " #children:" + t.getChildCount()); - out.println(sb.toString()); - for (int i = 0; i < t.getChildCount(); i++) { - printAST(out, t.getChild(i), indent + " "); - } - } - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel; + +import java.io.PrintStream; + +import org.springframework.expression.Expression; +import org.springframework.expression.spel.standard.SpelExpression; + +/** + * Utilities for working with Spring Expressions. + * + * @author Andy Clement + */ +public class SpelUtilities { + + /** + * Output an indented representation of the expression syntax tree to the specified output stream. + * @param printStream the output stream to print into + * @param expression the expression to be displayed + */ + public static void printAbstractSyntaxTree(PrintStream printStream, Expression expression) { + printStream.println("===> Expression '" + expression.getExpressionString() + "' - AST start"); + printAST(printStream, ((SpelExpression) expression).getAST(), ""); + printStream.println("===> Expression '" + expression.getExpressionString() + "' - AST end"); + } + + /* + * Helper method for printing the AST with indentation + */ + private static void printAST(PrintStream out, SpelNode t, String indent) { + if (t != null) { + StringBuilder sb = new StringBuilder(); + sb.append(indent).append(t.getClass().getSimpleName()); + sb.append(" value:").append(t.toStringAST()); + sb.append(t.getChildCount() < 2 ? "" : " #children:" + t.getChildCount()); + out.println(sb.toString()); + for (int i = 0; i < t.getChildCount(); i++) { + printAST(out, t.getChild(i), indent + " "); + } + } + } + +} diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/ast/FormatHelperTests.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/ast/FormatHelperTests.java index abd8ed775e..b40ec92a98 100644 --- a/org.springframework.expression/src/test/java/org/springframework/expression/spel/ast/FormatHelperTests.java +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/ast/FormatHelperTests.java @@ -1,44 +1,44 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel.ast; - -import java.util.Arrays; - -import org.junit.Test; - -import org.springframework.core.convert.TypeDescriptor; - -import static org.junit.Assert.*; - -/** - * @author Andy Wilkinson - */ -public class FormatHelperTests { - - @Test - public void formatMethodWithSingleArgumentForMessage() { - String message = FormatHelper.formatMethodForMessage("foo", Arrays.asList(TypeDescriptor.forObject("a string"))); - assertEquals("foo(java.lang.String)", message); - } - - @Test - public void formatMethodWithMultipleArgumentsForMessage() { - String message = FormatHelper.formatMethodForMessage("foo", Arrays.asList(TypeDescriptor.forObject("a string"), TypeDescriptor.forObject(Integer.valueOf(5)))); - assertEquals("foo(java.lang.String,java.lang.Integer)", message); - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel.ast; + +import java.util.Arrays; + +import org.junit.Test; + +import org.springframework.core.convert.TypeDescriptor; + +import static org.junit.Assert.*; + +/** + * @author Andy Wilkinson + */ +public class FormatHelperTests { + + @Test + public void formatMethodWithSingleArgumentForMessage() { + String message = FormatHelper.formatMethodForMessage("foo", Arrays.asList(TypeDescriptor.forObject("a string"))); + assertEquals("foo(java.lang.String)", message); + } + + @Test + public void formatMethodWithMultipleArgumentsForMessage() { + String message = FormatHelper.formatMethodForMessage("foo", Arrays.asList(TypeDescriptor.forObject("a string"), TypeDescriptor.forObject(Integer.valueOf(5)))); + assertEquals("foo(java.lang.String,java.lang.Integer)", message); + } + +} diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/standard/PropertiesConversionSpelTests.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/standard/PropertiesConversionSpelTests.java index ebac11450e..bf3435d55b 100644 --- a/org.springframework.expression/src/test/java/org/springframework/expression/spel/standard/PropertiesConversionSpelTests.java +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/standard/PropertiesConversionSpelTests.java @@ -1,106 +1,106 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel.standard; - -import static org.junit.Assert.assertEquals; - -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; -import java.util.UUID; - -import org.junit.Test; - -import org.springframework.expression.Expression; -import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.expression.spel.support.StandardEvaluationContext; - -/** - * @author Mark Fisher - */ -public class PropertiesConversionSpelTests { - - private static final SpelExpressionParser parser = new SpelExpressionParser(); - - @Test - public void props() { - Properties props = new Properties(); - props.setProperty("x", "1"); - props.setProperty("y", "2"); - props.setProperty("z", "3"); - Expression expression = parser.parseExpression("foo(#props)"); - StandardEvaluationContext context = new StandardEvaluationContext(); - context.setVariable("props", props); - String result = expression.getValue(context, new TestBean(), String.class); - assertEquals("123", result); - } - - @Test - public void mapWithAllStringValues() { - Map map = new HashMap(); - map.put("x", "1"); - map.put("y", "2"); - map.put("z", "3"); - Expression expression = parser.parseExpression("foo(#props)"); - StandardEvaluationContext context = new StandardEvaluationContext(); - context.setVariable("props", map); - String result = expression.getValue(context, new TestBean(), String.class); - assertEquals("123", result); - } - - @Test - public void mapWithNonStringValue() { - Map map = new HashMap(); - map.put("x", "1"); - map.put("y", 2); - map.put("z", "3"); - map.put("a", new UUID(1, 1)); - Expression expression = parser.parseExpression("foo(#props)"); - StandardEvaluationContext context = new StandardEvaluationContext(); - context.setVariable("props", map); - String result = expression.getValue(context, new TestBean(), String.class); - assertEquals("1null3", result); - } - - @Test - public void customMapWithNonStringValue() { - CustomMap map = new CustomMap(); - map.put("x", "1"); - map.put("y", 2); - map.put("z", "3"); - Expression expression = parser.parseExpression("foo(#props)"); - StandardEvaluationContext context = new StandardEvaluationContext(); - context.setVariable("props", map); - String result = expression.getValue(context, new TestBean(), String.class); - assertEquals("1null3", result); - } - - - private static class TestBean { - - @SuppressWarnings("unused") - public String foo(Properties props) { - return props.getProperty("x") + props.getProperty("y") + props.getProperty("z"); - } - } - - - @SuppressWarnings("serial") - private static class CustomMap extends HashMap { - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel.standard; + +import static org.junit.Assert.assertEquals; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.UUID; + +import org.junit.Test; + +import org.springframework.expression.Expression; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; + +/** + * @author Mark Fisher + */ +public class PropertiesConversionSpelTests { + + private static final SpelExpressionParser parser = new SpelExpressionParser(); + + @Test + public void props() { + Properties props = new Properties(); + props.setProperty("x", "1"); + props.setProperty("y", "2"); + props.setProperty("z", "3"); + Expression expression = parser.parseExpression("foo(#props)"); + StandardEvaluationContext context = new StandardEvaluationContext(); + context.setVariable("props", props); + String result = expression.getValue(context, new TestBean(), String.class); + assertEquals("123", result); + } + + @Test + public void mapWithAllStringValues() { + Map map = new HashMap(); + map.put("x", "1"); + map.put("y", "2"); + map.put("z", "3"); + Expression expression = parser.parseExpression("foo(#props)"); + StandardEvaluationContext context = new StandardEvaluationContext(); + context.setVariable("props", map); + String result = expression.getValue(context, new TestBean(), String.class); + assertEquals("123", result); + } + + @Test + public void mapWithNonStringValue() { + Map map = new HashMap(); + map.put("x", "1"); + map.put("y", 2); + map.put("z", "3"); + map.put("a", new UUID(1, 1)); + Expression expression = parser.parseExpression("foo(#props)"); + StandardEvaluationContext context = new StandardEvaluationContext(); + context.setVariable("props", map); + String result = expression.getValue(context, new TestBean(), String.class); + assertEquals("1null3", result); + } + + @Test + public void customMapWithNonStringValue() { + CustomMap map = new CustomMap(); + map.put("x", "1"); + map.put("y", 2); + map.put("z", "3"); + Expression expression = parser.parseExpression("foo(#props)"); + StandardEvaluationContext context = new StandardEvaluationContext(); + context.setVariable("props", map); + String result = expression.getValue(context, new TestBean(), String.class); + assertEquals("1null3", result); + } + + + private static class TestBean { + + @SuppressWarnings("unused") + public String foo(Properties props) { + return props.getProperty("x") + props.getProperty("y") + props.getProperty("z"); + } + } + + + @SuppressWarnings("serial") + private static class CustomMap extends HashMap { + } + +} diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/standard/SpelParserTests.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/standard/SpelParserTests.java index 00ddff35f4..cc9f83883e 100644 --- a/org.springframework.expression/src/test/java/org/springframework/expression/spel/standard/SpelParserTests.java +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/standard/SpelParserTests.java @@ -1,370 +1,370 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel.standard; - -import junit.framework.Assert; - -import org.junit.Test; -import org.springframework.expression.EvaluationContext; -import org.springframework.expression.EvaluationException; -import org.springframework.expression.ExpressionException; -import org.springframework.expression.ParseException; -import org.springframework.expression.spel.SpelMessage; -import org.springframework.expression.spel.SpelNode; -import org.springframework.expression.spel.SpelParseException; -import org.springframework.expression.spel.ast.OpAnd; -import org.springframework.expression.spel.ast.OpOr; -import org.springframework.expression.spel.support.StandardEvaluationContext; - -/** - * @author Andy Clement - */ -public class SpelParserTests { - - @Test - public void theMostBasic() throws EvaluationException,ParseException { - SpelExpressionParser parser = new SpelExpressionParser(); - SpelExpression expr = parser.parseRaw("2"); - Assert.assertNotNull(expr); - Assert.assertNotNull(expr.getAST()); - Assert.assertEquals(2,expr.getValue()); - Assert.assertEquals(Integer.class,expr.getValueType()); - Assert.assertEquals(2,expr.getAST().getValue(null)); - } - - @Test - public void valueType() throws Exception { - SpelExpressionParser parser = new SpelExpressionParser(); - EvaluationContext ctx = new StandardEvaluationContext(); - Class c = parser.parseRaw("2").getValueType(); - Assert.assertEquals(Integer.class,c); - c = parser.parseRaw("12").getValueType(ctx); - Assert.assertEquals(Integer.class,c); - c = parser.parseRaw("null").getValueType(); - Assert.assertNull(c); - c = parser.parseRaw("null").getValueType(ctx); - Assert.assertNull(c); - Object o = parser.parseRaw("null").getValue(ctx,Integer.class); - Assert.assertNull(o); - } - - @Test - public void whitespace() throws EvaluationException,ParseException { - SpelExpressionParser parser = new SpelExpressionParser(); - SpelExpression expr = parser.parseRaw("2 + 3"); - Assert.assertEquals(5,expr.getValue()); - expr = parser.parseRaw("2 + 3"); - Assert.assertEquals(5,expr.getValue()); - expr = parser.parseRaw("2\n+ 3"); - Assert.assertEquals(5,expr.getValue()); - expr = parser.parseRaw("2\r\n+\t3"); - Assert.assertEquals(5,expr.getValue()); - } - - @Test - public void arithmeticPlus1() throws EvaluationException,ParseException { - SpelExpressionParser parser = new SpelExpressionParser(); - SpelExpression expr = parser.parseRaw("2+2"); - Assert.assertNotNull(expr); - Assert.assertNotNull(expr.getAST()); - Assert.assertEquals(4,expr.getValue()); - } - - @Test - public void arithmeticPlus2() throws EvaluationException,ParseException { - SpelExpressionParser parser = new SpelExpressionParser(); - SpelExpression expr = parser.parseRaw("37+41"); - Assert.assertEquals(78,expr.getValue()); - } - - @Test - public void arithmeticMultiply1() throws EvaluationException,ParseException { - SpelExpressionParser parser = new SpelExpressionParser(); - SpelExpression expr = parser.parseRaw("2*3"); - Assert.assertNotNull(expr); - Assert.assertNotNull(expr.getAST()); -// printAst(expr.getAST(),0); - Assert.assertEquals(6,expr.getValue()); - } - - @Test - public void arithmeticPrecedence1() throws EvaluationException,ParseException { - SpelExpressionParser parser = new SpelExpressionParser(); - SpelExpression expr = parser.parseRaw("2*3+5"); - Assert.assertEquals(11,expr.getValue()); - } - - @Test - public void generalExpressions() throws Exception { - try { - SpelExpressionParser parser = new SpelExpressionParser(); - parser.parseRaw("new String"); - Assert.fail(); - } catch (ParseException e) { - Assert.assertTrue(e instanceof SpelParseException); - SpelParseException spe = (SpelParseException)e; - Assert.assertEquals(SpelMessage.MISSING_CONSTRUCTOR_ARGS,spe.getMessageCode()); - Assert.assertEquals(10,spe.getPosition()); - } - try { - SpelExpressionParser parser = new SpelExpressionParser(); - parser.parseRaw("new String(3,"); - Assert.fail(); - } catch (ParseException e) { - Assert.assertTrue(e instanceof SpelParseException); - SpelParseException spe = (SpelParseException)e; - Assert.assertEquals(SpelMessage.RUN_OUT_OF_ARGUMENTS,spe.getMessageCode()); - Assert.assertEquals(10,spe.getPosition()); - } - try { - SpelExpressionParser parser = new SpelExpressionParser(); - parser.parseRaw("new String(3"); - Assert.fail(); - } catch (ParseException e) { - Assert.assertTrue(e instanceof SpelParseException); - SpelParseException spe = (SpelParseException)e; - Assert.assertEquals(SpelMessage.RUN_OUT_OF_ARGUMENTS,spe.getMessageCode()); - Assert.assertEquals(10,spe.getPosition()); - } - try { - SpelExpressionParser parser = new SpelExpressionParser(); - parser.parseRaw("new String("); - Assert.fail(); - } catch (ParseException e) { - Assert.assertTrue(e instanceof SpelParseException); - SpelParseException spe = (SpelParseException)e; - Assert.assertEquals(SpelMessage.RUN_OUT_OF_ARGUMENTS,spe.getMessageCode()); - Assert.assertEquals(10,spe.getPosition()); - } - try { - SpelExpressionParser parser = new SpelExpressionParser(); - parser.parseRaw("\"abc"); - Assert.fail(); - } catch (ParseException e) { - Assert.assertTrue(e instanceof SpelParseException); - SpelParseException spe = (SpelParseException)e; - Assert.assertEquals(SpelMessage.NON_TERMINATING_DOUBLE_QUOTED_STRING,spe.getMessageCode()); - Assert.assertEquals(0,spe.getPosition()); - } - try { - SpelExpressionParser parser = new SpelExpressionParser(); - parser.parseRaw("'abc"); - Assert.fail(); - } catch (ParseException e) { - Assert.assertTrue(e instanceof SpelParseException); - SpelParseException spe = (SpelParseException)e; - Assert.assertEquals(SpelMessage.NON_TERMINATING_QUOTED_STRING,spe.getMessageCode()); - Assert.assertEquals(0,spe.getPosition()); - } - - } - - @Test - public void arithmeticPrecedence2() throws EvaluationException,ParseException { - SpelExpressionParser parser = new SpelExpressionParser(); - SpelExpression expr = parser.parseRaw("2+3*5"); - Assert.assertEquals(17,expr.getValue()); - } - - @Test - public void arithmeticPrecedence3() throws EvaluationException,ParseException { - SpelExpression expr = new SpelExpressionParser().parseRaw("3+10/2"); - Assert.assertEquals(8,expr.getValue()); - } - - @Test - public void arithmeticPrecedence4() throws EvaluationException,ParseException { - SpelExpression expr = new SpelExpressionParser().parseRaw("10/2+3"); - Assert.assertEquals(8,expr.getValue()); - } - - @Test - public void arithmeticPrecedence5() throws EvaluationException,ParseException { - SpelExpression expr = new SpelExpressionParser().parseRaw("(4+10)/2"); - Assert.assertEquals(7,expr.getValue()); - } - - @Test - public void arithmeticPrecedence6() throws EvaluationException,ParseException { - SpelExpression expr = new SpelExpressionParser().parseRaw("(3+2)*2"); - Assert.assertEquals(10,expr.getValue()); - } - - @Test - public void booleanOperators() throws EvaluationException,ParseException { - SpelExpression expr = new SpelExpressionParser().parseRaw("true"); - Assert.assertEquals(Boolean.TRUE,expr.getValue(Boolean.class)); - expr = new SpelExpressionParser().parseRaw("false"); - Assert.assertEquals(Boolean.FALSE,expr.getValue(Boolean.class)); - expr = new SpelExpressionParser().parseRaw("false and false"); - Assert.assertEquals(Boolean.FALSE,expr.getValue(Boolean.class)); - expr = new SpelExpressionParser().parseRaw("true and (true or false)"); - Assert.assertEquals(Boolean.TRUE,expr.getValue(Boolean.class)); - expr = new SpelExpressionParser().parseRaw("true and true or false"); - Assert.assertEquals(Boolean.TRUE,expr.getValue(Boolean.class)); - expr = new SpelExpressionParser().parseRaw("!true"); - Assert.assertEquals(Boolean.FALSE,expr.getValue(Boolean.class)); - expr = new SpelExpressionParser().parseRaw("!(false or true)"); - Assert.assertEquals(Boolean.FALSE,expr.getValue(Boolean.class)); - } - - @Test - public void testStringLiterals() throws EvaluationException,ParseException { - SpelExpression expr = new SpelExpressionParser().parseRaw("'howdy'"); - Assert.assertEquals("howdy",expr.getValue()); - expr = new SpelExpressionParser().parseRaw("'hello '' world'"); - Assert.assertEquals("hello ' world",expr.getValue()); - } - - @Test - public void testStringLiterals2() throws EvaluationException,ParseException { - SpelExpression expr = new SpelExpressionParser().parseRaw("'howdy'.substring(0,2)"); - Assert.assertEquals("ho",expr.getValue()); - } - - @Test - public void testPositionalInformation() throws EvaluationException, ParseException { - SpelExpression expr = new SpelExpressionParser().parseRaw("true and true or false"); - SpelNode rootAst = expr.getAST(); - OpOr operatorOr = (OpOr)rootAst; - OpAnd operatorAnd = (OpAnd)operatorOr.getLeftOperand(); - SpelNode rightOrOperand = operatorOr.getRightOperand(); - - // check position for final 'false' - Assert.assertEquals(17, rightOrOperand.getStartPosition()); - Assert.assertEquals(22, rightOrOperand.getEndPosition()); - - // check position for first 'true' - Assert.assertEquals(0, operatorAnd.getLeftOperand().getStartPosition()); - Assert.assertEquals(4, operatorAnd.getLeftOperand().getEndPosition()); - - // check position for second 'true' - Assert.assertEquals(9, operatorAnd.getRightOperand().getStartPosition()); - Assert.assertEquals(13, operatorAnd.getRightOperand().getEndPosition()); - - // check position for OperatorAnd - Assert.assertEquals(5, operatorAnd.getStartPosition()); - Assert.assertEquals(8, operatorAnd.getEndPosition()); - - // check position for OperatorOr - Assert.assertEquals(14, operatorOr.getStartPosition()); - Assert.assertEquals(16, operatorOr.getEndPosition()); - } - - @Test - public void testTokenKind() { - TokenKind tk = TokenKind.NOT; - Assert.assertFalse(tk.hasPayload()); - Assert.assertEquals("NOT(!)",tk.toString()); - - tk = TokenKind.MINUS; - Assert.assertFalse(tk.hasPayload()); - Assert.assertEquals("MINUS(-)",tk.toString()); - - tk = TokenKind.LITERAL_STRING; - Assert.assertEquals("LITERAL_STRING",tk.toString()); - Assert.assertTrue(tk.hasPayload()); - } - - @Test - public void testToken() { - Token token = new Token(TokenKind.NOT,0,3); - Assert.assertEquals(TokenKind.NOT,token.kind); - Assert.assertEquals(0,token.startpos); - Assert.assertEquals(3,token.endpos); - Assert.assertEquals("[NOT(!)](0,3)",token.toString()); - - token = new Token(TokenKind.LITERAL_STRING,"abc".toCharArray(),0,3); - Assert.assertEquals(TokenKind.LITERAL_STRING,token.kind); - Assert.assertEquals(0,token.startpos); - Assert.assertEquals(3,token.endpos); - Assert.assertEquals("[LITERAL_STRING:abc](0,3)",token.toString()); - } - - @Test - public void testExceptions() { - ExpressionException exprEx = new ExpressionException("test"); - Assert.assertEquals("test", exprEx.getMessage()); - Assert.assertEquals("test", exprEx.toDetailedString()); - - exprEx = new ExpressionException("wibble","test"); - Assert.assertEquals("test", exprEx.getMessage()); - Assert.assertEquals("Expression 'wibble': test", exprEx.toDetailedString()); - - exprEx = new ExpressionException("wibble",3, "test"); - Assert.assertEquals("test", exprEx.getMessage()); - Assert.assertEquals("Expression 'wibble' @ 3: test", exprEx.toDetailedString()); - } - - @Test - public void testNumerics() { - checkNumber("2",2,Integer.class); - checkNumber("22",22,Integer.class); - checkNumber("+22",22,Integer.class); - checkNumber("-22",-22,Integer.class); - - checkNumber("2L",2L,Long.class); - checkNumber("22l",22L,Long.class); - - checkNumber("0x1",1,Integer.class); - checkNumber("0x1L",1L,Long.class); - checkNumber("0xa",10,Integer.class); - checkNumber("0xAL",10L,Long.class); - - checkNumberError("0x",SpelMessage.NOT_AN_INTEGER); - checkNumberError("0xL",SpelMessage.NOT_A_LONG); - - checkNumberError(".324",SpelMessage.UNEXPECTED_DATA_AFTER_DOT); - - checkNumberError("3.4L",SpelMessage.REAL_CANNOT_BE_LONG); - - // Number is parsed as a float, but immediately promoted to a double - checkNumber("3.5f",3.5d,Double.class); - - checkNumber("1.2e3", 1.2e3d, Double.class); - checkNumber("1.2e+3", 1.2e3d, Double.class); - checkNumber("1.2e-3", 1.2e-3d, Double.class); - checkNumber("1.2e3", 1.2e3d, Double.class); - checkNumber("1.e+3", 1.e3d, Double.class); - checkNumber("1e+3", 1e3d, Double.class); - } - - private void checkNumber(String expression, Object value, Class type) { - try { - SpelExpressionParser parser = new SpelExpressionParser(); - SpelExpression expr = parser.parseRaw(expression); - Object o = expr.getValue(); - Assert.assertEquals(value,o); - Assert.assertEquals(type,o.getClass()); - } catch (Exception e) { - e.printStackTrace(); - Assert.fail(e.getMessage()); - } - } - - private void checkNumberError(String expression, SpelMessage expectedMessage) { - try { - SpelExpressionParser parser = new SpelExpressionParser(); - parser.parseRaw(expression); - Assert.fail(); - } catch (ParseException e) { - Assert.assertTrue(e instanceof SpelParseException); - SpelParseException spe = (SpelParseException)e; - Assert.assertEquals(expectedMessage,spe.getMessageCode()); - } - } -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel.standard; + +import junit.framework.Assert; + +import org.junit.Test; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.ExpressionException; +import org.springframework.expression.ParseException; +import org.springframework.expression.spel.SpelMessage; +import org.springframework.expression.spel.SpelNode; +import org.springframework.expression.spel.SpelParseException; +import org.springframework.expression.spel.ast.OpAnd; +import org.springframework.expression.spel.ast.OpOr; +import org.springframework.expression.spel.support.StandardEvaluationContext; + +/** + * @author Andy Clement + */ +public class SpelParserTests { + + @Test + public void theMostBasic() throws EvaluationException,ParseException { + SpelExpressionParser parser = new SpelExpressionParser(); + SpelExpression expr = parser.parseRaw("2"); + Assert.assertNotNull(expr); + Assert.assertNotNull(expr.getAST()); + Assert.assertEquals(2,expr.getValue()); + Assert.assertEquals(Integer.class,expr.getValueType()); + Assert.assertEquals(2,expr.getAST().getValue(null)); + } + + @Test + public void valueType() throws Exception { + SpelExpressionParser parser = new SpelExpressionParser(); + EvaluationContext ctx = new StandardEvaluationContext(); + Class c = parser.parseRaw("2").getValueType(); + Assert.assertEquals(Integer.class,c); + c = parser.parseRaw("12").getValueType(ctx); + Assert.assertEquals(Integer.class,c); + c = parser.parseRaw("null").getValueType(); + Assert.assertNull(c); + c = parser.parseRaw("null").getValueType(ctx); + Assert.assertNull(c); + Object o = parser.parseRaw("null").getValue(ctx,Integer.class); + Assert.assertNull(o); + } + + @Test + public void whitespace() throws EvaluationException,ParseException { + SpelExpressionParser parser = new SpelExpressionParser(); + SpelExpression expr = parser.parseRaw("2 + 3"); + Assert.assertEquals(5,expr.getValue()); + expr = parser.parseRaw("2 + 3"); + Assert.assertEquals(5,expr.getValue()); + expr = parser.parseRaw("2\n+ 3"); + Assert.assertEquals(5,expr.getValue()); + expr = parser.parseRaw("2\r\n+\t3"); + Assert.assertEquals(5,expr.getValue()); + } + + @Test + public void arithmeticPlus1() throws EvaluationException,ParseException { + SpelExpressionParser parser = new SpelExpressionParser(); + SpelExpression expr = parser.parseRaw("2+2"); + Assert.assertNotNull(expr); + Assert.assertNotNull(expr.getAST()); + Assert.assertEquals(4,expr.getValue()); + } + + @Test + public void arithmeticPlus2() throws EvaluationException,ParseException { + SpelExpressionParser parser = new SpelExpressionParser(); + SpelExpression expr = parser.parseRaw("37+41"); + Assert.assertEquals(78,expr.getValue()); + } + + @Test + public void arithmeticMultiply1() throws EvaluationException,ParseException { + SpelExpressionParser parser = new SpelExpressionParser(); + SpelExpression expr = parser.parseRaw("2*3"); + Assert.assertNotNull(expr); + Assert.assertNotNull(expr.getAST()); +// printAst(expr.getAST(),0); + Assert.assertEquals(6,expr.getValue()); + } + + @Test + public void arithmeticPrecedence1() throws EvaluationException,ParseException { + SpelExpressionParser parser = new SpelExpressionParser(); + SpelExpression expr = parser.parseRaw("2*3+5"); + Assert.assertEquals(11,expr.getValue()); + } + + @Test + public void generalExpressions() throws Exception { + try { + SpelExpressionParser parser = new SpelExpressionParser(); + parser.parseRaw("new String"); + Assert.fail(); + } catch (ParseException e) { + Assert.assertTrue(e instanceof SpelParseException); + SpelParseException spe = (SpelParseException)e; + Assert.assertEquals(SpelMessage.MISSING_CONSTRUCTOR_ARGS,spe.getMessageCode()); + Assert.assertEquals(10,spe.getPosition()); + } + try { + SpelExpressionParser parser = new SpelExpressionParser(); + parser.parseRaw("new String(3,"); + Assert.fail(); + } catch (ParseException e) { + Assert.assertTrue(e instanceof SpelParseException); + SpelParseException spe = (SpelParseException)e; + Assert.assertEquals(SpelMessage.RUN_OUT_OF_ARGUMENTS,spe.getMessageCode()); + Assert.assertEquals(10,spe.getPosition()); + } + try { + SpelExpressionParser parser = new SpelExpressionParser(); + parser.parseRaw("new String(3"); + Assert.fail(); + } catch (ParseException e) { + Assert.assertTrue(e instanceof SpelParseException); + SpelParseException spe = (SpelParseException)e; + Assert.assertEquals(SpelMessage.RUN_OUT_OF_ARGUMENTS,spe.getMessageCode()); + Assert.assertEquals(10,spe.getPosition()); + } + try { + SpelExpressionParser parser = new SpelExpressionParser(); + parser.parseRaw("new String("); + Assert.fail(); + } catch (ParseException e) { + Assert.assertTrue(e instanceof SpelParseException); + SpelParseException spe = (SpelParseException)e; + Assert.assertEquals(SpelMessage.RUN_OUT_OF_ARGUMENTS,spe.getMessageCode()); + Assert.assertEquals(10,spe.getPosition()); + } + try { + SpelExpressionParser parser = new SpelExpressionParser(); + parser.parseRaw("\"abc"); + Assert.fail(); + } catch (ParseException e) { + Assert.assertTrue(e instanceof SpelParseException); + SpelParseException spe = (SpelParseException)e; + Assert.assertEquals(SpelMessage.NON_TERMINATING_DOUBLE_QUOTED_STRING,spe.getMessageCode()); + Assert.assertEquals(0,spe.getPosition()); + } + try { + SpelExpressionParser parser = new SpelExpressionParser(); + parser.parseRaw("'abc"); + Assert.fail(); + } catch (ParseException e) { + Assert.assertTrue(e instanceof SpelParseException); + SpelParseException spe = (SpelParseException)e; + Assert.assertEquals(SpelMessage.NON_TERMINATING_QUOTED_STRING,spe.getMessageCode()); + Assert.assertEquals(0,spe.getPosition()); + } + + } + + @Test + public void arithmeticPrecedence2() throws EvaluationException,ParseException { + SpelExpressionParser parser = new SpelExpressionParser(); + SpelExpression expr = parser.parseRaw("2+3*5"); + Assert.assertEquals(17,expr.getValue()); + } + + @Test + public void arithmeticPrecedence3() throws EvaluationException,ParseException { + SpelExpression expr = new SpelExpressionParser().parseRaw("3+10/2"); + Assert.assertEquals(8,expr.getValue()); + } + + @Test + public void arithmeticPrecedence4() throws EvaluationException,ParseException { + SpelExpression expr = new SpelExpressionParser().parseRaw("10/2+3"); + Assert.assertEquals(8,expr.getValue()); + } + + @Test + public void arithmeticPrecedence5() throws EvaluationException,ParseException { + SpelExpression expr = new SpelExpressionParser().parseRaw("(4+10)/2"); + Assert.assertEquals(7,expr.getValue()); + } + + @Test + public void arithmeticPrecedence6() throws EvaluationException,ParseException { + SpelExpression expr = new SpelExpressionParser().parseRaw("(3+2)*2"); + Assert.assertEquals(10,expr.getValue()); + } + + @Test + public void booleanOperators() throws EvaluationException,ParseException { + SpelExpression expr = new SpelExpressionParser().parseRaw("true"); + Assert.assertEquals(Boolean.TRUE,expr.getValue(Boolean.class)); + expr = new SpelExpressionParser().parseRaw("false"); + Assert.assertEquals(Boolean.FALSE,expr.getValue(Boolean.class)); + expr = new SpelExpressionParser().parseRaw("false and false"); + Assert.assertEquals(Boolean.FALSE,expr.getValue(Boolean.class)); + expr = new SpelExpressionParser().parseRaw("true and (true or false)"); + Assert.assertEquals(Boolean.TRUE,expr.getValue(Boolean.class)); + expr = new SpelExpressionParser().parseRaw("true and true or false"); + Assert.assertEquals(Boolean.TRUE,expr.getValue(Boolean.class)); + expr = new SpelExpressionParser().parseRaw("!true"); + Assert.assertEquals(Boolean.FALSE,expr.getValue(Boolean.class)); + expr = new SpelExpressionParser().parseRaw("!(false or true)"); + Assert.assertEquals(Boolean.FALSE,expr.getValue(Boolean.class)); + } + + @Test + public void testStringLiterals() throws EvaluationException,ParseException { + SpelExpression expr = new SpelExpressionParser().parseRaw("'howdy'"); + Assert.assertEquals("howdy",expr.getValue()); + expr = new SpelExpressionParser().parseRaw("'hello '' world'"); + Assert.assertEquals("hello ' world",expr.getValue()); + } + + @Test + public void testStringLiterals2() throws EvaluationException,ParseException { + SpelExpression expr = new SpelExpressionParser().parseRaw("'howdy'.substring(0,2)"); + Assert.assertEquals("ho",expr.getValue()); + } + + @Test + public void testPositionalInformation() throws EvaluationException, ParseException { + SpelExpression expr = new SpelExpressionParser().parseRaw("true and true or false"); + SpelNode rootAst = expr.getAST(); + OpOr operatorOr = (OpOr)rootAst; + OpAnd operatorAnd = (OpAnd)operatorOr.getLeftOperand(); + SpelNode rightOrOperand = operatorOr.getRightOperand(); + + // check position for final 'false' + Assert.assertEquals(17, rightOrOperand.getStartPosition()); + Assert.assertEquals(22, rightOrOperand.getEndPosition()); + + // check position for first 'true' + Assert.assertEquals(0, operatorAnd.getLeftOperand().getStartPosition()); + Assert.assertEquals(4, operatorAnd.getLeftOperand().getEndPosition()); + + // check position for second 'true' + Assert.assertEquals(9, operatorAnd.getRightOperand().getStartPosition()); + Assert.assertEquals(13, operatorAnd.getRightOperand().getEndPosition()); + + // check position for OperatorAnd + Assert.assertEquals(5, operatorAnd.getStartPosition()); + Assert.assertEquals(8, operatorAnd.getEndPosition()); + + // check position for OperatorOr + Assert.assertEquals(14, operatorOr.getStartPosition()); + Assert.assertEquals(16, operatorOr.getEndPosition()); + } + + @Test + public void testTokenKind() { + TokenKind tk = TokenKind.NOT; + Assert.assertFalse(tk.hasPayload()); + Assert.assertEquals("NOT(!)",tk.toString()); + + tk = TokenKind.MINUS; + Assert.assertFalse(tk.hasPayload()); + Assert.assertEquals("MINUS(-)",tk.toString()); + + tk = TokenKind.LITERAL_STRING; + Assert.assertEquals("LITERAL_STRING",tk.toString()); + Assert.assertTrue(tk.hasPayload()); + } + + @Test + public void testToken() { + Token token = new Token(TokenKind.NOT,0,3); + Assert.assertEquals(TokenKind.NOT,token.kind); + Assert.assertEquals(0,token.startpos); + Assert.assertEquals(3,token.endpos); + Assert.assertEquals("[NOT(!)](0,3)",token.toString()); + + token = new Token(TokenKind.LITERAL_STRING,"abc".toCharArray(),0,3); + Assert.assertEquals(TokenKind.LITERAL_STRING,token.kind); + Assert.assertEquals(0,token.startpos); + Assert.assertEquals(3,token.endpos); + Assert.assertEquals("[LITERAL_STRING:abc](0,3)",token.toString()); + } + + @Test + public void testExceptions() { + ExpressionException exprEx = new ExpressionException("test"); + Assert.assertEquals("test", exprEx.getMessage()); + Assert.assertEquals("test", exprEx.toDetailedString()); + + exprEx = new ExpressionException("wibble","test"); + Assert.assertEquals("test", exprEx.getMessage()); + Assert.assertEquals("Expression 'wibble': test", exprEx.toDetailedString()); + + exprEx = new ExpressionException("wibble",3, "test"); + Assert.assertEquals("test", exprEx.getMessage()); + Assert.assertEquals("Expression 'wibble' @ 3: test", exprEx.toDetailedString()); + } + + @Test + public void testNumerics() { + checkNumber("2",2,Integer.class); + checkNumber("22",22,Integer.class); + checkNumber("+22",22,Integer.class); + checkNumber("-22",-22,Integer.class); + + checkNumber("2L",2L,Long.class); + checkNumber("22l",22L,Long.class); + + checkNumber("0x1",1,Integer.class); + checkNumber("0x1L",1L,Long.class); + checkNumber("0xa",10,Integer.class); + checkNumber("0xAL",10L,Long.class); + + checkNumberError("0x",SpelMessage.NOT_AN_INTEGER); + checkNumberError("0xL",SpelMessage.NOT_A_LONG); + + checkNumberError(".324",SpelMessage.UNEXPECTED_DATA_AFTER_DOT); + + checkNumberError("3.4L",SpelMessage.REAL_CANNOT_BE_LONG); + + // Number is parsed as a float, but immediately promoted to a double + checkNumber("3.5f",3.5d,Double.class); + + checkNumber("1.2e3", 1.2e3d, Double.class); + checkNumber("1.2e+3", 1.2e3d, Double.class); + checkNumber("1.2e-3", 1.2e-3d, Double.class); + checkNumber("1.2e3", 1.2e3d, Double.class); + checkNumber("1.e+3", 1.e3d, Double.class); + checkNumber("1e+3", 1e3d, Double.class); + } + + private void checkNumber(String expression, Object value, Class type) { + try { + SpelExpressionParser parser = new SpelExpressionParser(); + SpelExpression expr = parser.parseRaw(expression); + Object o = expr.getValue(); + Assert.assertEquals(value,o); + Assert.assertEquals(type,o.getClass()); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } + + private void checkNumberError(String expression, SpelMessage expectedMessage) { + try { + SpelExpressionParser parser = new SpelExpressionParser(); + parser.parseRaw(expression); + Assert.fail(); + } catch (ParseException e) { + Assert.assertTrue(e instanceof SpelParseException); + SpelParseException spe = (SpelParseException)e; + Assert.assertEquals(expectedMessage,spe.getMessageCode()); + } + } +} diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/support/StandardComponentsTests.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/support/StandardComponentsTests.java index 89d8014210..47c49ba026 100644 --- a/org.springframework.expression/src/test/java/org/springframework/expression/spel/support/StandardComponentsTests.java +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/support/StandardComponentsTests.java @@ -1,79 +1,79 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.expression.spel.support; - -import java.util.List; - -import org.junit.Assert; -import org.junit.Test; -import org.springframework.core.convert.TypeDescriptor; -import org.springframework.expression.EvaluationException; -import org.springframework.expression.Operation; -import org.springframework.expression.OperatorOverloader; -import org.springframework.expression.TypeComparator; -import org.springframework.expression.TypeConverter; -import org.springframework.expression.TypeLocator; - -public class StandardComponentsTests { - - @Test - public void testStandardEvaluationContext() { - StandardEvaluationContext context = new StandardEvaluationContext(); - Assert.assertNotNull(context.getTypeComparator()); - - TypeComparator tc = new StandardTypeComparator(); - context.setTypeComparator(tc); - Assert.assertEquals(tc,context.getTypeComparator()); - - TypeLocator tl = new StandardTypeLocator(); - context.setTypeLocator(tl); - Assert.assertEquals(tl,context.getTypeLocator()); - } - - @Test - public void testStandardOperatorOverloader() throws EvaluationException { - OperatorOverloader oo = new StandardOperatorOverloader(); - Assert.assertFalse(oo.overridesOperation(Operation.ADD, null, null)); - try { - oo.operate(Operation.ADD, 2, 3); - Assert.fail("should have failed"); - } catch (EvaluationException e) { - // success - } - } - - @Test - public void testStandardTypeLocator() { - StandardTypeLocator tl = new StandardTypeLocator(); - List prefixes = tl.getImportPrefixes(); - Assert.assertEquals(1,prefixes.size()); - tl.registerImport("java.util"); - prefixes = tl.getImportPrefixes(); - Assert.assertEquals(2,prefixes.size()); - tl.removeImport("java.util"); - prefixes = tl.getImportPrefixes(); - Assert.assertEquals(1,prefixes.size()); - } - - @Test - public void testStandardTypeConverter() throws EvaluationException { - TypeConverter tc = new StandardTypeConverter(); - tc.convertValue(3, TypeDescriptor.forObject(3), TypeDescriptor.valueOf(Double.class)); - } - -} - +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.expression.spel.support; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.expression.EvaluationException; +import org.springframework.expression.Operation; +import org.springframework.expression.OperatorOverloader; +import org.springframework.expression.TypeComparator; +import org.springframework.expression.TypeConverter; +import org.springframework.expression.TypeLocator; + +public class StandardComponentsTests { + + @Test + public void testStandardEvaluationContext() { + StandardEvaluationContext context = new StandardEvaluationContext(); + Assert.assertNotNull(context.getTypeComparator()); + + TypeComparator tc = new StandardTypeComparator(); + context.setTypeComparator(tc); + Assert.assertEquals(tc,context.getTypeComparator()); + + TypeLocator tl = new StandardTypeLocator(); + context.setTypeLocator(tl); + Assert.assertEquals(tl,context.getTypeLocator()); + } + + @Test + public void testStandardOperatorOverloader() throws EvaluationException { + OperatorOverloader oo = new StandardOperatorOverloader(); + Assert.assertFalse(oo.overridesOperation(Operation.ADD, null, null)); + try { + oo.operate(Operation.ADD, 2, 3); + Assert.fail("should have failed"); + } catch (EvaluationException e) { + // success + } + } + + @Test + public void testStandardTypeLocator() { + StandardTypeLocator tl = new StandardTypeLocator(); + List prefixes = tl.getImportPrefixes(); + Assert.assertEquals(1,prefixes.size()); + tl.registerImport("java.util"); + prefixes = tl.getImportPrefixes(); + Assert.assertEquals(2,prefixes.size()); + tl.removeImport("java.util"); + prefixes = tl.getImportPrefixes(); + Assert.assertEquals(1,prefixes.size()); + } + + @Test + public void testStandardTypeConverter() throws EvaluationException { + TypeConverter tc = new StandardTypeConverter(); + tc.convertValue(3, TypeDescriptor.forObject(3), TypeDescriptor.valueOf(Double.class)); + } + +} + diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/testresources/TestAddress.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/testresources/TestAddress.java index 069a42958f..0f84c9e85e 100644 --- a/org.springframework.expression/src/test/java/org/springframework/expression/spel/testresources/TestAddress.java +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/testresources/TestAddress.java @@ -1,21 +1,21 @@ -package org.springframework.expression.spel.testresources; - -import java.util.List; - -public class TestAddress{ - private String street; - private List crossStreets; - - public String getStreet() { - return street; - } - public void setStreet(String street) { - this.street = street; - } - public List getCrossStreets() { - return crossStreets; - } - public void setCrossStreets(List crossStreets) { - this.crossStreets = crossStreets; - } - } +package org.springframework.expression.spel.testresources; + +import java.util.List; + +public class TestAddress{ + private String street; + private List crossStreets; + + public String getStreet() { + return street; + } + public void setStreet(String street) { + this.street = street; + } + public List getCrossStreets() { + return crossStreets; + } + public void setCrossStreets(List crossStreets) { + this.crossStreets = crossStreets; + } + } diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/testresources/TestPerson.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/testresources/TestPerson.java index 94acb31380..dca009da12 100644 --- a/org.springframework.expression/src/test/java/org/springframework/expression/spel/testresources/TestPerson.java +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/testresources/TestPerson.java @@ -1,19 +1,19 @@ -package org.springframework.expression.spel.testresources; - -public class TestPerson { - private String name; - private TestAddress address; - - public String getName() { - return name; - } - public void setName(String name) { - this.name = name; - } - public TestAddress getAddress() { - return address; - } - public void setAddress(TestAddress address) { - this.address = address; - } +package org.springframework.expression.spel.testresources; + +public class TestPerson { + private String name; + private TestAddress address; + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public TestAddress getAddress() { + return address; + } + public void setAddress(TestAddress address) { + this.address = address; + } } \ No newline at end of file diff --git a/org.springframework.integration-tests/src/test/java/test/util/SerializationTestUtils.java b/org.springframework.integration-tests/src/test/java/test/util/SerializationTestUtils.java index 609ae77e00..15ef78a864 100644 --- a/org.springframework.integration-tests/src/test/java/test/util/SerializationTestUtils.java +++ b/org.springframework.integration-tests/src/test/java/test/util/SerializationTestUtils.java @@ -1,100 +1,100 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package test.util; - -import java.awt.*; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.NotSerializableException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.OutputStream; -import java.io.Serializable; - -import static org.junit.Assert.*; -import org.junit.Test; -import test.beans.TestBean; - -/** - * Utilities for testing serializability of objects. - * Exposes static methods for use in other test cases. - * Contains {@link org.junit.Test} methods to test itself. - * - * @author Rod Johnson - * @author Chris Beams - */ -public final class SerializationTestUtils { - - public static void testSerialization(Object o) throws IOException { - OutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(o); - } - - public static boolean isSerializable(Object o) throws IOException { - try { - testSerialization(o); - return true; - } - catch (NotSerializableException ex) { - return false; - } - } - - public static Object serializeAndDeserialize(Object o) throws IOException, ClassNotFoundException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(o); - oos.flush(); - baos.flush(); - byte[] bytes = baos.toByteArray(); - - ByteArrayInputStream is = new ByteArrayInputStream(bytes); - ObjectInputStream ois = new ObjectInputStream(is); - Object o2 = ois.readObject(); - return o2; - } - - - @Test(expected=NotSerializableException.class) - public void testWithNonSerializableObject() throws IOException { - TestBean o = new TestBean(); - assertFalse(o instanceof Serializable); - assertFalse(isSerializable(o)); - - testSerialization(o); - } - - @Test - public void testWithSerializableObject() throws Exception { - int x = 5; - int y = 10; - Point p = new Point(x, y); - assertTrue(p instanceof Serializable); - - testSerialization(p); - - assertTrue(isSerializable(p)); - - Point p2 = (Point) serializeAndDeserialize(p); - assertNotSame(p, p2); - assertEquals(x, (int) p2.getX()); - assertEquals(y, (int) p2.getY()); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package test.util; + +import java.awt.*; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.NotSerializableException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.Serializable; + +import static org.junit.Assert.*; +import org.junit.Test; +import test.beans.TestBean; + +/** + * Utilities for testing serializability of objects. + * Exposes static methods for use in other test cases. + * Contains {@link org.junit.Test} methods to test itself. + * + * @author Rod Johnson + * @author Chris Beams + */ +public final class SerializationTestUtils { + + public static void testSerialization(Object o) throws IOException { + OutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(o); + } + + public static boolean isSerializable(Object o) throws IOException { + try { + testSerialization(o); + return true; + } + catch (NotSerializableException ex) { + return false; + } + } + + public static Object serializeAndDeserialize(Object o) throws IOException, ClassNotFoundException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(o); + oos.flush(); + baos.flush(); + byte[] bytes = baos.toByteArray(); + + ByteArrayInputStream is = new ByteArrayInputStream(bytes); + ObjectInputStream ois = new ObjectInputStream(is); + Object o2 = ois.readObject(); + return o2; + } + + + @Test(expected=NotSerializableException.class) + public void testWithNonSerializableObject() throws IOException { + TestBean o = new TestBean(); + assertFalse(o instanceof Serializable); + assertFalse(isSerializable(o)); + + testSerialization(o); + } + + @Test + public void testWithSerializableObject() throws Exception { + int x = 5; + int y = 10; + Point p = new Point(x, y); + assertTrue(p instanceof Serializable); + + testSerialization(p); + + assertTrue(isSerializable(p)); + + Point p2 = (Point) serializeAndDeserialize(p); + assertNotSame(p, p2); + assertEquals(x, (int) p2.getX()); + assertEquals(y, (int) p2.getY()); + } + +} diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/config/DatabasePopulatorConfigUtils.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/config/DatabasePopulatorConfigUtils.java index a707d78ff3..043ccf1ad8 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/config/DatabasePopulatorConfigUtils.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/config/DatabasePopulatorConfigUtils.java @@ -1,82 +1,82 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.config; - -import java.util.List; - -import org.springframework.beans.BeanMetadataElement; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.TypedStringValue; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.ManagedList; -import org.springframework.jdbc.datasource.init.CompositeDatabasePopulator; -import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; -import org.springframework.util.StringUtils; -import org.springframework.util.xml.DomUtils; -import org.w3c.dom.Element; - -/** - * @author Juergen Hoeller - * @since 3.1 - */ -class DatabasePopulatorConfigUtils { - - public static void setDatabasePopulator(Element element, BeanDefinitionBuilder builder) { - List scripts = DomUtils.getChildElementsByTagName(element, "script"); - if (scripts.size() > 0) { - builder.addPropertyValue("databasePopulator", createDatabasePopulator(element, scripts, "INIT")); - builder.addPropertyValue("databaseCleaner", createDatabasePopulator(element, scripts, "DESTROY")); - } - } - - static private BeanDefinition createDatabasePopulator(Element element, List scripts, String execution) { - BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CompositeDatabasePopulator.class); - - boolean ignoreFailedDrops = element.getAttribute("ignore-failures").equals("DROPS"); - boolean continueOnError = element.getAttribute("ignore-failures").equals("ALL"); - - ManagedList delegates = new ManagedList(); - for (Element scriptElement : scripts) { - String executionAttr = scriptElement.getAttribute("execution"); - if (!StringUtils.hasText(executionAttr)) { - executionAttr = "INIT"; - } - if (!execution.equals(executionAttr)) { - continue; - } - BeanDefinitionBuilder delegate = BeanDefinitionBuilder.genericBeanDefinition(ResourceDatabasePopulator.class); - delegate.addPropertyValue("ignoreFailedDrops", ignoreFailedDrops); - delegate.addPropertyValue("continueOnError", continueOnError); - - // Use a factory bean for the resources so they can be given an order if a pattern is used - BeanDefinitionBuilder resourcesFactory = BeanDefinitionBuilder.genericBeanDefinition(SortedResourcesFactoryBean.class); - resourcesFactory.addConstructorArgValue(new TypedStringValue(scriptElement.getAttribute("location"))); - delegate.addPropertyValue("scripts", resourcesFactory.getBeanDefinition()); - if (StringUtils.hasLength(scriptElement.getAttribute("encoding"))) { - delegate.addPropertyValue("sqlScriptEncoding", new TypedStringValue(scriptElement.getAttribute("encoding"))); - } - if (StringUtils.hasLength(scriptElement.getAttribute("separator"))) { - delegate.addPropertyValue("separator", new TypedStringValue(scriptElement.getAttribute("separator"))); - } - delegates.add(delegate.getBeanDefinition()); - } - builder.addPropertyValue("populators", delegates); - - return builder.getBeanDefinition(); - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.config; + +import java.util.List; + +import org.springframework.beans.BeanMetadataElement; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.TypedStringValue; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.jdbc.datasource.init.CompositeDatabasePopulator; +import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; +import org.springframework.util.StringUtils; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Element; + +/** + * @author Juergen Hoeller + * @since 3.1 + */ +class DatabasePopulatorConfigUtils { + + public static void setDatabasePopulator(Element element, BeanDefinitionBuilder builder) { + List scripts = DomUtils.getChildElementsByTagName(element, "script"); + if (scripts.size() > 0) { + builder.addPropertyValue("databasePopulator", createDatabasePopulator(element, scripts, "INIT")); + builder.addPropertyValue("databaseCleaner", createDatabasePopulator(element, scripts, "DESTROY")); + } + } + + static private BeanDefinition createDatabasePopulator(Element element, List scripts, String execution) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CompositeDatabasePopulator.class); + + boolean ignoreFailedDrops = element.getAttribute("ignore-failures").equals("DROPS"); + boolean continueOnError = element.getAttribute("ignore-failures").equals("ALL"); + + ManagedList delegates = new ManagedList(); + for (Element scriptElement : scripts) { + String executionAttr = scriptElement.getAttribute("execution"); + if (!StringUtils.hasText(executionAttr)) { + executionAttr = "INIT"; + } + if (!execution.equals(executionAttr)) { + continue; + } + BeanDefinitionBuilder delegate = BeanDefinitionBuilder.genericBeanDefinition(ResourceDatabasePopulator.class); + delegate.addPropertyValue("ignoreFailedDrops", ignoreFailedDrops); + delegate.addPropertyValue("continueOnError", continueOnError); + + // Use a factory bean for the resources so they can be given an order if a pattern is used + BeanDefinitionBuilder resourcesFactory = BeanDefinitionBuilder.genericBeanDefinition(SortedResourcesFactoryBean.class); + resourcesFactory.addConstructorArgValue(new TypedStringValue(scriptElement.getAttribute("location"))); + delegate.addPropertyValue("scripts", resourcesFactory.getBeanDefinition()); + if (StringUtils.hasLength(scriptElement.getAttribute("encoding"))) { + delegate.addPropertyValue("sqlScriptEncoding", new TypedStringValue(scriptElement.getAttribute("encoding"))); + } + if (StringUtils.hasLength(scriptElement.getAttribute("separator"))) { + delegate.addPropertyValue("separator", new TypedStringValue(scriptElement.getAttribute("separator"))); + } + delegates.add(delegate.getBeanDefinition()); + } + builder.addPropertyValue("populators", delegates); + + return builder.getBeanDefinition(); + } + +} diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/config/InitializeDatabaseBeanDefinitionParser.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/config/InitializeDatabaseBeanDefinitionParser.java index 5ea642fa6c..8f7c7fd82b 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/config/InitializeDatabaseBeanDefinitionParser.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/config/InitializeDatabaseBeanDefinitionParser.java @@ -1,55 +1,55 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.config; - -import org.w3c.dom.Element; - -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.support.AbstractBeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.jdbc.datasource.init.DataSourceInitializer; -import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; - -/** - * {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses an {@code initialize-database} - * element and creates a {@link BeanDefinition} of type {@link DataSourceInitializer}. Picks up nested - * {@code script} elements and configures a {@link ResourceDatabasePopulator} for them. - * - * @author Dave Syer - * @author Juergen Hoeller - * @since 3.0 - */ -class InitializeDatabaseBeanDefinitionParser extends AbstractBeanDefinitionParser { - - @Override - protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { - BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(DataSourceInitializer.class); - builder.addPropertyReference("dataSource", element.getAttribute("data-source")); - builder.addPropertyValue("enabled", element.getAttribute("enabled")); - DatabasePopulatorConfigUtils.setDatabasePopulator(element, builder); - builder.getRawBeanDefinition().setSource(parserContext.extractSource(element)); - return builder.getBeanDefinition(); - } - - @Override - protected boolean shouldGenerateId() { - return true; - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.config; + +import org.w3c.dom.Element; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.jdbc.datasource.init.DataSourceInitializer; +import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; + +/** + * {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses an {@code initialize-database} + * element and creates a {@link BeanDefinition} of type {@link DataSourceInitializer}. Picks up nested + * {@code script} elements and configures a {@link ResourceDatabasePopulator} for them. + * + * @author Dave Syer + * @author Juergen Hoeller + * @since 3.0 + */ +class InitializeDatabaseBeanDefinitionParser extends AbstractBeanDefinitionParser { + + @Override + protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(DataSourceInitializer.class); + builder.addPropertyReference("dataSource", element.getAttribute("data-source")); + builder.addPropertyValue("enabled", element.getAttribute("enabled")); + DatabasePopulatorConfigUtils.setDatabasePopulator(element, builder); + builder.getRawBeanDefinition().setSource(parserContext.extractSource(element)); + return builder.getBeanDefinition(); + } + + @Override + protected boolean shouldGenerateId() { + return true; + } + +} diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/OutputStreamFactory.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/OutputStreamFactory.java index 811f389b31..848501e7e4 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/OutputStreamFactory.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/embedded/OutputStreamFactory.java @@ -1,42 +1,42 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.jdbc.datasource.embedded; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Internal helper for exposing dummy OutputStreams to embedded databases - * such as Derby, preventing the creation of a log file. - * - * @author Juergen Hoeller - * @since 3.0 - */ -public class OutputStreamFactory { - - /** - * Returns an {@link java.io.OutputStream} that ignores all data given to it. - */ - public static OutputStream getNoopOutputStream() { - return new OutputStream() { - public void write(int b) throws IOException { - // ignore the output - } - }; - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.datasource.embedded; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Internal helper for exposing dummy OutputStreams to embedded databases + * such as Derby, preventing the creation of a log file. + * + * @author Juergen Hoeller + * @since 3.0 + */ +public class OutputStreamFactory { + + /** + * Returns an {@link java.io.OutputStream} that ignores all data given to it. + */ + public static OutputStream getNoopOutputStream() { + return new OutputStream() { + public void write(int b) throws IOException { + // ignore the output + } + }; + } + +} diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/DatabasePopulatorUtils.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/DatabasePopulatorUtils.java index f90d94b418..0cf2318285 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/DatabasePopulatorUtils.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/datasource/init/DatabasePopulatorUtils.java @@ -1,61 +1,61 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.datasource.init; - -import java.sql.Connection; -import java.sql.SQLException; -import javax.sql.DataSource; - -import org.springframework.dao.DataAccessResourceFailureException; -import org.springframework.util.Assert; - -/** - * Utility methods for executing a DatabasePopulator. - * - * @author Juergen Hoeller - * @since 3.1 - */ -public abstract class DatabasePopulatorUtils { - - /** - * Execute the given DatabasePopulator against the given DataSource. - * @param populator the DatabasePopulator to execute - * @param dataSource the DataSource to execute against - */ - public static void execute(DatabasePopulator populator, DataSource dataSource) { - Assert.notNull(populator, "DatabasePopulator must be provided"); - Assert.notNull(dataSource, "DataSource must be provided"); - try { - Connection connection = dataSource.getConnection(); - try { - populator.populate(connection); - } - finally { - try { - connection.close(); - } - catch (SQLException ex) { - // ignore - } - } - } - catch (Exception ex) { - throw new DataAccessResourceFailureException("Failed to execute database script", ex); - } - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.datasource.init; + +import java.sql.Connection; +import java.sql.SQLException; +import javax.sql.DataSource; + +import org.springframework.dao.DataAccessResourceFailureException; +import org.springframework.util.Assert; + +/** + * Utility methods for executing a DatabasePopulator. + * + * @author Juergen Hoeller + * @since 3.1 + */ +public abstract class DatabasePopulatorUtils { + + /** + * Execute the given DatabasePopulator against the given DataSource. + * @param populator the DatabasePopulator to execute + * @param dataSource the DataSource to execute against + */ + public static void execute(DatabasePopulator populator, DataSource dataSource) { + Assert.notNull(populator, "DatabasePopulator must be provided"); + Assert.notNull(dataSource, "DataSource must be provided"); + try { + Connection connection = dataSource.getConnection(); + try { + populator.populate(connection); + } + finally { + try { + connection.close(); + } + catch (SQLException ex) { + // ignore + } + } + } + catch (Exception ex) { + throw new DataAccessResourceFailureException("Failed to execute database script", ex); + } + } + +} diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/nativejdbc/OracleJdbc4NativeJdbcExtractor.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/nativejdbc/OracleJdbc4NativeJdbcExtractor.java index 123e73c8dd..b54df13642 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/nativejdbc/OracleJdbc4NativeJdbcExtractor.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/nativejdbc/OracleJdbc4NativeJdbcExtractor.java @@ -1,60 +1,60 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.jdbc.support.nativejdbc; - -import java.sql.CallableStatement; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.Statement; - -/** - * A {@link Jdbc4NativeJdbcExtractor} which comes pre-configured for Oracle's JDBC driver, - * specifying the following vendor-specific API types for unwrapping: - *
    - *
  • oracle.jdbc.OracleConnection - *
  • oracle.jdbc.OracleStatement - *
  • oracle.jdbc.OraclePreparedStatement - *
  • oracle.jdbc.OracleCallableStatement - *
  • oracle.jdbc.OracleResultSet - *
- * - *

Note: This will work with any JDBC 4.0 compliant connection pool, without a need for - * connection pool specific setup. In other words, as of JDBC 4.0, NativeJdbcExtractors - * will typically be implemented for specific drivers instead of for specific pools. - * - * @author Juergen Hoeller - * @since 3.0.5 - */ -public class OracleJdbc4NativeJdbcExtractor extends Jdbc4NativeJdbcExtractor { - - @SuppressWarnings("unchecked") - public OracleJdbc4NativeJdbcExtractor() { - try { - setConnectionType((Class) getClass().getClassLoader().loadClass("oracle.jdbc.OracleConnection")); - setStatementType((Class) getClass().getClassLoader().loadClass("oracle.jdbc.OracleStatement")); - setPreparedStatementType((Class) getClass().getClassLoader().loadClass("oracle.jdbc.OraclePreparedStatement")); - setCallableStatementType((Class) getClass().getClassLoader().loadClass("oracle.jdbc.OracleCallableStatement")); - setResultSetType((Class) getClass().getClassLoader().loadClass("oracle.jdbc.OracleResultSet")); - } - catch (Exception ex) { - throw new IllegalStateException( - "Could not initialize OracleJdbc4NativeJdbcExtractor because Oracle API classes are not available: " + ex); - } - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.support.nativejdbc; + +import java.sql.CallableStatement; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.Statement; + +/** + * A {@link Jdbc4NativeJdbcExtractor} which comes pre-configured for Oracle's JDBC driver, + * specifying the following vendor-specific API types for unwrapping: + *

    + *
  • oracle.jdbc.OracleConnection + *
  • oracle.jdbc.OracleStatement + *
  • oracle.jdbc.OraclePreparedStatement + *
  • oracle.jdbc.OracleCallableStatement + *
  • oracle.jdbc.OracleResultSet + *
+ * + *

Note: This will work with any JDBC 4.0 compliant connection pool, without a need for + * connection pool specific setup. In other words, as of JDBC 4.0, NativeJdbcExtractors + * will typically be implemented for specific drivers instead of for specific pools. + * + * @author Juergen Hoeller + * @since 3.0.5 + */ +public class OracleJdbc4NativeJdbcExtractor extends Jdbc4NativeJdbcExtractor { + + @SuppressWarnings("unchecked") + public OracleJdbc4NativeJdbcExtractor() { + try { + setConnectionType((Class) getClass().getClassLoader().loadClass("oracle.jdbc.OracleConnection")); + setStatementType((Class) getClass().getClassLoader().loadClass("oracle.jdbc.OracleStatement")); + setPreparedStatementType((Class) getClass().getClassLoader().loadClass("oracle.jdbc.OraclePreparedStatement")); + setCallableStatementType((Class) getClass().getClassLoader().loadClass("oracle.jdbc.OracleCallableStatement")); + setResultSetType((Class) getClass().getClassLoader().loadClass("oracle.jdbc.OracleResultSet")); + } + catch (Exception ex) { + throw new IllegalStateException( + "Could not initialize OracleJdbc4NativeJdbcExtractor because Oracle API classes are not available: " + ex); + } + } + +} diff --git a/org.springframework.jms/src/main/java/org/springframework/jms/support/converter/MessageType.java b/org.springframework.jms/src/main/java/org/springframework/jms/support/converter/MessageType.java index cf62d34f48..8c633d61bb 100644 --- a/org.springframework.jms/src/main/java/org/springframework/jms/support/converter/MessageType.java +++ b/org.springframework.jms/src/main/java/org/springframework/jms/support/converter/MessageType.java @@ -1,32 +1,32 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.jms.support.converter; - -/** - * Constants that indicate a target message type to convert to: a - * {@link javax.jms.TextMessage}, a {@link javax.jms.BytesMessage}, - * a {@link javax.jms.MapMessage} or an {@link ObjectMessage}. - * - * @author Juergen Hoeller - * @since 3.0 - * @see MarshallingMessageConverter#setTargetType - */ -public enum MessageType { - - TEXT, BYTES, MAP, OBJECT - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jms.support.converter; + +/** + * Constants that indicate a target message type to convert to: a + * {@link javax.jms.TextMessage}, a {@link javax.jms.BytesMessage}, + * a {@link javax.jms.MapMessage} or an {@link ObjectMessage}. + * + * @author Juergen Hoeller + * @since 3.0 + * @see MarshallingMessageConverter#setTargetType + */ +public enum MessageType { + + TEXT, BYTES, MAP, OBJECT + +} diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalRegionFactoryProxy.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalRegionFactoryProxy.java index d43196ce3f..e066594157 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalRegionFactoryProxy.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/LocalRegionFactoryProxy.java @@ -1,123 +1,123 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.orm.hibernate3; - -import java.lang.reflect.Method; -import java.util.Properties; - -import org.hibernate.cache.CacheDataDescription; -import org.hibernate.cache.CacheException; -import org.hibernate.cache.CollectionRegion; -import org.hibernate.cache.EntityRegion; -import org.hibernate.cache.QueryResultsRegion; -import org.hibernate.cache.RegionFactory; -import org.hibernate.cache.TimestampsRegion; -import org.hibernate.cache.access.AccessType; -import org.hibernate.cfg.Settings; - -import org.springframework.util.ReflectionUtils; - -/** - * Proxy for a Hibernate RegionFactory, delegating to a Spring-managed - * RegionFactory instance, determined by LocalSessionFactoryBean's - * "cacheRegionFactory" property. - * - *

Compatible with Hibernate 3.3 as well as Hibernate 3.5's version - * of the RegionFactory SPI. - * - * @author Juergen Hoeller - * @since 3.0 - * @see LocalSessionFactoryBean#setCacheRegionFactory - */ -public class LocalRegionFactoryProxy implements RegionFactory { - - private final RegionFactory regionFactory; - - - /** - * Standard constructor. - */ - public LocalRegionFactoryProxy() { - RegionFactory rf = (RegionFactory) LocalSessionFactoryBean.getConfigTimeRegionFactory(); - // absolutely needs thread-bound RegionFactory to initialize - if (rf == null) { - throw new IllegalStateException("No Hibernate RegionFactory found - " + - "'cacheRegionFactory' property must be set on LocalSessionFactoryBean"); - } - this.regionFactory = rf; - } - - /** - * Properties constructor: not used by this class or formally required, - * but enforced by Hibernate when reflectively instantiating a RegionFactory. - */ - public LocalRegionFactoryProxy(Properties properties) { - this(); - } - - - public void start(Settings settings, Properties properties) throws CacheException { - this.regionFactory.start(settings, properties); - } - - public void stop() { - this.regionFactory.stop(); - } - - public boolean isMinimalPutsEnabledByDefault() { - return this.regionFactory.isMinimalPutsEnabledByDefault(); - } - - public AccessType getDefaultAccessType() { - try { - Method method = RegionFactory.class.getMethod("getDefaultAccessType"); - return (AccessType) ReflectionUtils.invokeMethod(method, this.regionFactory); - } - catch (NoSuchMethodException ex) { - throw new IllegalStateException("getDefaultAccessType requires Hibernate 3.5+"); - } - } - - public long nextTimestamp() { - return this.regionFactory.nextTimestamp(); - } - - public EntityRegion buildEntityRegion(String regionName, Properties properties, CacheDataDescription metadata) - throws CacheException { - - return this.regionFactory.buildEntityRegion(regionName, properties, metadata); - } - - public CollectionRegion buildCollectionRegion(String regionName, Properties properties, - CacheDataDescription metadata) throws CacheException { - - return this.regionFactory.buildCollectionRegion(regionName, properties, metadata); - } - - public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) - throws CacheException { - - return this.regionFactory.buildQueryResultsRegion(regionName, properties); - } - - public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties) - throws CacheException { - - return this.regionFactory.buildTimestampsRegion(regionName, properties); - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.hibernate3; + +import java.lang.reflect.Method; +import java.util.Properties; + +import org.hibernate.cache.CacheDataDescription; +import org.hibernate.cache.CacheException; +import org.hibernate.cache.CollectionRegion; +import org.hibernate.cache.EntityRegion; +import org.hibernate.cache.QueryResultsRegion; +import org.hibernate.cache.RegionFactory; +import org.hibernate.cache.TimestampsRegion; +import org.hibernate.cache.access.AccessType; +import org.hibernate.cfg.Settings; + +import org.springframework.util.ReflectionUtils; + +/** + * Proxy for a Hibernate RegionFactory, delegating to a Spring-managed + * RegionFactory instance, determined by LocalSessionFactoryBean's + * "cacheRegionFactory" property. + * + *

Compatible with Hibernate 3.3 as well as Hibernate 3.5's version + * of the RegionFactory SPI. + * + * @author Juergen Hoeller + * @since 3.0 + * @see LocalSessionFactoryBean#setCacheRegionFactory + */ +public class LocalRegionFactoryProxy implements RegionFactory { + + private final RegionFactory regionFactory; + + + /** + * Standard constructor. + */ + public LocalRegionFactoryProxy() { + RegionFactory rf = (RegionFactory) LocalSessionFactoryBean.getConfigTimeRegionFactory(); + // absolutely needs thread-bound RegionFactory to initialize + if (rf == null) { + throw new IllegalStateException("No Hibernate RegionFactory found - " + + "'cacheRegionFactory' property must be set on LocalSessionFactoryBean"); + } + this.regionFactory = rf; + } + + /** + * Properties constructor: not used by this class or formally required, + * but enforced by Hibernate when reflectively instantiating a RegionFactory. + */ + public LocalRegionFactoryProxy(Properties properties) { + this(); + } + + + public void start(Settings settings, Properties properties) throws CacheException { + this.regionFactory.start(settings, properties); + } + + public void stop() { + this.regionFactory.stop(); + } + + public boolean isMinimalPutsEnabledByDefault() { + return this.regionFactory.isMinimalPutsEnabledByDefault(); + } + + public AccessType getDefaultAccessType() { + try { + Method method = RegionFactory.class.getMethod("getDefaultAccessType"); + return (AccessType) ReflectionUtils.invokeMethod(method, this.regionFactory); + } + catch (NoSuchMethodException ex) { + throw new IllegalStateException("getDefaultAccessType requires Hibernate 3.5+"); + } + } + + public long nextTimestamp() { + return this.regionFactory.nextTimestamp(); + } + + public EntityRegion buildEntityRegion(String regionName, Properties properties, CacheDataDescription metadata) + throws CacheException { + + return this.regionFactory.buildEntityRegion(regionName, properties, metadata); + } + + public CollectionRegion buildCollectionRegion(String regionName, Properties properties, + CacheDataDescription metadata) throws CacheException { + + return this.regionFactory.buildCollectionRegion(regionName, properties, metadata); + } + + public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) + throws CacheException { + + return this.regionFactory.buildQueryResultsRegion(regionName, properties); + } + + public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties) + throws CacheException { + + return this.regionFactory.buildTimestampsRegion(regionName, properties); + } + +} diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate4/LocalSessionFactoryBean.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate4/LocalSessionFactoryBean.java index ca1265ce92..986e5e942f 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate4/LocalSessionFactoryBean.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate4/LocalSessionFactoryBean.java @@ -1,335 +1,335 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.hibernate4; - -import java.io.File; -import java.io.IOException; -import java.util.Properties; -import javax.sql.DataSource; - -import org.hibernate.SessionFactory; -import org.hibernate.cfg.NamingStrategy; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.ResourceLoaderAware; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.core.io.support.ResourcePatternResolver; -import org.springframework.core.io.support.ResourcePatternUtils; - -/** - * {@link org.springframework.beans.factory.FactoryBean} that creates a - * Hibernate {@link org.hibernate.SessionFactory}. This is the usual way to - * set up a shared Hibernate SessionFactory in a Spring application context; - * the SessionFactory can then be passed to Hibernate-based DAOs via - * dependency injection. - * - *

NOTE: This variant of LocalSessionFactoryBean requires Hibernate 4.0 - * or higher. It is similar in role to the same-named class in the orm.hibernate3 - * package. However, in practice, it is closer to AnnotationSessionFactoryBean - * since its core purpose is to bootstrap a SessionFactory from annotation scanning. - * - * @author Juergen Hoeller - * @since 3.1 - * @see #setDataSource - * @see #setPackagesToScan - */ -public class LocalSessionFactoryBean implements FactoryBean, ResourceLoaderAware, - InitializingBean, DisposableBean { - - private DataSource dataSource; - - private Resource[] configLocations; - - private String[] mappingResources; - - private Resource[] mappingLocations; - - private Resource[] cacheableMappingLocations; - - private Resource[] mappingJarLocations; - - private Resource[] mappingDirectoryLocations; - - private NamingStrategy namingStrategy; - - private Properties hibernateProperties; - - private Class[] annotatedClasses; - - private String[] annotatedPackages; - - private String[] packagesToScan; - - private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); - - private SessionFactory sessionFactory; - - - /** - * Set the DataSource to be used by the SessionFactory. - * If set, this will override corresponding settings in Hibernate properties. - *

If this is set, the Hibernate settings should not define - * a connection provider to avoid meaningless double configuration. - */ - public void setDataSource(DataSource dataSource) { - this.dataSource = dataSource; - } - - /** - * Set the location of a single Hibernate XML config file, for example as - * classpath resource "classpath:hibernate.cfg.xml". - *

Note: Can be omitted when all necessary properties and mapping - * resources are specified locally via this bean. - * @see org.hibernate.cfg.Configuration#configure(java.net.URL) - */ - public void setConfigLocation(Resource configLocation) { - this.configLocations = new Resource[] {configLocation}; - } - - /** - * Set the locations of multiple Hibernate XML config files, for example as - * classpath resources "classpath:hibernate.cfg.xml,classpath:extension.cfg.xml". - *

Note: Can be omitted when all necessary properties and mapping - * resources are specified locally via this bean. - * @see org.hibernate.cfg.Configuration#configure(java.net.URL) - */ - public void setConfigLocations(Resource[] configLocations) { - this.configLocations = configLocations; - } - - /** - * Set Hibernate mapping resources to be found in the class path, - * like "example.hbm.xml" or "mypackage/example.hbm.xml". - * Analogous to mapping entries in a Hibernate XML config file. - * Alternative to the more generic setMappingLocations method. - *

Can be used to add to mappings from a Hibernate XML config file, - * or to specify all mappings locally. - * @see #setMappingLocations - * @see org.hibernate.cfg.Configuration#addResource - */ - public void setMappingResources(String[] mappingResources) { - this.mappingResources = mappingResources; - } - - /** - * Set locations of Hibernate mapping files, for example as classpath - * resource "classpath:example.hbm.xml". Supports any resource location - * via Spring's resource abstraction, for example relative paths like - * "WEB-INF/mappings/example.hbm.xml" when running in an application context. - *

Can be used to add to mappings from a Hibernate XML config file, - * or to specify all mappings locally. - * @see org.hibernate.cfg.Configuration#addInputStream - */ - public void setMappingLocations(Resource[] mappingLocations) { - this.mappingLocations = mappingLocations; - } - - /** - * Set locations of cacheable Hibernate mapping files, for example as web app - * resource "/WEB-INF/mapping/example.hbm.xml". Supports any resource location - * via Spring's resource abstraction, as long as the resource can be resolved - * in the file system. - *

Can be used to add to mappings from a Hibernate XML config file, - * or to specify all mappings locally. - * @see org.hibernate.cfg.Configuration#addCacheableFile(java.io.File) - */ - public void setCacheableMappingLocations(Resource[] cacheableMappingLocations) { - this.cacheableMappingLocations = cacheableMappingLocations; - } - - /** - * Set locations of jar files that contain Hibernate mapping resources, - * like "WEB-INF/lib/example.hbm.jar". - *

Can be used to add to mappings from a Hibernate XML config file, - * or to specify all mappings locally. - * @see org.hibernate.cfg.Configuration#addJar(java.io.File) - */ - public void setMappingJarLocations(Resource[] mappingJarLocations) { - this.mappingJarLocations = mappingJarLocations; - } - - /** - * Set locations of directories that contain Hibernate mapping resources, - * like "WEB-INF/mappings". - *

Can be used to add to mappings from a Hibernate XML config file, - * or to specify all mappings locally. - * @see org.hibernate.cfg.Configuration#addDirectory(java.io.File) - */ - public void setMappingDirectoryLocations(Resource[] mappingDirectoryLocations) { - this.mappingDirectoryLocations = mappingDirectoryLocations; - } - - /** - * Set a Hibernate NamingStrategy for the SessionFactory, determining the - * physical column and table names given the info in the mapping document. - * @see org.hibernate.cfg.Configuration#setNamingStrategy - */ - public void setNamingStrategy(NamingStrategy namingStrategy) { - this.namingStrategy = namingStrategy; - } - - /** - * Set Hibernate properties, such as "hibernate.dialect". - *

Note: Do not specify a transaction provider here when using - * Spring-driven transactions. It is also advisable to omit connection - * provider settings and use a Spring-set DataSource instead. - * @see #setDataSource - */ - public void setHibernateProperties(Properties hibernateProperties) { - this.hibernateProperties = hibernateProperties; - } - - /** - * Return the Hibernate properties, if any. Mainly available for - * configuration through property paths that specify individual keys. - */ - public Properties getHibernateProperties() { - if (this.hibernateProperties == null) { - this.hibernateProperties = new Properties(); - } - return this.hibernateProperties; - } - - /** - * Specify annotated entity classes to register with this Hibernate SessionFactory. - * @see org.hibernate.cfg.Configuration#addAnnotatedClass(String) - */ - public void setAnnotatedClasses(Class[] annotatedClasses) { - this.annotatedClasses = annotatedClasses; - } - - /** - * Specify the names of annotated packages, for which package-level - * annotation metadata will be read. - * @see org.hibernate.cfg.Configuration#addPackage(String) - */ - public void setAnnotatedPackages(String[] annotatedPackages) { - this.annotatedPackages = annotatedPackages; - } - - /** - * Specify packages to search for autodetection of your entity classes in the - * classpath. This is analogous to Spring's component-scan feature - * ({@link org.springframework.context.annotation.ClassPathBeanDefinitionScanner}). - */ - public void setPackagesToScan(String... packagesToScan) { - this.packagesToScan = packagesToScan; - } - - public void setResourceLoader(ResourceLoader resourceLoader) { - this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader); - } - - - public void afterPropertiesSet() throws IOException { - LocalSessionFactoryBuilder sfb = new LocalSessionFactoryBuilder(this.dataSource, this.resourcePatternResolver); - - if (this.configLocations != null) { - for (Resource resource : this.configLocations) { - // Load Hibernate configuration from given location. - sfb.configure(resource.getURL()); - } - } - - if (this.mappingResources != null) { - // Register given Hibernate mapping definitions, contained in resource files. - for (String mapping : this.mappingResources) { - Resource mr = new ClassPathResource(mapping.trim(), this.resourcePatternResolver.getClassLoader()); - sfb.addInputStream(mr.getInputStream()); - } - } - - if (this.mappingLocations != null) { - // Register given Hibernate mapping definitions, contained in resource files. - for (Resource resource : this.mappingLocations) { - sfb.addInputStream(resource.getInputStream()); - } - } - - if (this.cacheableMappingLocations != null) { - // Register given cacheable Hibernate mapping definitions, read from the file system. - for (Resource resource : this.cacheableMappingLocations) { - sfb.addCacheableFile(resource.getFile()); - } - } - - if (this.mappingJarLocations != null) { - // Register given Hibernate mapping definitions, contained in jar files. - for (Resource resource : this.mappingJarLocations) { - sfb.addJar(resource.getFile()); - } - } - - if (this.mappingDirectoryLocations != null) { - // Register all Hibernate mapping definitions in the given directories. - for (Resource resource : this.mappingDirectoryLocations) { - File file = resource.getFile(); - if (!file.isDirectory()) { - throw new IllegalArgumentException( - "Mapping directory location [" + resource + "] does not denote a directory"); - } - sfb.addDirectory(file); - } - } - - if (this.namingStrategy != null) { - sfb.setNamingStrategy(this.namingStrategy); - } - - if (this.hibernateProperties != null) { - sfb.addProperties(this.hibernateProperties); - } - - if (this.annotatedClasses != null) { - sfb.addAnnotatedClasses(this.annotatedClasses); - } - - if (this.annotatedPackages != null) { - sfb.addPackages(this.annotatedPackages); - } - - if (this.packagesToScan != null) { - sfb.scanPackages(this.packagesToScan); - } - - this.sessionFactory = sfb.buildSessionFactory(); - } - - - public SessionFactory getObject() { - return this.sessionFactory; - } - - public Class getObjectType() { - return (this.sessionFactory != null ? this.sessionFactory.getClass() : SessionFactory.class); - } - - public boolean isSingleton() { - return true; - } - - - public void destroy() { - this.sessionFactory.close(); - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.hibernate4; + +import java.io.File; +import java.io.IOException; +import java.util.Properties; +import javax.sql.DataSource; + +import org.hibernate.SessionFactory; +import org.hibernate.cfg.NamingStrategy; + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ResourceLoaderAware; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternUtils; + +/** + * {@link org.springframework.beans.factory.FactoryBean} that creates a + * Hibernate {@link org.hibernate.SessionFactory}. This is the usual way to + * set up a shared Hibernate SessionFactory in a Spring application context; + * the SessionFactory can then be passed to Hibernate-based DAOs via + * dependency injection. + * + *

NOTE: This variant of LocalSessionFactoryBean requires Hibernate 4.0 + * or higher. It is similar in role to the same-named class in the orm.hibernate3 + * package. However, in practice, it is closer to AnnotationSessionFactoryBean + * since its core purpose is to bootstrap a SessionFactory from annotation scanning. + * + * @author Juergen Hoeller + * @since 3.1 + * @see #setDataSource + * @see #setPackagesToScan + */ +public class LocalSessionFactoryBean implements FactoryBean, ResourceLoaderAware, + InitializingBean, DisposableBean { + + private DataSource dataSource; + + private Resource[] configLocations; + + private String[] mappingResources; + + private Resource[] mappingLocations; + + private Resource[] cacheableMappingLocations; + + private Resource[] mappingJarLocations; + + private Resource[] mappingDirectoryLocations; + + private NamingStrategy namingStrategy; + + private Properties hibernateProperties; + + private Class[] annotatedClasses; + + private String[] annotatedPackages; + + private String[] packagesToScan; + + private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); + + private SessionFactory sessionFactory; + + + /** + * Set the DataSource to be used by the SessionFactory. + * If set, this will override corresponding settings in Hibernate properties. + *

If this is set, the Hibernate settings should not define + * a connection provider to avoid meaningless double configuration. + */ + public void setDataSource(DataSource dataSource) { + this.dataSource = dataSource; + } + + /** + * Set the location of a single Hibernate XML config file, for example as + * classpath resource "classpath:hibernate.cfg.xml". + *

Note: Can be omitted when all necessary properties and mapping + * resources are specified locally via this bean. + * @see org.hibernate.cfg.Configuration#configure(java.net.URL) + */ + public void setConfigLocation(Resource configLocation) { + this.configLocations = new Resource[] {configLocation}; + } + + /** + * Set the locations of multiple Hibernate XML config files, for example as + * classpath resources "classpath:hibernate.cfg.xml,classpath:extension.cfg.xml". + *

Note: Can be omitted when all necessary properties and mapping + * resources are specified locally via this bean. + * @see org.hibernate.cfg.Configuration#configure(java.net.URL) + */ + public void setConfigLocations(Resource[] configLocations) { + this.configLocations = configLocations; + } + + /** + * Set Hibernate mapping resources to be found in the class path, + * like "example.hbm.xml" or "mypackage/example.hbm.xml". + * Analogous to mapping entries in a Hibernate XML config file. + * Alternative to the more generic setMappingLocations method. + *

Can be used to add to mappings from a Hibernate XML config file, + * or to specify all mappings locally. + * @see #setMappingLocations + * @see org.hibernate.cfg.Configuration#addResource + */ + public void setMappingResources(String[] mappingResources) { + this.mappingResources = mappingResources; + } + + /** + * Set locations of Hibernate mapping files, for example as classpath + * resource "classpath:example.hbm.xml". Supports any resource location + * via Spring's resource abstraction, for example relative paths like + * "WEB-INF/mappings/example.hbm.xml" when running in an application context. + *

Can be used to add to mappings from a Hibernate XML config file, + * or to specify all mappings locally. + * @see org.hibernate.cfg.Configuration#addInputStream + */ + public void setMappingLocations(Resource[] mappingLocations) { + this.mappingLocations = mappingLocations; + } + + /** + * Set locations of cacheable Hibernate mapping files, for example as web app + * resource "/WEB-INF/mapping/example.hbm.xml". Supports any resource location + * via Spring's resource abstraction, as long as the resource can be resolved + * in the file system. + *

Can be used to add to mappings from a Hibernate XML config file, + * or to specify all mappings locally. + * @see org.hibernate.cfg.Configuration#addCacheableFile(java.io.File) + */ + public void setCacheableMappingLocations(Resource[] cacheableMappingLocations) { + this.cacheableMappingLocations = cacheableMappingLocations; + } + + /** + * Set locations of jar files that contain Hibernate mapping resources, + * like "WEB-INF/lib/example.hbm.jar". + *

Can be used to add to mappings from a Hibernate XML config file, + * or to specify all mappings locally. + * @see org.hibernate.cfg.Configuration#addJar(java.io.File) + */ + public void setMappingJarLocations(Resource[] mappingJarLocations) { + this.mappingJarLocations = mappingJarLocations; + } + + /** + * Set locations of directories that contain Hibernate mapping resources, + * like "WEB-INF/mappings". + *

Can be used to add to mappings from a Hibernate XML config file, + * or to specify all mappings locally. + * @see org.hibernate.cfg.Configuration#addDirectory(java.io.File) + */ + public void setMappingDirectoryLocations(Resource[] mappingDirectoryLocations) { + this.mappingDirectoryLocations = mappingDirectoryLocations; + } + + /** + * Set a Hibernate NamingStrategy for the SessionFactory, determining the + * physical column and table names given the info in the mapping document. + * @see org.hibernate.cfg.Configuration#setNamingStrategy + */ + public void setNamingStrategy(NamingStrategy namingStrategy) { + this.namingStrategy = namingStrategy; + } + + /** + * Set Hibernate properties, such as "hibernate.dialect". + *

Note: Do not specify a transaction provider here when using + * Spring-driven transactions. It is also advisable to omit connection + * provider settings and use a Spring-set DataSource instead. + * @see #setDataSource + */ + public void setHibernateProperties(Properties hibernateProperties) { + this.hibernateProperties = hibernateProperties; + } + + /** + * Return the Hibernate properties, if any. Mainly available for + * configuration through property paths that specify individual keys. + */ + public Properties getHibernateProperties() { + if (this.hibernateProperties == null) { + this.hibernateProperties = new Properties(); + } + return this.hibernateProperties; + } + + /** + * Specify annotated entity classes to register with this Hibernate SessionFactory. + * @see org.hibernate.cfg.Configuration#addAnnotatedClass(String) + */ + public void setAnnotatedClasses(Class[] annotatedClasses) { + this.annotatedClasses = annotatedClasses; + } + + /** + * Specify the names of annotated packages, for which package-level + * annotation metadata will be read. + * @see org.hibernate.cfg.Configuration#addPackage(String) + */ + public void setAnnotatedPackages(String[] annotatedPackages) { + this.annotatedPackages = annotatedPackages; + } + + /** + * Specify packages to search for autodetection of your entity classes in the + * classpath. This is analogous to Spring's component-scan feature + * ({@link org.springframework.context.annotation.ClassPathBeanDefinitionScanner}). + */ + public void setPackagesToScan(String... packagesToScan) { + this.packagesToScan = packagesToScan; + } + + public void setResourceLoader(ResourceLoader resourceLoader) { + this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader); + } + + + public void afterPropertiesSet() throws IOException { + LocalSessionFactoryBuilder sfb = new LocalSessionFactoryBuilder(this.dataSource, this.resourcePatternResolver); + + if (this.configLocations != null) { + for (Resource resource : this.configLocations) { + // Load Hibernate configuration from given location. + sfb.configure(resource.getURL()); + } + } + + if (this.mappingResources != null) { + // Register given Hibernate mapping definitions, contained in resource files. + for (String mapping : this.mappingResources) { + Resource mr = new ClassPathResource(mapping.trim(), this.resourcePatternResolver.getClassLoader()); + sfb.addInputStream(mr.getInputStream()); + } + } + + if (this.mappingLocations != null) { + // Register given Hibernate mapping definitions, contained in resource files. + for (Resource resource : this.mappingLocations) { + sfb.addInputStream(resource.getInputStream()); + } + } + + if (this.cacheableMappingLocations != null) { + // Register given cacheable Hibernate mapping definitions, read from the file system. + for (Resource resource : this.cacheableMappingLocations) { + sfb.addCacheableFile(resource.getFile()); + } + } + + if (this.mappingJarLocations != null) { + // Register given Hibernate mapping definitions, contained in jar files. + for (Resource resource : this.mappingJarLocations) { + sfb.addJar(resource.getFile()); + } + } + + if (this.mappingDirectoryLocations != null) { + // Register all Hibernate mapping definitions in the given directories. + for (Resource resource : this.mappingDirectoryLocations) { + File file = resource.getFile(); + if (!file.isDirectory()) { + throw new IllegalArgumentException( + "Mapping directory location [" + resource + "] does not denote a directory"); + } + sfb.addDirectory(file); + } + } + + if (this.namingStrategy != null) { + sfb.setNamingStrategy(this.namingStrategy); + } + + if (this.hibernateProperties != null) { + sfb.addProperties(this.hibernateProperties); + } + + if (this.annotatedClasses != null) { + sfb.addAnnotatedClasses(this.annotatedClasses); + } + + if (this.annotatedPackages != null) { + sfb.addPackages(this.annotatedPackages); + } + + if (this.packagesToScan != null) { + sfb.scanPackages(this.packagesToScan); + } + + this.sessionFactory = sfb.buildSessionFactory(); + } + + + public SessionFactory getObject() { + return this.sessionFactory; + } + + public Class getObjectType() { + return (this.sessionFactory != null ? this.sessionFactory.getClass() : SessionFactory.class); + } + + public boolean isSingleton() { + return true; + } + + + public void destroy() { + this.sessionFactory.close(); + } + +} diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SmartPersistenceUnitInfo.java b/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SmartPersistenceUnitInfo.java index 176e49556f..1d90c22251 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SmartPersistenceUnitInfo.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/jpa/persistenceunit/SmartPersistenceUnitInfo.java @@ -1,40 +1,40 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.orm.jpa.persistenceunit; - -import javax.persistence.spi.PersistenceUnitInfo; - -/** - * Extension of the standard JPA PersistenceUnitInfo interface, for advanced collaboration - * between Spring's {@link org.springframework.orm.jpa.LocalEntityManagerFactoryBean} and - * {@link PersistenceUnitManager} implementations. - * - * @author Juergen Hoeller - * @since 3.0.1 - * @see PersistenceUnitManager - * @see org.springframework.orm.jpa.LocalEntityManagerFactoryBean - */ -public interface SmartPersistenceUnitInfo extends PersistenceUnitInfo { - - /** - * Set the persistence provider's own package name, for exclusion from class transformation. - * @see #addTransformer(javax.persistence.spi.ClassTransformer) - * @see #getNewTempClassLoader() - */ - void setPersistenceProviderPackageName(String persistenceProviderPackageName); - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.jpa.persistenceunit; + +import javax.persistence.spi.PersistenceUnitInfo; + +/** + * Extension of the standard JPA PersistenceUnitInfo interface, for advanced collaboration + * between Spring's {@link org.springframework.orm.jpa.LocalEntityManagerFactoryBean} and + * {@link PersistenceUnitManager} implementations. + * + * @author Juergen Hoeller + * @since 3.0.1 + * @see PersistenceUnitManager + * @see org.springframework.orm.jpa.LocalEntityManagerFactoryBean + */ +public interface SmartPersistenceUnitInfo extends PersistenceUnitInfo { + + /** + * Set the persistence provider's own package name, for exclusion from class transformation. + * @see #addTransformer(javax.persistence.spi.ClassTransformer) + * @see #getNewTempClassLoader() + */ + void setPersistenceProviderPackageName(String persistenceProviderPackageName); + +} diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaSessionFactoryBean.java b/org.springframework.orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaSessionFactoryBean.java index ba3c5c4b28..a1584090ab 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaSessionFactoryBean.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/jpa/vendor/HibernateJpaSessionFactoryBean.java @@ -1,56 +1,56 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.vendor; - -import javax.persistence.EntityManagerFactory; - -import org.hibernate.SessionFactory; -import org.hibernate.ejb.HibernateEntityManagerFactory; - -import org.springframework.beans.factory.FactoryBean; -import org.springframework.orm.jpa.EntityManagerFactoryAccessor; -import org.springframework.util.Assert; - -/** - * Simple FactoryBean that exposes the underlying {@link SessionFactory} - * behind a Hibernate-backed JPA {@link EntityManagerFactory}. - * - *

Primarily available for resolving a SessionFactory by JPA persistence unit name - * via the {@link #setPersistenceUnitName "persistenceUnitName"} bean property. - * - * @author Juergen Hoeller - * @since 3.1 - * @see #setPersistenceUnitName - * @see #setEntityManagerFactory - */ -public class HibernateJpaSessionFactoryBean extends EntityManagerFactoryAccessor implements FactoryBean { - - public SessionFactory getObject() { - EntityManagerFactory emf = getEntityManagerFactory(); - Assert.isInstanceOf(HibernateEntityManagerFactory.class, emf); - return ((HibernateEntityManagerFactory) emf).getSessionFactory(); - } - - public Class getObjectType() { - return SessionFactory.class; - } - - public boolean isSingleton() { - return true; - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.vendor; + +import javax.persistence.EntityManagerFactory; + +import org.hibernate.SessionFactory; +import org.hibernate.ejb.HibernateEntityManagerFactory; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.orm.jpa.EntityManagerFactoryAccessor; +import org.springframework.util.Assert; + +/** + * Simple FactoryBean that exposes the underlying {@link SessionFactory} + * behind a Hibernate-backed JPA {@link EntityManagerFactory}. + * + *

Primarily available for resolving a SessionFactory by JPA persistence unit name + * via the {@link #setPersistenceUnitName "persistenceUnitName"} bean property. + * + * @author Juergen Hoeller + * @since 3.1 + * @see #setPersistenceUnitName + * @see #setEntityManagerFactory + */ +public class HibernateJpaSessionFactoryBean extends EntityManagerFactoryAccessor implements FactoryBean { + + public SessionFactory getObject() { + EntityManagerFactory emf = getEntityManagerFactory(); + Assert.isInstanceOf(HibernateEntityManagerFactory.class, emf); + return ((HibernateEntityManagerFactory) emf).getSessionFactory(); + } + + public Class getObjectType() { + return SessionFactory.class; + } + + public boolean isSingleton() { + return true; + } + +} diff --git a/org.springframework.orm/src/test/java/org/springframework/orm/hibernate3/CglibProxyBridgeMethodTests.java b/org.springframework.orm/src/test/java/org/springframework/orm/hibernate3/CglibProxyBridgeMethodTests.java index ba55810ffe..4a6c4e00a2 100644 --- a/org.springframework.orm/src/test/java/org/springframework/orm/hibernate3/CglibProxyBridgeMethodTests.java +++ b/org.springframework.orm/src/test/java/org/springframework/orm/hibernate3/CglibProxyBridgeMethodTests.java @@ -1,73 +1,73 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.orm.hibernate3; - -import java.io.Serializable; - -import org.hibernate.proxy.HibernateProxy; -import org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer; -import org.junit.Test; - -import org.springframework.beans.BeanUtils; - -/** - * Test for compatibility of Spring's BeanUtils and its BridgeMethodResolver use - * when operating on a Hibernate-generated CGLIB proxy class. - * - * @author Arnout Engelen - * @author Juergen Hoeller - */ -public class CglibProxyBridgeMethodTests { - - @Test - public void introspectHibernateProxyForGenericClass() { - BeanUtils.getPropertyDescriptor(CglibInstantieMedewerker.class, "organisatie"); - Class clazz = CGLIBLazyInitializer.getProxyFactory( - CglibInstantieMedewerker.class, new Class[] {HibernateProxy.class}); - BeanUtils.getPropertyDescriptor(clazz, "organisatie"); - } - - - public interface CglibIOrganisatie { - } - - - public class CglibOrganisatie implements CglibIOrganisatie { - } - - - public class CglibInstantie extends CglibOrganisatie { - } - - - public interface CglibIOrganisatieMedewerker { - - void setOrganisatie(T organisatie); - } - - - public class CglibOrganisatieMedewerker implements CglibIOrganisatieMedewerker { - - public void setOrganisatie(CglibOrganisatie organisatie) { - } - } - - - public class CglibInstantieMedewerker extends CglibOrganisatieMedewerker implements Serializable { - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.orm.hibernate3; + +import java.io.Serializable; + +import org.hibernate.proxy.HibernateProxy; +import org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer; +import org.junit.Test; + +import org.springframework.beans.BeanUtils; + +/** + * Test for compatibility of Spring's BeanUtils and its BridgeMethodResolver use + * when operating on a Hibernate-generated CGLIB proxy class. + * + * @author Arnout Engelen + * @author Juergen Hoeller + */ +public class CglibProxyBridgeMethodTests { + + @Test + public void introspectHibernateProxyForGenericClass() { + BeanUtils.getPropertyDescriptor(CglibInstantieMedewerker.class, "organisatie"); + Class clazz = CGLIBLazyInitializer.getProxyFactory( + CglibInstantieMedewerker.class, new Class[] {HibernateProxy.class}); + BeanUtils.getPropertyDescriptor(clazz, "organisatie"); + } + + + public interface CglibIOrganisatie { + } + + + public class CglibOrganisatie implements CglibIOrganisatie { + } + + + public class CglibInstantie extends CglibOrganisatie { + } + + + public interface CglibIOrganisatieMedewerker { + + void setOrganisatie(T organisatie); + } + + + public class CglibOrganisatieMedewerker implements CglibIOrganisatieMedewerker { + + public void setOrganisatie(CglibOrganisatie organisatie) { + } + } + + + public class CglibInstantieMedewerker extends CglibOrganisatieMedewerker implements Serializable { + } + +} diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorMappingException.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorMappingException.java index fc881da516..4ecc63168b 100644 --- a/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorMappingException.java +++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorMappingException.java @@ -1,39 +1,39 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.oxm.castor; - -import org.springframework.oxm.XmlMappingException; - -/** - * Exception thrown by {@link CastorMarshaller} whenever it encounters a mapping problem. - * - * @author Juergen Hoeller - * @since 3.0 - */ -public class CastorMappingException extends XmlMappingException { - - /** - * Construct a CastorMappingException with the specified detail message - * and nested exception. - * @param msg the detail message - * @param cause the nested exception - */ - public CastorMappingException(String msg, Throwable cause) { - super(msg, cause); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.oxm.castor; + +import org.springframework.oxm.XmlMappingException; + +/** + * Exception thrown by {@link CastorMarshaller} whenever it encounters a mapping problem. + * + * @author Juergen Hoeller + * @since 3.0 + */ +public class CastorMappingException extends XmlMappingException { + + /** + * Construct a CastorMappingException with the specified detail message + * and nested exception. + * @param msg the detail message + * @param cause the nested exception + */ + public CastorMappingException(String msg, Throwable cause) { + super(msg, cause); + } + +} diff --git a/org.springframework.oxm/src/main/resources/META-INF/spring.schemas b/org.springframework.oxm/src/main/resources/META-INF/spring.schemas index e746146264..89359c315e 100644 --- a/org.springframework.oxm/src/main/resources/META-INF/spring.schemas +++ b/org.springframework.oxm/src/main/resources/META-INF/spring.schemas @@ -1,3 +1,3 @@ -http\://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd=org/springframework/oxm/config/spring-oxm-3.0.xsd -http\://www.springframework.org/schema/oxm/spring-oxm-3.1.xsd=org/springframework/oxm/config/spring-oxm-3.1.xsd -http\://www.springframework.org/schema/oxm/spring-oxm.xsd=org/springframework/oxm/config/spring-oxm-3.1.xsd +http\://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd=org/springframework/oxm/config/spring-oxm-3.0.xsd +http\://www.springframework.org/schema/oxm/spring-oxm-3.1.xsd=org/springframework/oxm/config/spring-oxm-3.1.xsd +http\://www.springframework.org/schema/oxm/spring-oxm.xsd=org/springframework/oxm/config/spring-oxm-3.1.xsd diff --git a/org.springframework.test/src/main/java/org/springframework/mock/web/portlet/MockCacheControl.java b/org.springframework.test/src/main/java/org/springframework/mock/web/portlet/MockCacheControl.java index 45dcae7d5e..0ee9fbeb7c 100644 --- a/org.springframework.test/src/main/java/org/springframework/mock/web/portlet/MockCacheControl.java +++ b/org.springframework.test/src/main/java/org/springframework/mock/web/portlet/MockCacheControl.java @@ -1,70 +1,70 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web.portlet; - -import javax.portlet.CacheControl; - -/** - * Mock implementation of the {@link javax.portlet.CacheControl} interface. - * - * @author Juergen Hoeller - * @since 3.0 - */ -public class MockCacheControl implements CacheControl { - - private int expirationTime = 0; - - private boolean publicScope = false; - - private String etag; - - private boolean useCachedContent = false; - - - public int getExpirationTime() { - return this.expirationTime; - } - - public void setExpirationTime(int time) { - this.expirationTime = time; - } - - public boolean isPublicScope() { - return this.publicScope; - } - - public void setPublicScope(boolean publicScope) { - this.publicScope = publicScope; - } - - public String getETag() { - return this.etag; - } - - public void setETag(String token) { - this.etag = token; - } - - public boolean useCachedContent() { - return this.useCachedContent; - } - - public void setUseCachedContent(boolean useCachedContent) { - this.useCachedContent = useCachedContent; - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web.portlet; + +import javax.portlet.CacheControl; + +/** + * Mock implementation of the {@link javax.portlet.CacheControl} interface. + * + * @author Juergen Hoeller + * @since 3.0 + */ +public class MockCacheControl implements CacheControl { + + private int expirationTime = 0; + + private boolean publicScope = false; + + private String etag; + + private boolean useCachedContent = false; + + + public int getExpirationTime() { + return this.expirationTime; + } + + public void setExpirationTime(int time) { + this.expirationTime = time; + } + + public boolean isPublicScope() { + return this.publicScope; + } + + public void setPublicScope(boolean publicScope) { + this.publicScope = publicScope; + } + + public String getETag() { + return this.etag; + } + + public void setETag(String token) { + this.etag = token; + } + + public boolean useCachedContent() { + return this.useCachedContent; + } + + public void setUseCachedContent(boolean useCachedContent) { + this.useCachedContent = useCachedContent; + } + +} diff --git a/org.springframework.test/src/main/java/org/springframework/mock/web/portlet/MockEvent.java b/org.springframework.test/src/main/java/org/springframework/mock/web/portlet/MockEvent.java index b58aced0ba..0dc7efaba8 100644 --- a/org.springframework.test/src/main/java/org/springframework/mock/web/portlet/MockEvent.java +++ b/org.springframework.test/src/main/java/org/springframework/mock/web/portlet/MockEvent.java @@ -1,88 +1,88 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web.portlet; - -import java.io.Serializable; -import javax.portlet.Event; -import javax.xml.namespace.QName; - -/** - * Mock implementation of the {@link javax.portlet.Event} interface. - * - * @author Juergen Hoeller - * @since 3.0 - * @see MockEventRequest - */ -public class MockEvent implements Event { - - private final QName name; - - private final Serializable value; - - - /** - * Create a new MockEvent with the given name. - * @param name the name of the event - */ - public MockEvent(QName name) { - this.name = name; - this.value = null; - } - - /** - * Create a new MockEvent with the given name and value. - * @param name the name of the event - * @param value the associated payload of the event - */ - public MockEvent(QName name, Serializable value) { - this.name = name; - this.value = value; - } - - /** - * Create a new MockEvent with the given name. - * @param name the name of the event - */ - public MockEvent(String name) { - this.name = new QName(name); - this.value = null; - } - - /** - * Create a new MockEvent with the given name and value. - * @param name the name of the event - * @param value the associated payload of the event - */ - public MockEvent(String name, Serializable value) { - this.name = new QName(name); - this.value = value; - } - - - public QName getQName() { - return this.name; - } - - public String getName() { - return this.name.getLocalPart(); - } - - public Serializable getValue() { - return this.value; - } - +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web.portlet; + +import java.io.Serializable; +import javax.portlet.Event; +import javax.xml.namespace.QName; + +/** + * Mock implementation of the {@link javax.portlet.Event} interface. + * + * @author Juergen Hoeller + * @since 3.0 + * @see MockEventRequest + */ +public class MockEvent implements Event { + + private final QName name; + + private final Serializable value; + + + /** + * Create a new MockEvent with the given name. + * @param name the name of the event + */ + public MockEvent(QName name) { + this.name = name; + this.value = null; + } + + /** + * Create a new MockEvent with the given name and value. + * @param name the name of the event + * @param value the associated payload of the event + */ + public MockEvent(QName name, Serializable value) { + this.name = name; + this.value = value; + } + + /** + * Create a new MockEvent with the given name. + * @param name the name of the event + */ + public MockEvent(String name) { + this.name = new QName(name); + this.value = null; + } + + /** + * Create a new MockEvent with the given name and value. + * @param name the name of the event + * @param value the associated payload of the event + */ + public MockEvent(String name, Serializable value) { + this.name = new QName(name); + this.value = value; + } + + + public QName getQName() { + return this.name; + } + + public String getName() { + return this.name.getLocalPart(); + } + + public Serializable getValue() { + return this.value; + } + } \ No newline at end of file diff --git a/org.springframework.test/src/main/java/org/springframework/mock/web/portlet/ServletWrappingPortletContext.java b/org.springframework.test/src/main/java/org/springframework/mock/web/portlet/ServletWrappingPortletContext.java index 16b3979ca7..8a88066c93 100644 --- a/org.springframework.test/src/main/java/org/springframework/mock/web/portlet/ServletWrappingPortletContext.java +++ b/org.springframework.test/src/main/java/org/springframework/mock/web/portlet/ServletWrappingPortletContext.java @@ -1,145 +1,145 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web.portlet; - -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Set; -import javax.portlet.PortletContext; -import javax.portlet.PortletRequestDispatcher; -import javax.servlet.ServletContext; - -import org.springframework.util.Assert; - -/** - * Mock implementation of the {@link javax.portlet.PortletContext} interface, - * wrapping an underlying {@link javax.servlet.ServletContext}. - * - * @author Juergen Hoeller - * @since 3.0 - * @see MockPortletContext - */ -public class ServletWrappingPortletContext implements PortletContext { - - private final ServletContext servletContext; - - - /** - * Create a new PortletContext wrapping the given ServletContext. - * @param servletContext the ServletContext to wrap - */ - public ServletWrappingPortletContext(ServletContext servletContext) { - Assert.notNull(servletContext, "ServletContext must not be null"); - this.servletContext = servletContext; - } - - /** - * Return the underlying ServletContext that this PortletContext wraps. - */ - public final ServletContext getServletContext() { - return this.servletContext; - } - - - public String getServerInfo() { - return this.servletContext.getServerInfo(); - } - - public PortletRequestDispatcher getRequestDispatcher(String path) { - return null; - } - - public PortletRequestDispatcher getNamedDispatcher(String name) { - return null; - } - - public InputStream getResourceAsStream(String path) { - return this.servletContext.getResourceAsStream(path); - } - - public int getMajorVersion() { - return 2; - } - - public int getMinorVersion() { - return 0; - } - - public String getMimeType(String file) { - return this.servletContext.getMimeType(file); - } - - public String getRealPath(String path) { - return this.servletContext.getRealPath(path); - } - - @SuppressWarnings("unchecked") - public Set getResourcePaths(String path) { - return this.servletContext.getResourcePaths(path); - } - - public URL getResource(String path) throws MalformedURLException { - return this.servletContext.getResource(path); - } - - public Object getAttribute(String name) { - return this.servletContext.getAttribute(name); - } - - @SuppressWarnings("unchecked") - public Enumeration getAttributeNames() { - return this.servletContext.getAttributeNames(); - } - - public String getInitParameter(String name) { - return this.servletContext.getInitParameter(name); - } - - @SuppressWarnings("unchecked") - public Enumeration getInitParameterNames() { - return this.servletContext.getInitParameterNames(); - } - - public void log(String msg) { - this.servletContext.log(msg); - } - - public void log(String message, Throwable throwable) { - this.servletContext.log(message, throwable); - } - - public void removeAttribute(String name) { - this.servletContext.removeAttribute(name); - } - - public void setAttribute(String name, Object object) { - this.servletContext.setAttribute(name, object); - } - - public String getPortletContextName() { - return this.servletContext.getServletContextName(); - } - - public Enumeration getContainerRuntimeOptions() { - return Collections.enumeration(new HashSet()); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web.portlet; + +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Set; +import javax.portlet.PortletContext; +import javax.portlet.PortletRequestDispatcher; +import javax.servlet.ServletContext; + +import org.springframework.util.Assert; + +/** + * Mock implementation of the {@link javax.portlet.PortletContext} interface, + * wrapping an underlying {@link javax.servlet.ServletContext}. + * + * @author Juergen Hoeller + * @since 3.0 + * @see MockPortletContext + */ +public class ServletWrappingPortletContext implements PortletContext { + + private final ServletContext servletContext; + + + /** + * Create a new PortletContext wrapping the given ServletContext. + * @param servletContext the ServletContext to wrap + */ + public ServletWrappingPortletContext(ServletContext servletContext) { + Assert.notNull(servletContext, "ServletContext must not be null"); + this.servletContext = servletContext; + } + + /** + * Return the underlying ServletContext that this PortletContext wraps. + */ + public final ServletContext getServletContext() { + return this.servletContext; + } + + + public String getServerInfo() { + return this.servletContext.getServerInfo(); + } + + public PortletRequestDispatcher getRequestDispatcher(String path) { + return null; + } + + public PortletRequestDispatcher getNamedDispatcher(String name) { + return null; + } + + public InputStream getResourceAsStream(String path) { + return this.servletContext.getResourceAsStream(path); + } + + public int getMajorVersion() { + return 2; + } + + public int getMinorVersion() { + return 0; + } + + public String getMimeType(String file) { + return this.servletContext.getMimeType(file); + } + + public String getRealPath(String path) { + return this.servletContext.getRealPath(path); + } + + @SuppressWarnings("unchecked") + public Set getResourcePaths(String path) { + return this.servletContext.getResourcePaths(path); + } + + public URL getResource(String path) throws MalformedURLException { + return this.servletContext.getResource(path); + } + + public Object getAttribute(String name) { + return this.servletContext.getAttribute(name); + } + + @SuppressWarnings("unchecked") + public Enumeration getAttributeNames() { + return this.servletContext.getAttributeNames(); + } + + public String getInitParameter(String name) { + return this.servletContext.getInitParameter(name); + } + + @SuppressWarnings("unchecked") + public Enumeration getInitParameterNames() { + return this.servletContext.getInitParameterNames(); + } + + public void log(String msg) { + this.servletContext.log(msg); + } + + public void log(String message, Throwable throwable) { + this.servletContext.log(message, throwable); + } + + public void removeAttribute(String name) { + this.servletContext.removeAttribute(name); + } + + public void setAttribute(String name, Object object) { + this.servletContext.setAttribute(name, object); + } + + public String getPortletContextName() { + return this.servletContext.getServletContextName(); + } + + public Enumeration getContainerRuntimeOptions() { + return Collections.enumeration(new HashSet()); + } + +} diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/expression/ExpressionUsageTests.java b/org.springframework.test/src/test/java/org/springframework/test/context/expression/ExpressionUsageTests.java index ddb846d4f5..723a3c1c08 100644 --- a/org.springframework.test/src/test/java/org/springframework/test/context/expression/ExpressionUsageTests.java +++ b/org.springframework.test/src/test/java/org/springframework/test/context/expression/ExpressionUsageTests.java @@ -1,83 +1,83 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.expression; - -import static junit.framework.Assert.assertEquals; - -import java.util.Properties; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -/** - * @author Andy Clement - * @author Dave Syer - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration -public class ExpressionUsageTests { - - @Autowired - @Qualifier("derived") - private Properties props; - - @Autowired - @Qualifier("andy2") - private Foo andy2; - - @Autowired - @Qualifier("andy") - private Foo andy; - - - @Test - public void testSpr5906() throws Exception { - // verify the property values have been evaluated as expressions - assertEquals("Dave", props.getProperty("user.name")); - assertEquals("Andy", props.getProperty("username")); - - // verify the property keys have been evaluated as expressions - assertEquals("exists", props.getProperty("Dave")); - assertEquals("exists also", props.getProperty("Andy")); - } - - @Test - public void testSpr5847() throws Exception { - assertEquals("Andy", andy2.getName()); - assertEquals("Andy", andy.getName()); - } - - - public static class Foo { - - private String name; - - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.expression; + +import static junit.framework.Assert.assertEquals; + +import java.util.Properties; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Andy Clement + * @author Dave Syer + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +public class ExpressionUsageTests { + + @Autowired + @Qualifier("derived") + private Properties props; + + @Autowired + @Qualifier("andy2") + private Foo andy2; + + @Autowired + @Qualifier("andy") + private Foo andy; + + + @Test + public void testSpr5906() throws Exception { + // verify the property values have been evaluated as expressions + assertEquals("Dave", props.getProperty("user.name")); + assertEquals("Andy", props.getProperty("username")); + + // verify the property keys have been evaluated as expressions + assertEquals("exists", props.getProperty("Dave")); + assertEquals("exists also", props.getProperty("Andy")); + } + + @Test + public void testSpr5847() throws Exception { + assertEquals("Andy", andy2.getName()); + assertEquals("Andy", andy.getName()); + } + + + public static class Foo { + + private String name; + + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + +} diff --git a/org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/TransactionAspectUtils.java b/org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/TransactionAspectUtils.java index 9d07609fdd..84b082a272 100644 --- a/org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/TransactionAspectUtils.java +++ b/org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/TransactionAspectUtils.java @@ -1,135 +1,135 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.interceptor; - -import java.lang.reflect.Method; -import java.util.Map; - -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryUtils; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.support.AbstractBeanDefinition; -import org.springframework.beans.factory.support.AutowireCandidateQualifier; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.util.ObjectUtils; - -/** - * Utility methods for obtaining a PlatformTransactionManager by - * {@link TransactionAttribute#getQualifier() qualifier value}. - * - * @author Juergen Hoeller - * @since 3.0.2 - */ -public abstract class TransactionAspectUtils { - - /** - * Obtain a PlatformTransactionManager from the given BeanFactory, - * matching the given qualifier. - * @param beanFactory the BeanFactory to get the PlatformTransactionManager bean from - * @param qualifier the qualifier for selecting between multiple PlatformTransactionManager matches - * @return the chosen PlatformTransactionManager (never null) - * @throws IllegalStateException if no matching PlatformTransactionManager bean found - */ - public static PlatformTransactionManager getTransactionManager(BeanFactory beanFactory, String qualifier) { - if (beanFactory instanceof ConfigurableListableBeanFactory) { - // Full qualifier matching supported. - return getTransactionManager((ConfigurableListableBeanFactory) beanFactory, qualifier); - } - else if (beanFactory.containsBean(qualifier)) { - // Fallback: PlatformTransactionManager at least found by bean name. - return beanFactory.getBean(qualifier, PlatformTransactionManager.class); - } - else { - throw new IllegalStateException("No matching PlatformTransactionManager bean found for bean name '" + - qualifier + "'! (Note: Qualifier matching not supported because given BeanFactory does not " + - "implement ConfigurableListableBeanFactory.)"); - } - } - - /** - * Obtain a PlatformTransactionManager from the given BeanFactory, - * matching the given qualifier. - * @param bf the BeanFactory to get the PlatformTransactionManager bean from - * @param qualifier the qualifier for selecting between multiple PlatformTransactionManager matches - * @return the chosen PlatformTransactionManager (never null) - * @throws IllegalStateException if no matching PlatformTransactionManager bean found - */ - public static PlatformTransactionManager getTransactionManager(ConfigurableListableBeanFactory bf, String qualifier) { - Map tms = - BeanFactoryUtils.beansOfTypeIncludingAncestors(bf, PlatformTransactionManager.class); - PlatformTransactionManager chosen = null; - for (String beanName : tms.keySet()) { - if (isQualifierMatch(qualifier, beanName, bf)) { - if (chosen != null) { - throw new IllegalStateException("No unique PlatformTransactionManager bean found " + - "for qualifier '" + qualifier + "'"); - } - chosen = tms.get(beanName); - } - } - if (chosen != null) { - return chosen; - } - else { - throw new IllegalStateException("No matching PlatformTransactionManager bean found for qualifier '" + - qualifier + "' - neither qualifier match nor bean name match!"); - } - } - - /** - * Check whether we have a qualifier match for the given candidate bean. - * @param qualifier the qualifier that we are looking for - * @param beanName the name of the candidate bean - * @param bf the BeanFactory to get the bean definition from - * @return true if either the bean definition (in the XML case) - * or the bean's factory method (in the @Bean case) defines a matching qualifier - * value (through <qualifier<> or @Qualifier) - */ - private static boolean isQualifierMatch(String qualifier, String beanName, ConfigurableListableBeanFactory bf) { - if (bf.containsBean(beanName)) { - try { - BeanDefinition bd = bf.getMergedBeanDefinition(beanName); - if (bd instanceof AbstractBeanDefinition) { - AbstractBeanDefinition abd = (AbstractBeanDefinition) bd; - AutowireCandidateQualifier candidate = abd.getQualifier(Qualifier.class.getName()); - if ((candidate != null && qualifier.equals(candidate.getAttribute(AutowireCandidateQualifier.VALUE_KEY))) || - qualifier.equals(beanName) || ObjectUtils.containsElement(bf.getAliases(beanName), qualifier)) { - return true; - } - } - if (bd instanceof RootBeanDefinition) { - Method factoryMethod = ((RootBeanDefinition) bd).getResolvedFactoryMethod(); - if (factoryMethod != null) { - Qualifier targetAnnotation = factoryMethod.getAnnotation(Qualifier.class); - if (targetAnnotation != null && qualifier.equals(targetAnnotation.value())) { - return true; - } - } - } - } - catch (NoSuchBeanDefinitionException ex) { - // ignore - can't compare qualifiers for a manually registered singleton object - } - } - return false; - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.interceptor; + +import java.lang.reflect.Method; +import java.util.Map; + +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryUtils; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.AutowireCandidateQualifier; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.util.ObjectUtils; + +/** + * Utility methods for obtaining a PlatformTransactionManager by + * {@link TransactionAttribute#getQualifier() qualifier value}. + * + * @author Juergen Hoeller + * @since 3.0.2 + */ +public abstract class TransactionAspectUtils { + + /** + * Obtain a PlatformTransactionManager from the given BeanFactory, + * matching the given qualifier. + * @param beanFactory the BeanFactory to get the PlatformTransactionManager bean from + * @param qualifier the qualifier for selecting between multiple PlatformTransactionManager matches + * @return the chosen PlatformTransactionManager (never null) + * @throws IllegalStateException if no matching PlatformTransactionManager bean found + */ + public static PlatformTransactionManager getTransactionManager(BeanFactory beanFactory, String qualifier) { + if (beanFactory instanceof ConfigurableListableBeanFactory) { + // Full qualifier matching supported. + return getTransactionManager((ConfigurableListableBeanFactory) beanFactory, qualifier); + } + else if (beanFactory.containsBean(qualifier)) { + // Fallback: PlatformTransactionManager at least found by bean name. + return beanFactory.getBean(qualifier, PlatformTransactionManager.class); + } + else { + throw new IllegalStateException("No matching PlatformTransactionManager bean found for bean name '" + + qualifier + "'! (Note: Qualifier matching not supported because given BeanFactory does not " + + "implement ConfigurableListableBeanFactory.)"); + } + } + + /** + * Obtain a PlatformTransactionManager from the given BeanFactory, + * matching the given qualifier. + * @param bf the BeanFactory to get the PlatformTransactionManager bean from + * @param qualifier the qualifier for selecting between multiple PlatformTransactionManager matches + * @return the chosen PlatformTransactionManager (never null) + * @throws IllegalStateException if no matching PlatformTransactionManager bean found + */ + public static PlatformTransactionManager getTransactionManager(ConfigurableListableBeanFactory bf, String qualifier) { + Map tms = + BeanFactoryUtils.beansOfTypeIncludingAncestors(bf, PlatformTransactionManager.class); + PlatformTransactionManager chosen = null; + for (String beanName : tms.keySet()) { + if (isQualifierMatch(qualifier, beanName, bf)) { + if (chosen != null) { + throw new IllegalStateException("No unique PlatformTransactionManager bean found " + + "for qualifier '" + qualifier + "'"); + } + chosen = tms.get(beanName); + } + } + if (chosen != null) { + return chosen; + } + else { + throw new IllegalStateException("No matching PlatformTransactionManager bean found for qualifier '" + + qualifier + "' - neither qualifier match nor bean name match!"); + } + } + + /** + * Check whether we have a qualifier match for the given candidate bean. + * @param qualifier the qualifier that we are looking for + * @param beanName the name of the candidate bean + * @param bf the BeanFactory to get the bean definition from + * @return true if either the bean definition (in the XML case) + * or the bean's factory method (in the @Bean case) defines a matching qualifier + * value (through <qualifier<> or @Qualifier) + */ + private static boolean isQualifierMatch(String qualifier, String beanName, ConfigurableListableBeanFactory bf) { + if (bf.containsBean(beanName)) { + try { + BeanDefinition bd = bf.getMergedBeanDefinition(beanName); + if (bd instanceof AbstractBeanDefinition) { + AbstractBeanDefinition abd = (AbstractBeanDefinition) bd; + AutowireCandidateQualifier candidate = abd.getQualifier(Qualifier.class.getName()); + if ((candidate != null && qualifier.equals(candidate.getAttribute(AutowireCandidateQualifier.VALUE_KEY))) || + qualifier.equals(beanName) || ObjectUtils.containsElement(bf.getAliases(beanName), qualifier)) { + return true; + } + } + if (bd instanceof RootBeanDefinition) { + Method factoryMethod = ((RootBeanDefinition) bd).getResolvedFactoryMethod(); + if (factoryMethod != null) { + Qualifier targetAnnotation = factoryMethod.getAnnotation(Qualifier.class); + if (targetAnnotation != null && qualifier.equals(targetAnnotation.value())) { + return true; + } + } + } + } + catch (NoSuchBeanDefinitionException ex) { + // ignore - can't compare qualifiers for a manually registered singleton object + } + } + return false; + } + +} diff --git a/org.springframework.transaction/src/main/java/org/springframework/transaction/jta/ManagedTransactionAdapter.java b/org.springframework.transaction/src/main/java/org/springframework/transaction/jta/ManagedTransactionAdapter.java index ee9938c702..d3310106ca 100644 --- a/org.springframework.transaction/src/main/java/org/springframework/transaction/jta/ManagedTransactionAdapter.java +++ b/org.springframework.transaction/src/main/java/org/springframework/transaction/jta/ManagedTransactionAdapter.java @@ -1,89 +1,89 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.transaction.jta; - -import javax.transaction.HeuristicMixedException; -import javax.transaction.HeuristicRollbackException; -import javax.transaction.RollbackException; -import javax.transaction.Synchronization; -import javax.transaction.SystemException; -import javax.transaction.Transaction; -import javax.transaction.TransactionManager; -import javax.transaction.xa.XAResource; - -import org.springframework.util.Assert; - -/** - * Adapter for a managed JTA Transaction handle, taking a JTA - * {@link javax.transaction.TransactionManager} reference and creating - * a JTA {@link javax.transaction.Transaction} handle for it. - * - * @author Juergen Hoeller - * @since 3.0.2 - */ -public class ManagedTransactionAdapter implements Transaction { - - private final TransactionManager transactionManager; - - - /** - * Create a new ManagedTransactionAdapter for the given TransactionManager. - * @param transactionManager the JTA TransactionManager to wrap - */ - public ManagedTransactionAdapter(TransactionManager transactionManager) throws SystemException { - Assert.notNull(transactionManager, "TransactionManager must not be null"); - this.transactionManager = transactionManager; - } - - /** - * Return the JTA TransactionManager that this adapter delegates to. - */ - public final TransactionManager getTransactionManager() { - return this.transactionManager; - } - - - public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, - SecurityException, SystemException { - this.transactionManager.commit(); - } - - public void rollback() throws SystemException { - this.transactionManager.rollback(); - } - - public void setRollbackOnly() throws SystemException { - this.transactionManager.setRollbackOnly(); - } - - public int getStatus() throws SystemException { - return this.transactionManager.getStatus(); - } - - public boolean enlistResource(XAResource xaRes) throws RollbackException, SystemException { - return this.transactionManager.getTransaction().enlistResource(xaRes); - } - - public boolean delistResource(XAResource xaRes, int flag) throws SystemException { - return this.transactionManager.getTransaction().delistResource(xaRes, flag); - } - - public void registerSynchronization(Synchronization sync) throws RollbackException, SystemException { - this.transactionManager.getTransaction().registerSynchronization(sync); - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.jta; + +import javax.transaction.HeuristicMixedException; +import javax.transaction.HeuristicRollbackException; +import javax.transaction.RollbackException; +import javax.transaction.Synchronization; +import javax.transaction.SystemException; +import javax.transaction.Transaction; +import javax.transaction.TransactionManager; +import javax.transaction.xa.XAResource; + +import org.springframework.util.Assert; + +/** + * Adapter for a managed JTA Transaction handle, taking a JTA + * {@link javax.transaction.TransactionManager} reference and creating + * a JTA {@link javax.transaction.Transaction} handle for it. + * + * @author Juergen Hoeller + * @since 3.0.2 + */ +public class ManagedTransactionAdapter implements Transaction { + + private final TransactionManager transactionManager; + + + /** + * Create a new ManagedTransactionAdapter for the given TransactionManager. + * @param transactionManager the JTA TransactionManager to wrap + */ + public ManagedTransactionAdapter(TransactionManager transactionManager) throws SystemException { + Assert.notNull(transactionManager, "TransactionManager must not be null"); + this.transactionManager = transactionManager; + } + + /** + * Return the JTA TransactionManager that this adapter delegates to. + */ + public final TransactionManager getTransactionManager() { + return this.transactionManager; + } + + + public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, + SecurityException, SystemException { + this.transactionManager.commit(); + } + + public void rollback() throws SystemException { + this.transactionManager.rollback(); + } + + public void setRollbackOnly() throws SystemException { + this.transactionManager.setRollbackOnly(); + } + + public int getStatus() throws SystemException { + return this.transactionManager.getStatus(); + } + + public boolean enlistResource(XAResource xaRes) throws RollbackException, SystemException { + return this.transactionManager.getTransaction().enlistResource(xaRes); + } + + public boolean delistResource(XAResource xaRes, int flag) throws SystemException { + return this.transactionManager.getTransaction().delistResource(xaRes, flag); + } + + public void registerSynchronization(Synchronization sync) throws RollbackException, SystemException { + this.transactionManager.getTransaction().registerSynchronization(sync); + } + +} diff --git a/org.springframework.transaction/src/test/java/org/springframework/transaction/config/TransactionManagerConfiguration.java b/org.springframework.transaction/src/test/java/org/springframework/transaction/config/TransactionManagerConfiguration.java index bed910d0e3..11a649ad50 100644 --- a/org.springframework.transaction/src/test/java/org/springframework/transaction/config/TransactionManagerConfiguration.java +++ b/org.springframework.transaction/src/test/java/org/springframework/transaction/config/TransactionManagerConfiguration.java @@ -1,45 +1,45 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.transaction.config; - -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.transaction.CallCountingTransactionManager; -import org.springframework.transaction.PlatformTransactionManager; - -/** - * @author Juergen Hoeller - */ -@Configuration -public class TransactionManagerConfiguration { - - @Bean - @Qualifier("synch") - public PlatformTransactionManager transactionManager1() { - return new CallCountingTransactionManager(); - } - - @Bean - @Qualifier("noSynch") - public PlatformTransactionManager transactionManager2() { - CallCountingTransactionManager tm = new CallCountingTransactionManager(); - tm.setTransactionSynchronization(CallCountingTransactionManager.SYNCHRONIZATION_NEVER); - return tm; - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.transaction.config; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.CallCountingTransactionManager; +import org.springframework.transaction.PlatformTransactionManager; + +/** + * @author Juergen Hoeller + */ +@Configuration +public class TransactionManagerConfiguration { + + @Bean + @Qualifier("synch") + public PlatformTransactionManager transactionManager1() { + return new CallCountingTransactionManager(); + } + + @Bean + @Qualifier("noSynch") + public PlatformTransactionManager transactionManager2() { + CallCountingTransactionManager tm = new CallCountingTransactionManager(); + tm.setTransactionSynchronization(CallCountingTransactionManager.SYNCHRONIZATION_NEVER); + return tm; + } + +} diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/NoHandlerFoundException.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/NoHandlerFoundException.java index bd5ab0c3ca..8c24356729 100644 --- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/NoHandlerFoundException.java +++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/NoHandlerFoundException.java @@ -1,53 +1,53 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.portlet; - -import javax.portlet.PortletException; -import javax.portlet.PortletRequest; - -import org.springframework.core.style.StylerUtils; - -/** - * Exception to be thrown if DispatcherPortlet is unable to determine - * a corresponding handler for an incoming portlet request. - * - * @author Juergen Hoeller - * @since 3.0.5 - */ -public class NoHandlerFoundException extends PortletException { - - /** - * Constructor for NoHandlerFoundException. - * @param msg the detail message - */ - public NoHandlerFoundException(String msg) { - super(msg); - } - - /** - * Constructor for NoHandlerFoundException. - * @param msg the detail message - * @param request the current portlet request, - * for further context to be included in the exception message - */ - public NoHandlerFoundException(String msg, PortletRequest request) { - super(msg + ": mode '" + request.getPortletMode() + - "', phase '" + request.getAttribute(PortletRequest.LIFECYCLE_PHASE) + - "', parameters " + StylerUtils.style(request.getParameterMap())); - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet; + +import javax.portlet.PortletException; +import javax.portlet.PortletRequest; + +import org.springframework.core.style.StylerUtils; + +/** + * Exception to be thrown if DispatcherPortlet is unable to determine + * a corresponding handler for an incoming portlet request. + * + * @author Juergen Hoeller + * @since 3.0.5 + */ +public class NoHandlerFoundException extends PortletException { + + /** + * Constructor for NoHandlerFoundException. + * @param msg the detail message + */ + public NoHandlerFoundException(String msg) { + super(msg); + } + + /** + * Constructor for NoHandlerFoundException. + * @param msg the detail message + * @param request the current portlet request, + * for further context to be included in the exception message + */ + public NoHandlerFoundException(String msg, PortletRequest request) { + super(msg + ": mode '" + request.getPortletMode() + + "', phase '" + request.getAttribute(PortletRequest.LIFECYCLE_PHASE) + + "', parameters " + StylerUtils.style(request.getParameterMap())); + } + +} diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/ActionMapping.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/ActionMapping.java index 0adb5ded1c..28716a9810 100644 --- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/ActionMapping.java +++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/ActionMapping.java @@ -1,63 +1,63 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.portlet.bind.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.web.bind.annotation.Mapping; - -/** - * Annotation for mapping Portlet action requests onto handler methods. - * - * @author Juergen Hoeller - * @since 3.0 - * @see org.springframework.web.bind.annotation.RequestMapping - */ -@Target({ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Mapping -public @interface ActionMapping { - - /** - * The name of the action, according to the Portlet 2.0 - * "javax.portlet.action" parameter. - *

If not specified, the method will be used as default handler: - * i.e. for action requests where no specific action mapping was found. - *

Note that all such annotated action methods only apply within the - * @RequestMapping constraints of the containing handler class. - * @see javax.portlet.ActionRequest#ACTION_NAME - */ - String value() default ""; - - /** - * The parameters of the mapped request, narrowing the primary mapping. - *

Same format for any environment: a sequence of "myParam=myValue" style - * expressions, with a request only mapped if each such parameter is found - * to have the given value. "myParam" style expressions are also supported, - * with such parameters having to be present in the request (allowed to have - * any value). Finally, "!myParam" style expressions indicate that the - * specified parameter is not supposed to be present in the request. - * @see org.springframework.web.bind.annotation.RequestMapping#params() - */ - String[] params() default {}; - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.bind.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.web.bind.annotation.Mapping; + +/** + * Annotation for mapping Portlet action requests onto handler methods. + * + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.web.bind.annotation.RequestMapping + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Mapping +public @interface ActionMapping { + + /** + * The name of the action, according to the Portlet 2.0 + * "javax.portlet.action" parameter. + *

If not specified, the method will be used as default handler: + * i.e. for action requests where no specific action mapping was found. + *

Note that all such annotated action methods only apply within the + * @RequestMapping constraints of the containing handler class. + * @see javax.portlet.ActionRequest#ACTION_NAME + */ + String value() default ""; + + /** + * The parameters of the mapped request, narrowing the primary mapping. + *

Same format for any environment: a sequence of "myParam=myValue" style + * expressions, with a request only mapped if each such parameter is found + * to have the given value. "myParam" style expressions are also supported, + * with such parameters having to be present in the request (allowed to have + * any value). Finally, "!myParam" style expressions indicate that the + * specified parameter is not supposed to be present in the request. + * @see org.springframework.web.bind.annotation.RequestMapping#params() + */ + String[] params() default {}; + +} diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/EventMapping.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/EventMapping.java index c6c605dc82..1d9e45ce98 100644 --- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/EventMapping.java +++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/EventMapping.java @@ -1,52 +1,52 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.portlet.bind.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.web.bind.annotation.Mapping; - -/** - * Annotation for mapping Portlet event requests onto handler methods. - * - * @author Juergen Hoeller - * @since 3.0 - * @see org.springframework.web.bind.annotation.RequestMapping - */ -@Target({ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Mapping() -public @interface EventMapping { - - /** - * The name of the event to be handled. - * This name uniquely identifies an event within a portlet mode. - *

Typically the local name of the event, but fully qualified names - * with a "{...}" namespace part will be mapped correctly as well. - *

If not specified, the handler method will be invoked for any - * event request within its general mapping. - * @see javax.portlet.EventRequest#getEvent() - * @see javax.portlet.Event#getName() - */ - String value() default ""; - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.bind.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.web.bind.annotation.Mapping; + +/** + * Annotation for mapping Portlet event requests onto handler methods. + * + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.web.bind.annotation.RequestMapping + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Mapping() +public @interface EventMapping { + + /** + * The name of the event to be handled. + * This name uniquely identifies an event within a portlet mode. + *

Typically the local name of the event, but fully qualified names + * with a "{...}" namespace part will be mapped correctly as well. + *

If not specified, the handler method will be invoked for any + * event request within its general mapping. + * @see javax.portlet.EventRequest#getEvent() + * @see javax.portlet.Event#getName() + */ + String value() default ""; + +} diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/RenderMapping.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/RenderMapping.java index 7eb8b1dcf9..13e8d31095 100644 --- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/RenderMapping.java +++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/RenderMapping.java @@ -1,62 +1,62 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.portlet.bind.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.web.bind.annotation.Mapping; - -/** - * Annotation for mapping Portlet render requests onto handler methods. - * - * @author Juergen Hoeller - * @since 3.0 - * @see org.springframework.web.bind.annotation.RequestMapping - */ -@Target({ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Mapping -public @interface RenderMapping { - - /** - * The window state that the annotated render method applies for. - *

If not specified, the render method will be invoked for any - * window state within its general mapping. - *

Standard Portlet spec values: "NORMAL", "MAXIMIZED", "MINIMIZED". - * Custom window states can be used as well, as supported by the portal. - * @see javax.portlet.PortletRequest#getWindowState() - */ - String value() default ""; - - /** - * The parameters of the mapped request, narrowing the primary mapping. - *

Same format for any environment: a sequence of "myParam=myValue" style - * expressions, with a request only mapped if each such parameter is found - * to have the given value. "myParam" style expressions are also supported, - * with such parameters having to be present in the request (allowed to have - * any value). Finally, "!myParam" style expressions indicate that the - * specified parameter is not supposed to be present in the request. - * @see org.springframework.web.bind.annotation.RequestMapping#params() - */ - String[] params() default {}; - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.bind.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.web.bind.annotation.Mapping; + +/** + * Annotation for mapping Portlet render requests onto handler methods. + * + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.web.bind.annotation.RequestMapping + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Mapping +public @interface RenderMapping { + + /** + * The window state that the annotated render method applies for. + *

If not specified, the render method will be invoked for any + * window state within its general mapping. + *

Standard Portlet spec values: "NORMAL", "MAXIMIZED", "MINIMIZED". + * Custom window states can be used as well, as supported by the portal. + * @see javax.portlet.PortletRequest#getWindowState() + */ + String value() default ""; + + /** + * The parameters of the mapped request, narrowing the primary mapping. + *

Same format for any environment: a sequence of "myParam=myValue" style + * expressions, with a request only mapped if each such parameter is found + * to have the given value. "myParam" style expressions are also supported, + * with such parameters having to be present in the request (allowed to have + * any value). Finally, "!myParam" style expressions indicate that the + * specified parameter is not supposed to be present in the request. + * @see org.springframework.web.bind.annotation.RequestMapping#params() + */ + String[] params() default {}; + +} diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/ResourceMapping.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/ResourceMapping.java index 250d8e7faa..1da4819200 100644 --- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/ResourceMapping.java +++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/bind/annotation/ResourceMapping.java @@ -1,49 +1,49 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.portlet.bind.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.web.bind.annotation.Mapping; - -/** - * Annotation for mapping Portlet resource requests onto handler methods. - * - * @author Juergen Hoeller - * @since 3.0 - * @see org.springframework.web.bind.annotation.RequestMapping - */ -@Target({ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Mapping() -public @interface ResourceMapping { - - /** - * The id of the resource to be handled. - * This id uniquely identifies a resource within a portlet mode. - *

If not specified, the handler method will be invoked for any - * resource request within its general mapping. - * @see javax.portlet.ResourceRequest#getResourceID() - */ - String value() default ""; - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.bind.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.web.bind.annotation.Mapping; + +/** + * Annotation for mapping Portlet resource requests onto handler methods. + * + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.web.bind.annotation.RequestMapping + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Mapping() +public @interface ResourceMapping { + + /** + * The id of the resource to be handled. + * This id uniquely identifies a resource within a portlet mode. + *

If not specified, the handler method will be invoked for any + * resource request within its general mapping. + * @see javax.portlet.ResourceRequest#getResourceID() + */ + String value() default ""; + +} diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/PortletContextScope.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/PortletContextScope.java index 459ae6a77b..bdd5f6846c 100644 --- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/PortletContextScope.java +++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/PortletContextScope.java @@ -1,111 +1,111 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.portlet.context; - -import java.util.LinkedHashMap; -import java.util.Map; -import javax.portlet.PortletContext; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.ObjectFactory; -import org.springframework.beans.factory.config.Scope; -import org.springframework.util.Assert; - -/** - * {@link Scope} wrapper for a PortletContext, i.e. for global web application attributes. - * - *

This differs from traditional Spring singletons in that it exposes attributes in the - * PortletContext. Those attributes will get destroyed whenever the entire application - * shuts down, which might be earlier or later than the shutdown of the containing Spring - * ApplicationContext. - * - *

The associated destruction mechanism relies on a - * {@link org.springframework.web.context.ContextCleanupListener} being registered in - * web.xml. Note that {@link org.springframework.web.context.ContextLoaderListener} - * includes ContextCleanupListener's functionality. - * - *

This scope is registered as default scope with key - * {@link org.springframework.web.context.WebApplicationContext#SCOPE_APPLICATION "application"}. - * - * @author Juergen Hoeller - * @since 3.0 - * @see org.springframework.web.context.ContextCleanupListener - */ -public class PortletContextScope implements Scope, DisposableBean { - - private final PortletContext portletContext; - - private final Map destructionCallbacks = new LinkedHashMap(); - - - /** - * Create a new Scope wrapper for the given PortletContext. - * @param PortletContext the PortletContext to wrap - */ - public PortletContextScope(PortletContext portletContext) { - Assert.notNull(portletContext, "PortletContext must not be null"); - this.portletContext = portletContext; - } - - - public Object get(String name, ObjectFactory objectFactory) { - Object scopedObject = this.portletContext.getAttribute(name); - if (scopedObject == null) { - scopedObject = objectFactory.getObject(); - this.portletContext.setAttribute(name, scopedObject); - } - return scopedObject; - } - - public Object remove(String name) { - Object scopedObject = this.portletContext.getAttribute(name); - if (scopedObject != null) { - this.portletContext.removeAttribute(name); - this.destructionCallbacks.remove(name); - return scopedObject; - } - else { - return null; - } - } - - public void registerDestructionCallback(String name, Runnable callback) { - this.destructionCallbacks.put(name, callback); - } - - public Object resolveContextualObject(String key) { - return null; - } - - public String getConversationId() { - return null; - } - - - /** - * Invoke all registered destruction callbacks. - * To be called on ServletContext shutdown. - * @see org.springframework.web.context.ContextCleanupListener - */ - public void destroy() { - for (Runnable runnable : this.destructionCallbacks.values()) { - runnable.run(); - } - this.destructionCallbacks.clear(); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.context; + +import java.util.LinkedHashMap; +import java.util.Map; +import javax.portlet.PortletContext; + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.ObjectFactory; +import org.springframework.beans.factory.config.Scope; +import org.springframework.util.Assert; + +/** + * {@link Scope} wrapper for a PortletContext, i.e. for global web application attributes. + * + *

This differs from traditional Spring singletons in that it exposes attributes in the + * PortletContext. Those attributes will get destroyed whenever the entire application + * shuts down, which might be earlier or later than the shutdown of the containing Spring + * ApplicationContext. + * + *

The associated destruction mechanism relies on a + * {@link org.springframework.web.context.ContextCleanupListener} being registered in + * web.xml. Note that {@link org.springframework.web.context.ContextLoaderListener} + * includes ContextCleanupListener's functionality. + * + *

This scope is registered as default scope with key + * {@link org.springframework.web.context.WebApplicationContext#SCOPE_APPLICATION "application"}. + * + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.web.context.ContextCleanupListener + */ +public class PortletContextScope implements Scope, DisposableBean { + + private final PortletContext portletContext; + + private final Map destructionCallbacks = new LinkedHashMap(); + + + /** + * Create a new Scope wrapper for the given PortletContext. + * @param PortletContext the PortletContext to wrap + */ + public PortletContextScope(PortletContext portletContext) { + Assert.notNull(portletContext, "PortletContext must not be null"); + this.portletContext = portletContext; + } + + + public Object get(String name, ObjectFactory objectFactory) { + Object scopedObject = this.portletContext.getAttribute(name); + if (scopedObject == null) { + scopedObject = objectFactory.getObject(); + this.portletContext.setAttribute(name, scopedObject); + } + return scopedObject; + } + + public Object remove(String name) { + Object scopedObject = this.portletContext.getAttribute(name); + if (scopedObject != null) { + this.portletContext.removeAttribute(name); + this.destructionCallbacks.remove(name); + return scopedObject; + } + else { + return null; + } + } + + public void registerDestructionCallback(String name, Runnable callback) { + this.destructionCallbacks.put(name, callback); + } + + public Object resolveContextualObject(String key) { + return null; + } + + public String getConversationId() { + return null; + } + + + /** + * Invoke all registered destruction callbacks. + * To be called on ServletContext shutdown. + * @see org.springframework.web.context.ContextCleanupListener + */ + public void destroy() { + for (Runnable runnable : this.destructionCallbacks.values()) { + runnable.run(); + } + this.destructionCallbacks.clear(); + } + +} diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/PortletModeParameterLookupKey.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/PortletModeParameterLookupKey.java index c527368077..dd47407172 100644 --- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/PortletModeParameterLookupKey.java +++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/handler/PortletModeParameterLookupKey.java @@ -1,64 +1,64 @@ -/* - * 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.handler; - -import javax.portlet.PortletMode; - -import org.springframework.util.ObjectUtils; - -/** - * Internal class used as lookup key, combining PortletMode and parameter value. - * - * @author Juergen Hoeller - */ -class PortletModeParameterLookupKey { - - private final PortletMode mode; - - private final String parameter; - - - public PortletModeParameterLookupKey(PortletMode portletMode, String parameter) { - this.mode = portletMode; - this.parameter = parameter; - } - - - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - if (!(other instanceof PortletModeParameterLookupKey)) { - return false; - } - PortletModeParameterLookupKey otherKey = (PortletModeParameterLookupKey) other; - return (this.mode.equals(otherKey.mode) && - ObjectUtils.nullSafeEquals(this.parameter, otherKey.parameter)); - } - - @Override - public int hashCode() { - return (this.mode.hashCode() * 29 + ObjectUtils.nullSafeHashCode(this.parameter)); - } - - @Override - public String toString() { - return "Portlet mode '" + this.mode + "', parameter '" + this.parameter + "'"; - } - -} +/* + * 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.handler; + +import javax.portlet.PortletMode; + +import org.springframework.util.ObjectUtils; + +/** + * Internal class used as lookup key, combining PortletMode and parameter value. + * + * @author Juergen Hoeller + */ +class PortletModeParameterLookupKey { + + private final PortletMode mode; + + private final String parameter; + + + public PortletModeParameterLookupKey(PortletMode portletMode, String parameter) { + this.mode = portletMode; + this.parameter = parameter; + } + + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof PortletModeParameterLookupKey)) { + return false; + } + PortletModeParameterLookupKey otherKey = (PortletModeParameterLookupKey) other; + return (this.mode.equals(otherKey.mode) && + ObjectUtils.nullSafeEquals(this.parameter, otherKey.parameter)); + } + + @Override + public int hashCode() { + return (this.mode.hashCode() * 29 + ObjectUtils.nullSafeHashCode(this.parameter)); + } + + @Override + public String toString() { + return "Portlet mode '" + this.mode + "', parameter '" + this.parameter + "'"; + } + +} diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/EventAwareController.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/EventAwareController.java index fd692733e2..bd2519ea22 100644 --- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/EventAwareController.java +++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/EventAwareController.java @@ -1,43 +1,43 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.portlet.mvc; - -import javax.portlet.EventRequest; -import javax.portlet.EventResponse; - -/** - * Extension of the Portlet {@link Controller} interface that allows - * for handling Portlet 2.0 event requests as well. Can also be - * implemented by {@link AbstractController} subclasses. - * - * @author Juergen Hoeller - * @since 3.0 - * @see javax.portlet.EventPortlet - * @see Controller - * @see ResourceAwareController - */ -public interface EventAwareController { - - /** - * Process the event request. There is nothing to return. - * @param request current portlet event request - * @param response current portlet event response - * @throws Exception in case of errors - */ - void handleEventRequest(EventRequest request, EventResponse response) throws Exception; - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.mvc; + +import javax.portlet.EventRequest; +import javax.portlet.EventResponse; + +/** + * Extension of the Portlet {@link Controller} interface that allows + * for handling Portlet 2.0 event requests as well. Can also be + * implemented by {@link AbstractController} subclasses. + * + * @author Juergen Hoeller + * @since 3.0 + * @see javax.portlet.EventPortlet + * @see Controller + * @see ResourceAwareController + */ +public interface EventAwareController { + + /** + * Process the event request. There is nothing to return. + * @param request current portlet event request + * @param response current portlet event response + * @throws Exception in case of errors + */ + void handleEventRequest(EventRequest request, EventResponse response) throws Exception; + +} diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/ResourceAwareController.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/ResourceAwareController.java index 24ad45d76b..dc35b897be 100644 --- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/ResourceAwareController.java +++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/ResourceAwareController.java @@ -1,48 +1,48 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.portlet.mvc; - -import javax.portlet.ResourceRequest; -import javax.portlet.ResourceResponse; - -import org.springframework.web.portlet.ModelAndView; - -/** - * Extension of the Portlet {@link Controller} interface that allows - * for handling Portlet 2.0 resource requests as well. Can also be - * implemented by {@link AbstractController} subclasses. - * - * @author Juergen Hoeller - * @since 3.0 - * @see javax.portlet.ResourceServingPortlet - * @see Controller - * @see EventAwareController - */ -public interface ResourceAwareController { - - /** - * Process the resource request and return a ModelAndView object which the DispatcherPortlet - * will render. A null return value is not an error: It indicates that this - * object completed request processing itself, thus there is no ModelAndView to render. - * @param request current portlet resource request - * @param response current portlet resource response - * @return a ModelAndView to render, or null if handled directly - * @throws Exception in case of errors - */ - ModelAndView handleResourceRequest(ResourceRequest request, ResourceResponse response) throws Exception; - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.mvc; + +import javax.portlet.ResourceRequest; +import javax.portlet.ResourceResponse; + +import org.springframework.web.portlet.ModelAndView; + +/** + * Extension of the Portlet {@link Controller} interface that allows + * for handling Portlet 2.0 resource requests as well. Can also be + * implemented by {@link AbstractController} subclasses. + * + * @author Juergen Hoeller + * @since 3.0 + * @see javax.portlet.ResourceServingPortlet + * @see Controller + * @see EventAwareController + */ +public interface ResourceAwareController { + + /** + * Process the resource request and return a ModelAndView object which the DispatcherPortlet + * will render. A null return value is not an error: It indicates that this + * object completed request processing itself, thus there is no ModelAndView to render. + * @param request current portlet resource request + * @param response current portlet resource response + * @return a ModelAndView to render, or null if handled directly + * @throws Exception in case of errors + */ + ModelAndView handleResourceRequest(ResourceRequest request, ResourceResponse response) throws Exception; + +} diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockCacheControl.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockCacheControl.java index 45dcae7d5e..0ee9fbeb7c 100644 --- a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockCacheControl.java +++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockCacheControl.java @@ -1,70 +1,70 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web.portlet; - -import javax.portlet.CacheControl; - -/** - * Mock implementation of the {@link javax.portlet.CacheControl} interface. - * - * @author Juergen Hoeller - * @since 3.0 - */ -public class MockCacheControl implements CacheControl { - - private int expirationTime = 0; - - private boolean publicScope = false; - - private String etag; - - private boolean useCachedContent = false; - - - public int getExpirationTime() { - return this.expirationTime; - } - - public void setExpirationTime(int time) { - this.expirationTime = time; - } - - public boolean isPublicScope() { - return this.publicScope; - } - - public void setPublicScope(boolean publicScope) { - this.publicScope = publicScope; - } - - public String getETag() { - return this.etag; - } - - public void setETag(String token) { - this.etag = token; - } - - public boolean useCachedContent() { - return this.useCachedContent; - } - - public void setUseCachedContent(boolean useCachedContent) { - this.useCachedContent = useCachedContent; - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web.portlet; + +import javax.portlet.CacheControl; + +/** + * Mock implementation of the {@link javax.portlet.CacheControl} interface. + * + * @author Juergen Hoeller + * @since 3.0 + */ +public class MockCacheControl implements CacheControl { + + private int expirationTime = 0; + + private boolean publicScope = false; + + private String etag; + + private boolean useCachedContent = false; + + + public int getExpirationTime() { + return this.expirationTime; + } + + public void setExpirationTime(int time) { + this.expirationTime = time; + } + + public boolean isPublicScope() { + return this.publicScope; + } + + public void setPublicScope(boolean publicScope) { + this.publicScope = publicScope; + } + + public String getETag() { + return this.etag; + } + + public void setETag(String token) { + this.etag = token; + } + + public boolean useCachedContent() { + return this.useCachedContent; + } + + public void setUseCachedContent(boolean useCachedContent) { + this.useCachedContent = useCachedContent; + } + +} diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockEvent.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockEvent.java index b58aced0ba..0dc7efaba8 100644 --- a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockEvent.java +++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/MockEvent.java @@ -1,88 +1,88 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web.portlet; - -import java.io.Serializable; -import javax.portlet.Event; -import javax.xml.namespace.QName; - -/** - * Mock implementation of the {@link javax.portlet.Event} interface. - * - * @author Juergen Hoeller - * @since 3.0 - * @see MockEventRequest - */ -public class MockEvent implements Event { - - private final QName name; - - private final Serializable value; - - - /** - * Create a new MockEvent with the given name. - * @param name the name of the event - */ - public MockEvent(QName name) { - this.name = name; - this.value = null; - } - - /** - * Create a new MockEvent with the given name and value. - * @param name the name of the event - * @param value the associated payload of the event - */ - public MockEvent(QName name, Serializable value) { - this.name = name; - this.value = value; - } - - /** - * Create a new MockEvent with the given name. - * @param name the name of the event - */ - public MockEvent(String name) { - this.name = new QName(name); - this.value = null; - } - - /** - * Create a new MockEvent with the given name and value. - * @param name the name of the event - * @param value the associated payload of the event - */ - public MockEvent(String name, Serializable value) { - this.name = new QName(name); - this.value = value; - } - - - public QName getQName() { - return this.name; - } - - public String getName() { - return this.name.getLocalPart(); - } - - public Serializable getValue() { - return this.value; - } - +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web.portlet; + +import java.io.Serializable; +import javax.portlet.Event; +import javax.xml.namespace.QName; + +/** + * Mock implementation of the {@link javax.portlet.Event} interface. + * + * @author Juergen Hoeller + * @since 3.0 + * @see MockEventRequest + */ +public class MockEvent implements Event { + + private final QName name; + + private final Serializable value; + + + /** + * Create a new MockEvent with the given name. + * @param name the name of the event + */ + public MockEvent(QName name) { + this.name = name; + this.value = null; + } + + /** + * Create a new MockEvent with the given name and value. + * @param name the name of the event + * @param value the associated payload of the event + */ + public MockEvent(QName name, Serializable value) { + this.name = name; + this.value = value; + } + + /** + * Create a new MockEvent with the given name. + * @param name the name of the event + */ + public MockEvent(String name) { + this.name = new QName(name); + this.value = null; + } + + /** + * Create a new MockEvent with the given name and value. + * @param name the name of the event + * @param value the associated payload of the event + */ + public MockEvent(String name, Serializable value) { + this.name = new QName(name); + this.value = value; + } + + + public QName getQName() { + return this.name; + } + + public String getName() { + return this.name.getLocalPart(); + } + + public Serializable getValue() { + return this.value; + } + } \ No newline at end of file diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/ServletWrappingPortletContext.java b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/ServletWrappingPortletContext.java index d796d3ea45..a333984f48 100644 --- a/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/ServletWrappingPortletContext.java +++ b/org.springframework.web.portlet/src/test/java/org/springframework/mock/web/portlet/ServletWrappingPortletContext.java @@ -1,145 +1,145 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web.portlet; - -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Set; -import javax.portlet.PortletContext; -import javax.portlet.PortletRequestDispatcher; -import javax.servlet.ServletContext; - -import org.springframework.util.Assert; - -/** - * Mock implementation of the {@link javax.portlet.PortletContext} interface, - * wrapping an underlying {@link javax.servlet.ServletContext}. - * - * @author Juergen Hoeller - * @since 3.0 - * @see org.springframework.mock.web.portlet.MockPortletContext - */ -public class ServletWrappingPortletContext implements PortletContext { - - private final ServletContext servletContext; - - - /** - * Create a new PortletContext wrapping the given ServletContext. - * @param servletContext the ServletContext to wrap - */ - public ServletWrappingPortletContext(ServletContext servletContext) { - Assert.notNull(servletContext, "ServletContext must not be null"); - this.servletContext = servletContext; - } - - /** - * Return the underlying ServletContext that this PortletContext wraps. - */ - public final ServletContext getServletContext() { - return this.servletContext; - } - - - public String getServerInfo() { - return this.servletContext.getServerInfo(); - } - - public PortletRequestDispatcher getRequestDispatcher(String path) { - return null; - } - - public PortletRequestDispatcher getNamedDispatcher(String name) { - return null; - } - - public InputStream getResourceAsStream(String path) { - return this.servletContext.getResourceAsStream(path); - } - - public int getMajorVersion() { - return 2; - } - - public int getMinorVersion() { - return 0; - } - - public String getMimeType(String file) { - return this.servletContext.getMimeType(file); - } - - public String getRealPath(String path) { - return this.servletContext.getRealPath(path); - } - - @SuppressWarnings("unchecked") - public Set getResourcePaths(String path) { - return this.servletContext.getResourcePaths(path); - } - - public URL getResource(String path) throws MalformedURLException { - return this.servletContext.getResource(path); - } - - public Object getAttribute(String name) { - return this.servletContext.getAttribute(name); - } - - @SuppressWarnings("unchecked") - public Enumeration getAttributeNames() { - return this.servletContext.getAttributeNames(); - } - - public String getInitParameter(String name) { - return this.servletContext.getInitParameter(name); - } - - @SuppressWarnings("unchecked") - public Enumeration getInitParameterNames() { - return this.servletContext.getInitParameterNames(); - } - - public void log(String msg) { - this.servletContext.log(msg); - } - - public void log(String message, Throwable throwable) { - this.servletContext.log(message, throwable); - } - - public void removeAttribute(String name) { - this.servletContext.removeAttribute(name); - } - - public void setAttribute(String name, Object object) { - this.servletContext.setAttribute(name, object); - } - - public String getPortletContextName() { - return this.servletContext.getServletContextName(); - } - - public Enumeration getContainerRuntimeOptions() { - return Collections.enumeration(new HashSet()); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web.portlet; + +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Set; +import javax.portlet.PortletContext; +import javax.portlet.PortletRequestDispatcher; +import javax.servlet.ServletContext; + +import org.springframework.util.Assert; + +/** + * Mock implementation of the {@link javax.portlet.PortletContext} interface, + * wrapping an underlying {@link javax.servlet.ServletContext}. + * + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.mock.web.portlet.MockPortletContext + */ +public class ServletWrappingPortletContext implements PortletContext { + + private final ServletContext servletContext; + + + /** + * Create a new PortletContext wrapping the given ServletContext. + * @param servletContext the ServletContext to wrap + */ + public ServletWrappingPortletContext(ServletContext servletContext) { + Assert.notNull(servletContext, "ServletContext must not be null"); + this.servletContext = servletContext; + } + + /** + * Return the underlying ServletContext that this PortletContext wraps. + */ + public final ServletContext getServletContext() { + return this.servletContext; + } + + + public String getServerInfo() { + return this.servletContext.getServerInfo(); + } + + public PortletRequestDispatcher getRequestDispatcher(String path) { + return null; + } + + public PortletRequestDispatcher getNamedDispatcher(String name) { + return null; + } + + public InputStream getResourceAsStream(String path) { + return this.servletContext.getResourceAsStream(path); + } + + public int getMajorVersion() { + return 2; + } + + public int getMinorVersion() { + return 0; + } + + public String getMimeType(String file) { + return this.servletContext.getMimeType(file); + } + + public String getRealPath(String path) { + return this.servletContext.getRealPath(path); + } + + @SuppressWarnings("unchecked") + public Set getResourcePaths(String path) { + return this.servletContext.getResourcePaths(path); + } + + public URL getResource(String path) throws MalformedURLException { + return this.servletContext.getResource(path); + } + + public Object getAttribute(String name) { + return this.servletContext.getAttribute(name); + } + + @SuppressWarnings("unchecked") + public Enumeration getAttributeNames() { + return this.servletContext.getAttributeNames(); + } + + public String getInitParameter(String name) { + return this.servletContext.getInitParameter(name); + } + + @SuppressWarnings("unchecked") + public Enumeration getInitParameterNames() { + return this.servletContext.getInitParameterNames(); + } + + public void log(String msg) { + this.servletContext.log(msg); + } + + public void log(String message, Throwable throwable) { + this.servletContext.log(message, throwable); + } + + public void removeAttribute(String name) { + this.servletContext.removeAttribute(name); + } + + public void setAttribute(String name, Object object) { + this.servletContext.setAttribute(name, object); + } + + public String getPortletContextName() { + return this.servletContext.getServletContextName(); + } + + public Enumeration getContainerRuntimeOptions() { + return Collections.enumeration(new HashSet()); + } + +} diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/context/PortletApplicationContextScopeTests.java b/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/context/PortletApplicationContextScopeTests.java index 64201e768a..452ddb3c52 100644 --- a/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/context/PortletApplicationContextScopeTests.java +++ b/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/context/PortletApplicationContextScopeTests.java @@ -1,128 +1,128 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.portlet.context; - -import javax.portlet.PortletContext; -import javax.portlet.PortletSession; -import javax.servlet.ServletContextEvent; - -import static org.junit.Assert.*; -import org.junit.Test; - -import org.springframework.beans.DerivedTestBean; -import org.springframework.beans.factory.support.GenericBeanDefinition; -import org.springframework.mock.web.MockServletContext; -import org.springframework.mock.web.portlet.MockRenderRequest; -import org.springframework.mock.web.portlet.ServletWrappingPortletContext; -import org.springframework.web.context.ContextCleanupListener; -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.support.GenericWebApplicationContext; - -/** - * @author Juergen Hoeller - */ -public class PortletApplicationContextScopeTests { - - private static final String NAME = "scoped"; - - - private ConfigurablePortletApplicationContext initApplicationContext(String scope) { - MockServletContext sc = new MockServletContext(); - GenericWebApplicationContext rac = new GenericWebApplicationContext(sc); - rac.refresh(); - PortletContext pc = new ServletWrappingPortletContext(sc); - StaticPortletApplicationContext ac = new StaticPortletApplicationContext(); - ac.setParent(rac); - ac.setPortletContext(pc); - GenericBeanDefinition bd = new GenericBeanDefinition(); - bd.setBeanClass(DerivedTestBean.class); - bd.setScope(scope); - ac.registerBeanDefinition(NAME, bd); - ac.refresh(); - return ac; - } - - @Test - public void testRequestScope() { - WebApplicationContext ac = initApplicationContext(WebApplicationContext.SCOPE_REQUEST); - MockRenderRequest request = new MockRenderRequest(); - PortletRequestAttributes requestAttributes = new PortletRequestAttributes(request); - RequestContextHolder.setRequestAttributes(requestAttributes); - try { - assertNull(request.getAttribute(NAME)); - DerivedTestBean bean = ac.getBean(NAME, DerivedTestBean.class); - assertSame(bean, request.getAttribute(NAME)); - assertSame(bean, ac.getBean(NAME)); - requestAttributes.requestCompleted(); - assertTrue(bean.wasDestroyed()); - } - finally { - RequestContextHolder.setRequestAttributes(null); - } - } - - @Test - public void testSessionScope() { - WebApplicationContext ac = initApplicationContext(WebApplicationContext.SCOPE_SESSION); - MockRenderRequest request = new MockRenderRequest(); - PortletRequestAttributes requestAttributes = new PortletRequestAttributes(request); - RequestContextHolder.setRequestAttributes(requestAttributes); - try { - assertNull(request.getPortletSession().getAttribute(NAME)); - DerivedTestBean bean = ac.getBean(NAME, DerivedTestBean.class); - assertSame(bean, request.getPortletSession().getAttribute(NAME)); - assertSame(bean, ac.getBean(NAME)); - request.getPortletSession().invalidate(); - assertTrue(bean.wasDestroyed()); - } - finally { - RequestContextHolder.setRequestAttributes(null); - } - } - - @Test - public void testGlobalSessionScope() { - WebApplicationContext ac = initApplicationContext(WebApplicationContext.SCOPE_GLOBAL_SESSION); - MockRenderRequest request = new MockRenderRequest(); - PortletRequestAttributes requestAttributes = new PortletRequestAttributes(request); - RequestContextHolder.setRequestAttributes(requestAttributes); - try { - assertNull(request.getPortletSession().getAttribute(NAME, PortletSession.APPLICATION_SCOPE)); - DerivedTestBean bean = ac.getBean(NAME, DerivedTestBean.class); - assertSame(bean, request.getPortletSession().getAttribute(NAME, PortletSession.APPLICATION_SCOPE)); - assertSame(bean, ac.getBean(NAME)); - request.getPortletSession().invalidate(); - assertTrue(bean.wasDestroyed()); - } - finally { - RequestContextHolder.setRequestAttributes(null); - } - } - - @Test - public void testApplicationScope() { - ConfigurablePortletApplicationContext ac = initApplicationContext(WebApplicationContext.SCOPE_APPLICATION); - assertNull(ac.getPortletContext().getAttribute(NAME)); - DerivedTestBean bean = ac.getBean(NAME, DerivedTestBean.class); - assertSame(bean, ac.getPortletContext().getAttribute(NAME)); - assertSame(bean, ac.getBean(NAME)); - new ContextCleanupListener().contextDestroyed(new ServletContextEvent(ac.getServletContext())); - assertTrue(bean.wasDestroyed()); - } - +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.portlet.context; + +import javax.portlet.PortletContext; +import javax.portlet.PortletSession; +import javax.servlet.ServletContextEvent; + +import static org.junit.Assert.*; +import org.junit.Test; + +import org.springframework.beans.DerivedTestBean; +import org.springframework.beans.factory.support.GenericBeanDefinition; +import org.springframework.mock.web.MockServletContext; +import org.springframework.mock.web.portlet.MockRenderRequest; +import org.springframework.mock.web.portlet.ServletWrappingPortletContext; +import org.springframework.web.context.ContextCleanupListener; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.support.GenericWebApplicationContext; + +/** + * @author Juergen Hoeller + */ +public class PortletApplicationContextScopeTests { + + private static final String NAME = "scoped"; + + + private ConfigurablePortletApplicationContext initApplicationContext(String scope) { + MockServletContext sc = new MockServletContext(); + GenericWebApplicationContext rac = new GenericWebApplicationContext(sc); + rac.refresh(); + PortletContext pc = new ServletWrappingPortletContext(sc); + StaticPortletApplicationContext ac = new StaticPortletApplicationContext(); + ac.setParent(rac); + ac.setPortletContext(pc); + GenericBeanDefinition bd = new GenericBeanDefinition(); + bd.setBeanClass(DerivedTestBean.class); + bd.setScope(scope); + ac.registerBeanDefinition(NAME, bd); + ac.refresh(); + return ac; + } + + @Test + public void testRequestScope() { + WebApplicationContext ac = initApplicationContext(WebApplicationContext.SCOPE_REQUEST); + MockRenderRequest request = new MockRenderRequest(); + PortletRequestAttributes requestAttributes = new PortletRequestAttributes(request); + RequestContextHolder.setRequestAttributes(requestAttributes); + try { + assertNull(request.getAttribute(NAME)); + DerivedTestBean bean = ac.getBean(NAME, DerivedTestBean.class); + assertSame(bean, request.getAttribute(NAME)); + assertSame(bean, ac.getBean(NAME)); + requestAttributes.requestCompleted(); + assertTrue(bean.wasDestroyed()); + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + } + + @Test + public void testSessionScope() { + WebApplicationContext ac = initApplicationContext(WebApplicationContext.SCOPE_SESSION); + MockRenderRequest request = new MockRenderRequest(); + PortletRequestAttributes requestAttributes = new PortletRequestAttributes(request); + RequestContextHolder.setRequestAttributes(requestAttributes); + try { + assertNull(request.getPortletSession().getAttribute(NAME)); + DerivedTestBean bean = ac.getBean(NAME, DerivedTestBean.class); + assertSame(bean, request.getPortletSession().getAttribute(NAME)); + assertSame(bean, ac.getBean(NAME)); + request.getPortletSession().invalidate(); + assertTrue(bean.wasDestroyed()); + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + } + + @Test + public void testGlobalSessionScope() { + WebApplicationContext ac = initApplicationContext(WebApplicationContext.SCOPE_GLOBAL_SESSION); + MockRenderRequest request = new MockRenderRequest(); + PortletRequestAttributes requestAttributes = new PortletRequestAttributes(request); + RequestContextHolder.setRequestAttributes(requestAttributes); + try { + assertNull(request.getPortletSession().getAttribute(NAME, PortletSession.APPLICATION_SCOPE)); + DerivedTestBean bean = ac.getBean(NAME, DerivedTestBean.class); + assertSame(bean, request.getPortletSession().getAttribute(NAME, PortletSession.APPLICATION_SCOPE)); + assertSame(bean, ac.getBean(NAME)); + request.getPortletSession().invalidate(); + assertTrue(bean.wasDestroyed()); + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + } + + @Test + public void testApplicationScope() { + ConfigurablePortletApplicationContext ac = initApplicationContext(WebApplicationContext.SCOPE_APPLICATION); + assertNull(ac.getPortletContext().getAttribute(NAME)); + DerivedTestBean bean = ac.getBean(NAME, DerivedTestBean.class); + assertSame(bean, ac.getPortletContext().getAttribute(NAME)); + assertSame(bean, ac.getBean(NAME)); + new ContextCleanupListener().contextDestroyed(new ServletContextEvent(ac.getServletContext())); + assertTrue(bean.wasDestroyed()); + } + } \ No newline at end of file diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/package-info.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/package-info.java index 1bd6310988..b318bed079 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/package-info.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/package-info.java @@ -1,8 +1,8 @@ - -/** - * - * Common MVC logic for matching incoming requests based on conditions. - * - */ -package org.springframework.web.servlet.mvc.condition; - + +/** + * + * Common MVC logic for matching incoming requests based on conditions. + * + */ +package org.springframework.web.servlet.mvc.condition; + diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/package-info.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/package-info.java index 32a80b0471..ead0f5afed 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/package-info.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/package-info.java @@ -1,10 +1,10 @@ - -/** - * - * MVC infrastructure for annotation-based handler method processing, - * building on the org.springframework.web.method.annotation package. - * Entry points are {@link RequestMappingHandlerMapping} and {@link RequestMappingHandlerAdapter}. - * - */ -package org.springframework.web.servlet.mvc.method.annotation; - + +/** + * + * MVC infrastructure for annotation-based handler method processing, + * building on the org.springframework.web.method.annotation package. + * Entry points are {@link RequestMappingHandlerMapping} and {@link RequestMappingHandlerAdapter}. + * + */ +package org.springframework.web.servlet.mvc.method.annotation; + diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/package-info.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/package-info.java index abeebd1039..039fcb7b35 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/package-info.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/package-info.java @@ -1,9 +1,9 @@ - -/** - * - * Servlet-based infrastructure for handler method processing, - * building on the org.springframework.web.method package. - * - */ -package org.springframework.web.servlet.mvc.method; - + +/** + * + * Servlet-based infrastructure for handler method processing, + * building on the org.springframework.web.method package. + * + */ +package org.springframework.web.servlet.mvc.method; + diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/tiles2/SpringTilesApplicationContextFactory.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/tiles2/SpringTilesApplicationContextFactory.java index db630ce561..da6383a734 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/tiles2/SpringTilesApplicationContextFactory.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/tiles2/SpringTilesApplicationContextFactory.java @@ -1,112 +1,112 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.servlet.view.tiles2; - -import java.io.IOException; -import java.net.URL; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; -import javax.servlet.ServletContext; - -import org.apache.tiles.Initializable; -import org.apache.tiles.TilesApplicationContext; -import org.apache.tiles.context.AbstractTilesApplicationContextFactory; -import org.apache.tiles.servlet.context.ServletTilesApplicationContext; - -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.ResourcePatternResolver; -import org.springframework.web.context.support.ServletContextResourcePatternResolver; - -/** - * Spring-specific subclass of the standard Tiles AbstractTilesApplicationContextFactory, - * passing given properties through as Tiles init-param map. - * - * @author Juergen Hoeller - * @since 3.0 - * @see TilesConfigurer#setTilesProperties - */ -public class SpringTilesApplicationContextFactory extends AbstractTilesApplicationContextFactory - implements Initializable { - - private Map params; - - public void init(Map params) { - this.params = params; - } - - public TilesApplicationContext createApplicationContext(Object context) { - return new SpringWildcardServletTilesApplicationContext((ServletContext) context, this.params); - } - - - /** - * Custom subclass of the standard Tiles WildcardServletTilesApplicationContext, - * passing given properties through as Tiles init-param map. - */ - private static class SpringWildcardServletTilesApplicationContext extends ServletTilesApplicationContext { - - private final Map mergedInitParams; - - private final ResourcePatternResolver resolver; - - public SpringWildcardServletTilesApplicationContext(ServletContext servletContext, Map params) { - super(servletContext); - this.mergedInitParams = new LinkedHashMap(); - Enumeration initParamNames = servletContext.getInitParameterNames(); - while (initParamNames.hasMoreElements()) { - String initParamName = (String) initParamNames.nextElement(); - this.mergedInitParams.put(initParamName, servletContext.getInitParameter(initParamName)); - } - if (params != null) { - this.mergedInitParams.putAll(params); - } - this.resolver = new ServletContextResourcePatternResolver(servletContext); - } - - @Override - public Map getInitParams() { - return this.mergedInitParams; - } - - @Override - public URL getResource(String path) throws IOException { - URL retValue = null; - Set urlSet = getResources(path); - if (urlSet != null && !urlSet.isEmpty()) { - retValue = urlSet.iterator().next(); - } - return retValue; - } - - @Override - public Set getResources(String path) throws IOException { - Set urlSet = null; - Resource[] resources = this.resolver.getResources(path); - if (resources != null && resources.length > 0) { - urlSet = new HashSet(); - for (Resource resource : resources) { - urlSet.add(resource.getURL()); - } - } - return urlSet; - } - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.view.tiles2; + +import java.io.IOException; +import java.net.URL; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import javax.servlet.ServletContext; + +import org.apache.tiles.Initializable; +import org.apache.tiles.TilesApplicationContext; +import org.apache.tiles.context.AbstractTilesApplicationContextFactory; +import org.apache.tiles.servlet.context.ServletTilesApplicationContext; + +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.web.context.support.ServletContextResourcePatternResolver; + +/** + * Spring-specific subclass of the standard Tiles AbstractTilesApplicationContextFactory, + * passing given properties through as Tiles init-param map. + * + * @author Juergen Hoeller + * @since 3.0 + * @see TilesConfigurer#setTilesProperties + */ +public class SpringTilesApplicationContextFactory extends AbstractTilesApplicationContextFactory + implements Initializable { + + private Map params; + + public void init(Map params) { + this.params = params; + } + + public TilesApplicationContext createApplicationContext(Object context) { + return new SpringWildcardServletTilesApplicationContext((ServletContext) context, this.params); + } + + + /** + * Custom subclass of the standard Tiles WildcardServletTilesApplicationContext, + * passing given properties through as Tiles init-param map. + */ + private static class SpringWildcardServletTilesApplicationContext extends ServletTilesApplicationContext { + + private final Map mergedInitParams; + + private final ResourcePatternResolver resolver; + + public SpringWildcardServletTilesApplicationContext(ServletContext servletContext, Map params) { + super(servletContext); + this.mergedInitParams = new LinkedHashMap(); + Enumeration initParamNames = servletContext.getInitParameterNames(); + while (initParamNames.hasMoreElements()) { + String initParamName = (String) initParamNames.nextElement(); + this.mergedInitParams.put(initParamName, servletContext.getInitParameter(initParamName)); + } + if (params != null) { + this.mergedInitParams.putAll(params); + } + this.resolver = new ServletContextResourcePatternResolver(servletContext); + } + + @Override + public Map getInitParams() { + return this.mergedInitParams; + } + + @Override + public URL getResource(String path) throws IOException { + URL retValue = null; + Set urlSet = getResources(path); + if (urlSet != null && !urlSet.isEmpty()) { + retValue = urlSet.iterator().next(); + } + return retValue; + } + + @Override + public Set getResources(String path) throws IOException { + Set urlSet = null; + Resource[] resources = this.resolver.getResources(path); + if (resources != null && resources.length > 0) { + urlSet = new HashSet(); + for (Resource resource : resources) { + urlSet.add(resource.getURL()); + } + } + return urlSet; + } + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/DelegatingServletInputStream.java b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/DelegatingServletInputStream.java index 22dd38281e..b083e95b27 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/DelegatingServletInputStream.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/DelegatingServletInputStream.java @@ -1,66 +1,66 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import java.io.IOException; -import java.io.InputStream; -import javax.servlet.ServletInputStream; - -import org.springframework.util.Assert; - -/** - * Delegating implementation of {@link javax.servlet.ServletInputStream}. - * - *

Used by {@link MockHttpServletRequest}; typically not directly - * used for testing application controllers. - * - * @author Juergen Hoeller - * @since 1.0.2 - * @see MockHttpServletRequest - */ -public class DelegatingServletInputStream extends ServletInputStream { - - private final InputStream sourceStream; - - - /** - * Create a DelegatingServletInputStream for the given source stream. - * @param sourceStream the source stream (never null) - */ - public DelegatingServletInputStream(InputStream sourceStream) { - Assert.notNull(sourceStream, "Source InputStream must not be null"); - this.sourceStream = sourceStream; - } - - /** - * Return the underlying source stream (never null). - */ - public final InputStream getSourceStream() { - return this.sourceStream; - } - - - public int read() throws IOException { - return this.sourceStream.read(); - } - - public void close() throws IOException { - super.close(); - this.sourceStream.close(); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.io.IOException; +import java.io.InputStream; +import javax.servlet.ServletInputStream; + +import org.springframework.util.Assert; + +/** + * Delegating implementation of {@link javax.servlet.ServletInputStream}. + * + *

Used by {@link MockHttpServletRequest}; typically not directly + * used for testing application controllers. + * + * @author Juergen Hoeller + * @since 1.0.2 + * @see MockHttpServletRequest + */ +public class DelegatingServletInputStream extends ServletInputStream { + + private final InputStream sourceStream; + + + /** + * Create a DelegatingServletInputStream for the given source stream. + * @param sourceStream the source stream (never null) + */ + public DelegatingServletInputStream(InputStream sourceStream) { + Assert.notNull(sourceStream, "Source InputStream must not be null"); + this.sourceStream = sourceStream; + } + + /** + * Return the underlying source stream (never null). + */ + public final InputStream getSourceStream() { + return this.sourceStream; + } + + + public int read() throws IOException { + return this.sourceStream.read(); + } + + public void close() throws IOException { + super.close(); + this.sourceStream.close(); + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/DelegatingServletOutputStream.java b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/DelegatingServletOutputStream.java index ccf5ce3f21..edc42c2d84 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/DelegatingServletOutputStream.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/DelegatingServletOutputStream.java @@ -1,74 +1,74 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import java.io.IOException; -import java.io.OutputStream; -import javax.servlet.ServletOutputStream; - -import org.springframework.util.Assert; - -/** - * Delegating implementation of {@link javax.servlet.ServletOutputStream}. - * - *

Used by {@link MockHttpServletResponse}; typically not directly - * used for testing application controllers. - * - * @author Juergen Hoeller - * @since 1.0.2 - * @see MockHttpServletResponse - */ -public class DelegatingServletOutputStream extends ServletOutputStream { - - private final OutputStream targetStream; - - - /** - * Create a DelegatingServletOutputStream for the given target stream. - * @param targetStream the target stream (never null) - */ - public DelegatingServletOutputStream(OutputStream targetStream) { - Assert.notNull(targetStream, "Target OutputStream must not be null"); - this.targetStream = targetStream; - } - - /** - * Return the underlying target stream (never null). - */ - public final OutputStream getTargetStream() { - return this.targetStream; - } - - - @Override - public void write(int b) throws IOException { - this.targetStream.write(b); - } - - @Override - public void flush() throws IOException { - super.flush(); - this.targetStream.flush(); - } - - @Override - public void close() throws IOException { - super.close(); - this.targetStream.close(); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.io.IOException; +import java.io.OutputStream; +import javax.servlet.ServletOutputStream; + +import org.springframework.util.Assert; + +/** + * Delegating implementation of {@link javax.servlet.ServletOutputStream}. + * + *

Used by {@link MockHttpServletResponse}; typically not directly + * used for testing application controllers. + * + * @author Juergen Hoeller + * @since 1.0.2 + * @see MockHttpServletResponse + */ +public class DelegatingServletOutputStream extends ServletOutputStream { + + private final OutputStream targetStream; + + + /** + * Create a DelegatingServletOutputStream for the given target stream. + * @param targetStream the target stream (never null) + */ + public DelegatingServletOutputStream(OutputStream targetStream) { + Assert.notNull(targetStream, "Target OutputStream must not be null"); + this.targetStream = targetStream; + } + + /** + * Return the underlying target stream (never null). + */ + public final OutputStream getTargetStream() { + return this.targetStream; + } + + + @Override + public void write(int b) throws IOException { + this.targetStream.write(b); + } + + @Override + public void flush() throws IOException { + super.flush(); + this.targetStream.flush(); + } + + @Override + public void close() throws IOException { + super.close(); + this.targetStream.close(); + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/HeaderValueHolder.java b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/HeaderValueHolder.java index 48224a00d2..afe74ad8f0 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/HeaderValueHolder.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/HeaderValueHolder.java @@ -1,96 +1,96 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import org.springframework.util.Assert; -import org.springframework.util.CollectionUtils; - -/** - * Internal helper class that serves as value holder for request headers. - * - * @author Juergen Hoeller - * @author Rick Evans - * @since 2.0.1 - */ -class HeaderValueHolder { - - private final List values = new LinkedList(); - - - public void setValue(Object value) { - this.values.clear(); - this.values.add(value); - } - - public void addValue(Object value) { - this.values.add(value); - } - - public void addValues(Collection values) { - this.values.addAll(values); - } - - public void addValueArray(Object values) { - CollectionUtils.mergeArrayIntoCollection(values, this.values); - } - - public List getValues() { - return Collections.unmodifiableList(this.values); - } - - public List getStringValues() { - List stringList = new ArrayList(this.values.size()); - for (Object value : this.values) { - stringList.add(value.toString()); - } - return Collections.unmodifiableList(stringList); - } - - public Object getValue() { - return (!this.values.isEmpty() ? this.values.get(0) : null); - } - - public String getStringValue() { - return (!this.values.isEmpty() ? this.values.get(0).toString() : null); - } - - - /** - * Find a HeaderValueHolder by name, ignoring casing. - * @param headers the Map of header names to HeaderValueHolders - * @param name the name of the desired header - * @return the corresponding HeaderValueHolder, - * or null if none found - */ - public static HeaderValueHolder getByName(Map headers, String name) { - Assert.notNull(name, "Header name must not be null"); - for (String headerName : headers.keySet()) { - if (headerName.equalsIgnoreCase(name)) { - return headers.get(headerName); - } - } - return null; - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +/** + * Internal helper class that serves as value holder for request headers. + * + * @author Juergen Hoeller + * @author Rick Evans + * @since 2.0.1 + */ +class HeaderValueHolder { + + private final List values = new LinkedList(); + + + public void setValue(Object value) { + this.values.clear(); + this.values.add(value); + } + + public void addValue(Object value) { + this.values.add(value); + } + + public void addValues(Collection values) { + this.values.addAll(values); + } + + public void addValueArray(Object values) { + CollectionUtils.mergeArrayIntoCollection(values, this.values); + } + + public List getValues() { + return Collections.unmodifiableList(this.values); + } + + public List getStringValues() { + List stringList = new ArrayList(this.values.size()); + for (Object value : this.values) { + stringList.add(value.toString()); + } + return Collections.unmodifiableList(stringList); + } + + public Object getValue() { + return (!this.values.isEmpty() ? this.values.get(0) : null); + } + + public String getStringValue() { + return (!this.values.isEmpty() ? this.values.get(0).toString() : null); + } + + + /** + * Find a HeaderValueHolder by name, ignoring casing. + * @param headers the Map of header names to HeaderValueHolders + * @param name the name of the desired header + * @return the corresponding HeaderValueHolder, + * or null if none found + */ + public static HeaderValueHolder getByName(Map headers, String name) { + Assert.notNull(name, "Header name must not be null"); + for (String headerName : headers.keySet()) { + if (headerName.equalsIgnoreCase(name)) { + return headers.get(headerName); + } + } + return null; + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockBodyContent.java b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockBodyContent.java index 25b6fae60b..3fb6ca7703 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockBodyContent.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockBodyContent.java @@ -1,197 +1,197 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import java.io.IOException; -import java.io.Reader; -import java.io.StringReader; -import java.io.Writer; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.jsp.JspWriter; -import javax.servlet.jsp.tagext.BodyContent; - -/** - * Mock implementation of the {@link javax.servlet.jsp.tagext.BodyContent} class. - * - *

Used for testing the web framework; only necessary for testing - * applications when testing custom JSP tags. - * - * @author Juergen Hoeller - * @since 2.5 - */ -public class MockBodyContent extends BodyContent { - - private final String content; - - - /** - * Create a MockBodyContent for the given response. - * @param content the body content to expose - * @param response the servlet response to wrap - */ - public MockBodyContent(String content, HttpServletResponse response) { - this(content, response, null); - } - - /** - * Create a MockBodyContent for the given response. - * @param content the body content to expose - * @param targetWriter the target Writer to wrap - */ - public MockBodyContent(String content, Writer targetWriter) { - this(content, null, targetWriter); - } - - /** - * Create a MockBodyContent for the given response. - * @param content the body content to expose - * @param response the servlet response to wrap - * @param targetWriter the target Writer to wrap - */ - public MockBodyContent(String content, HttpServletResponse response, Writer targetWriter) { - super(adaptJspWriter(targetWriter, response)); - this.content = content; - } - - private static JspWriter adaptJspWriter(Writer targetWriter, HttpServletResponse response) { - if (targetWriter instanceof JspWriter) { - return (JspWriter) targetWriter; - } - else { - return new MockJspWriter(response, targetWriter); - } - } - - - public Reader getReader() { - return new StringReader(this.content); - } - - public String getString() { - return this.content; - } - - public void writeOut(Writer writer) throws IOException { - writer.write(this.content); - } - - - //--------------------------------------------------------------------- - // Delegating implementations of JspWriter's abstract methods - //--------------------------------------------------------------------- - - public void clear() throws IOException { - getEnclosingWriter().clear(); - } - - public void clearBuffer() throws IOException { - getEnclosingWriter().clearBuffer(); - } - - public void close() throws IOException { - getEnclosingWriter().close(); - } - - public int getRemaining() { - return getEnclosingWriter().getRemaining(); - } - - public void newLine() throws IOException { - getEnclosingWriter().println(); - } - - public void write(char value[], int offset, int length) throws IOException { - getEnclosingWriter().write(value, offset, length); - } - - public void print(boolean value) throws IOException { - getEnclosingWriter().print(value); - } - - public void print(char value) throws IOException { - getEnclosingWriter().print(value); - } - - public void print(char[] value) throws IOException { - getEnclosingWriter().print(value); - } - - public void print(double value) throws IOException { - getEnclosingWriter().print(value); - } - - public void print(float value) throws IOException { - getEnclosingWriter().print(value); - } - - public void print(int value) throws IOException { - getEnclosingWriter().print(value); - } - - public void print(long value) throws IOException { - getEnclosingWriter().print(value); - } - - public void print(Object value) throws IOException { - getEnclosingWriter().print(value); - } - - public void print(String value) throws IOException { - getEnclosingWriter().print(value); - } - - public void println() throws IOException { - getEnclosingWriter().println(); - } - - public void println(boolean value) throws IOException { - getEnclosingWriter().println(value); - } - - public void println(char value) throws IOException { - getEnclosingWriter().println(value); - } - - public void println(char[] value) throws IOException { - getEnclosingWriter().println(value); - } - - public void println(double value) throws IOException { - getEnclosingWriter().println(value); - } - - public void println(float value) throws IOException { - getEnclosingWriter().println(value); - } - - public void println(int value) throws IOException { - getEnclosingWriter().println(value); - } - - public void println(long value) throws IOException { - getEnclosingWriter().println(value); - } - - public void println(Object value) throws IOException { - getEnclosingWriter().println(value); - } - - public void println(String value) throws IOException { - getEnclosingWriter().println(value); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.io.Writer; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.jsp.JspWriter; +import javax.servlet.jsp.tagext.BodyContent; + +/** + * Mock implementation of the {@link javax.servlet.jsp.tagext.BodyContent} class. + * + *

Used for testing the web framework; only necessary for testing + * applications when testing custom JSP tags. + * + * @author Juergen Hoeller + * @since 2.5 + */ +public class MockBodyContent extends BodyContent { + + private final String content; + + + /** + * Create a MockBodyContent for the given response. + * @param content the body content to expose + * @param response the servlet response to wrap + */ + public MockBodyContent(String content, HttpServletResponse response) { + this(content, response, null); + } + + /** + * Create a MockBodyContent for the given response. + * @param content the body content to expose + * @param targetWriter the target Writer to wrap + */ + public MockBodyContent(String content, Writer targetWriter) { + this(content, null, targetWriter); + } + + /** + * Create a MockBodyContent for the given response. + * @param content the body content to expose + * @param response the servlet response to wrap + * @param targetWriter the target Writer to wrap + */ + public MockBodyContent(String content, HttpServletResponse response, Writer targetWriter) { + super(adaptJspWriter(targetWriter, response)); + this.content = content; + } + + private static JspWriter adaptJspWriter(Writer targetWriter, HttpServletResponse response) { + if (targetWriter instanceof JspWriter) { + return (JspWriter) targetWriter; + } + else { + return new MockJspWriter(response, targetWriter); + } + } + + + public Reader getReader() { + return new StringReader(this.content); + } + + public String getString() { + return this.content; + } + + public void writeOut(Writer writer) throws IOException { + writer.write(this.content); + } + + + //--------------------------------------------------------------------- + // Delegating implementations of JspWriter's abstract methods + //--------------------------------------------------------------------- + + public void clear() throws IOException { + getEnclosingWriter().clear(); + } + + public void clearBuffer() throws IOException { + getEnclosingWriter().clearBuffer(); + } + + public void close() throws IOException { + getEnclosingWriter().close(); + } + + public int getRemaining() { + return getEnclosingWriter().getRemaining(); + } + + public void newLine() throws IOException { + getEnclosingWriter().println(); + } + + public void write(char value[], int offset, int length) throws IOException { + getEnclosingWriter().write(value, offset, length); + } + + public void print(boolean value) throws IOException { + getEnclosingWriter().print(value); + } + + public void print(char value) throws IOException { + getEnclosingWriter().print(value); + } + + public void print(char[] value) throws IOException { + getEnclosingWriter().print(value); + } + + public void print(double value) throws IOException { + getEnclosingWriter().print(value); + } + + public void print(float value) throws IOException { + getEnclosingWriter().print(value); + } + + public void print(int value) throws IOException { + getEnclosingWriter().print(value); + } + + public void print(long value) throws IOException { + getEnclosingWriter().print(value); + } + + public void print(Object value) throws IOException { + getEnclosingWriter().print(value); + } + + public void print(String value) throws IOException { + getEnclosingWriter().print(value); + } + + public void println() throws IOException { + getEnclosingWriter().println(); + } + + public void println(boolean value) throws IOException { + getEnclosingWriter().println(value); + } + + public void println(char value) throws IOException { + getEnclosingWriter().println(value); + } + + public void println(char[] value) throws IOException { + getEnclosingWriter().println(value); + } + + public void println(double value) throws IOException { + getEnclosingWriter().println(value); + } + + public void println(float value) throws IOException { + getEnclosingWriter().println(value); + } + + public void println(int value) throws IOException { + getEnclosingWriter().println(value); + } + + public void println(long value) throws IOException { + getEnclosingWriter().println(value); + } + + public void println(Object value) throws IOException { + getEnclosingWriter().println(value); + } + + public void println(String value) throws IOException { + getEnclosingWriter().println(value); + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockFilterChain.java b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockFilterChain.java index b59b233e12..3f74cac8b5 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockFilterChain.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockFilterChain.java @@ -1,70 +1,70 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import javax.servlet.FilterChain; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - -import org.springframework.util.Assert; - -/** - * Mock implementation of the {@link javax.servlet.FilterConfig} interface. - * - *

Used for testing the web framework; also usefol for testing - * custom {@link javax.servlet.Filter} implementations. - * - * @author Juergen Hoeller - * @since 2.0.3 - * @see MockFilterConfig - * @see PassThroughFilterChain - */ -public class MockFilterChain implements FilterChain { - - private ServletRequest request; - - private ServletResponse response; - - - /** - * Records the request and response. - */ - public void doFilter(ServletRequest request, ServletResponse response) { - Assert.notNull(request, "Request must not be null"); - Assert.notNull(response, "Response must not be null"); - if (this.request != null) { - throw new IllegalStateException("This FilterChain has already been called!"); - } - this.request = request; - this.response = response; - } - - /** - * Return the request that {@link #doFilter} has been called with. - */ - public ServletRequest getRequest() { - return this.request; - } - - /** - * Return the response that {@link #doFilter} has been called with. - */ - public ServletResponse getResponse() { - return this.response; - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import javax.servlet.FilterChain; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import org.springframework.util.Assert; + +/** + * Mock implementation of the {@link javax.servlet.FilterConfig} interface. + * + *

Used for testing the web framework; also usefol for testing + * custom {@link javax.servlet.Filter} implementations. + * + * @author Juergen Hoeller + * @since 2.0.3 + * @see MockFilterConfig + * @see PassThroughFilterChain + */ +public class MockFilterChain implements FilterChain { + + private ServletRequest request; + + private ServletResponse response; + + + /** + * Records the request and response. + */ + public void doFilter(ServletRequest request, ServletResponse response) { + Assert.notNull(request, "Request must not be null"); + Assert.notNull(response, "Response must not be null"); + if (this.request != null) { + throw new IllegalStateException("This FilterChain has already been called!"); + } + this.request = request; + this.response = response; + } + + /** + * Return the request that {@link #doFilter} has been called with. + */ + public ServletRequest getRequest() { + return this.request; + } + + /** + * Return the response that {@link #doFilter} has been called with. + */ + public ServletResponse getResponse() { + return this.response; + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java index f493d553cf..5d23662a3f 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java @@ -1,948 +1,948 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.UnsupportedEncodingException; -import java.security.Principal; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; - -import javax.servlet.AsyncContext; -import javax.servlet.DispatcherType; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import javax.servlet.http.Part; - -import org.springframework.util.Assert; -import org.springframework.util.LinkedCaseInsensitiveMap; - -/** - * Mock implementation of the {@link javax.servlet.http.HttpServletRequest} - * interface. Supports the Servlet 2.5 API level; throws - * {@link UnsupportedOperationException} for all methods introduced in Servlet 3.0. - * - *

Used for testing the web framework; also useful for testing - * application controllers. - * - * @author Juergen Hoeller - * @author Rod Johnson - * @author Rick Evans - * @author Mark Fisher - * @author Chris Beams - * @since 1.0.2 - */ -public class MockHttpServletRequest implements HttpServletRequest { - - /** - * The default protocol: 'http'. - */ - public static final String DEFAULT_PROTOCOL = "http"; - - /** - * The default server address: '127.0.0.1'. - */ - public static final String DEFAULT_SERVER_ADDR = "127.0.0.1"; - - /** - * The default server name: 'localhost'. - */ - public static final String DEFAULT_SERVER_NAME = "localhost"; - - /** - * The default server port: '80'. - */ - public static final int DEFAULT_SERVER_PORT = 80; - - /** - * The default remote address: '127.0.0.1'. - */ - public static final String DEFAULT_REMOTE_ADDR = "127.0.0.1"; - - /** - * The default remote host: 'localhost'. - */ - public static final String DEFAULT_REMOTE_HOST = "localhost"; - - private static final String CONTENT_TYPE_HEADER = "Content-Type"; - - private static final String CHARSET_PREFIX = "charset="; - - - private boolean active = true; - - - //--------------------------------------------------------------------- - // ServletRequest properties - //--------------------------------------------------------------------- - - private final Map attributes = new LinkedHashMap(); - - private String characterEncoding; - - private byte[] content; - - private String contentType; - - private final Map parameters = new LinkedHashMap(16); - - private String protocol = DEFAULT_PROTOCOL; - - private String scheme = DEFAULT_PROTOCOL; - - private String serverName = DEFAULT_SERVER_NAME; - - private int serverPort = DEFAULT_SERVER_PORT; - - private String remoteAddr = DEFAULT_REMOTE_ADDR; - - private String remoteHost = DEFAULT_REMOTE_HOST; - - /** List of locales in descending order */ - private final List locales = new LinkedList(); - - private boolean secure = false; - - private final ServletContext servletContext; - - private int remotePort = DEFAULT_SERVER_PORT; - - private String localName = DEFAULT_SERVER_NAME; - - private String localAddr = DEFAULT_SERVER_ADDR; - - private int localPort = DEFAULT_SERVER_PORT; - - private Map parts = new HashMap(); - - //--------------------------------------------------------------------- - // HttpServletRequest properties - //--------------------------------------------------------------------- - - private String authType; - - private Cookie[] cookies; - - private final Map headers = new LinkedCaseInsensitiveMap(); - - private String method; - - private String pathInfo; - - private String contextPath = ""; - - private String queryString; - - private String remoteUser; - - private final Set userRoles = new HashSet(); - - private Principal userPrincipal; - - private String requestedSessionId; - - private String requestURI; - - private String servletPath = ""; - - private HttpSession session; - - private boolean requestedSessionIdValid = true; - - private boolean requestedSessionIdFromCookie = true; - - private boolean requestedSessionIdFromURL = false; - - - //--------------------------------------------------------------------- - // Constructors - //--------------------------------------------------------------------- - - /** - * Create a new MockHttpServletRequest with a default - * {@link MockServletContext}. - * @see MockServletContext - */ - public MockHttpServletRequest() { - this(null, "", ""); - } - - /** - * Create a new MockHttpServletRequest with a default - * {@link MockServletContext}. - * @param method the request method (may be null) - * @param requestURI the request URI (may be null) - * @see #setMethod - * @see #setRequestURI - * @see MockServletContext - */ - public MockHttpServletRequest(String method, String requestURI) { - this(null, method, requestURI); - } - - /** - * Create a new MockHttpServletRequest. - * @param servletContext the ServletContext that the request runs in - * (may be null to use a default MockServletContext) - * @see MockServletContext - */ - public MockHttpServletRequest(ServletContext servletContext) { - this(servletContext, "", ""); - } - - /** - * Create a new MockHttpServletRequest. - * @param servletContext the ServletContext that the request runs in - * (may be null to use a default MockServletContext) - * @param method the request method (may be null) - * @param requestURI the request URI (may be null) - * @see #setMethod - * @see #setRequestURI - * @see MockServletContext - */ - public MockHttpServletRequest(ServletContext servletContext, String method, String requestURI) { - this.servletContext = (servletContext != null ? servletContext : new MockServletContext()); - this.method = method; - this.requestURI = requestURI; - this.locales.add(Locale.ENGLISH); - } - - - //--------------------------------------------------------------------- - // Lifecycle methods - //--------------------------------------------------------------------- - - /** - * Return the ServletContext that this request is associated with. - * (Not available in the standard HttpServletRequest interface for some reason.) - */ - public ServletContext getServletContext() { - return this.servletContext; - } - - /** - * Return whether this request is still active (that is, not completed yet). - */ - public boolean isActive() { - return this.active; - } - - /** - * Mark this request as completed, keeping its state. - */ - public void close() { - this.active = false; - } - - /** - * Invalidate this request, clearing its state. - */ - public void invalidate() { - close(); - clearAttributes(); - } - - /** - * Check whether this request is still active (that is, not completed yet), - * throwing an IllegalStateException if not active anymore. - */ - protected void checkActive() throws IllegalStateException { - if (!this.active) { - throw new IllegalStateException("Request is not active anymore"); - } - } - - - //--------------------------------------------------------------------- - // ServletRequest interface - //--------------------------------------------------------------------- - - public Object getAttribute(String name) { - checkActive(); - return this.attributes.get(name); - } - - public Enumeration getAttributeNames() { - checkActive(); - return Collections.enumeration(this.attributes.keySet()); - } - - public String getCharacterEncoding() { - return this.characterEncoding; - } - - public void setCharacterEncoding(String characterEncoding) { - this.characterEncoding = characterEncoding; - updateContentTypeHeader(); - } - - private void updateContentTypeHeader() { - if (this.contentType != null) { - StringBuilder sb = new StringBuilder(this.contentType); - if (this.contentType.toLowerCase().indexOf(CHARSET_PREFIX) == -1 && this.characterEncoding != null) { - sb.append(";").append(CHARSET_PREFIX).append(this.characterEncoding); - } - doAddHeaderValue(CONTENT_TYPE_HEADER, sb.toString(), true); - } - } - - public void setContent(byte[] content) { - this.content = content; - } - - public int getContentLength() { - return (this.content != null ? this.content.length : -1); - } - - public void setContentType(String contentType) { - this.contentType = contentType; - if (contentType != null) { - int charsetIndex = contentType.toLowerCase().indexOf(CHARSET_PREFIX); - if (charsetIndex != -1) { - String encoding = contentType.substring(charsetIndex + CHARSET_PREFIX.length()); - this.characterEncoding = encoding; - } - updateContentTypeHeader(); - } - } - - public String getContentType() { - return this.contentType; - } - - public ServletInputStream getInputStream() { - if (this.content != null) { - return new DelegatingServletInputStream(new ByteArrayInputStream(this.content)); - } - else { - return null; - } - } - - /** - * Set a single value for the specified HTTP parameter. - *

If there are already one or more values registered for the given - * parameter name, they will be replaced. - */ - public void setParameter(String name, String value) { - setParameter(name, new String[] {value}); - } - - /** - * Set an array of values for the specified HTTP parameter. - *

If there are already one or more values registered for the given - * parameter name, they will be replaced. - */ - public void setParameter(String name, String[] values) { - Assert.notNull(name, "Parameter name must not be null"); - this.parameters.put(name, values); - } - - /** - * Sets all provided parameters replacing any - * existing values for the provided parameter names. To add without - * replacing existing values, use {@link #addParameters(java.util.Map)}. - */ - public void setParameters(Map params) { - Assert.notNull(params, "Parameter map must not be null"); - for (Object key : params.keySet()) { - Assert.isInstanceOf(String.class, key, - "Parameter map key must be of type [" + String.class.getName() + "]"); - Object value = params.get(key); - if (value instanceof String) { - this.setParameter((String) key, (String) value); - } - else if (value instanceof String[]) { - this.setParameter((String) key, (String[]) value); - } - else { - throw new IllegalArgumentException( - "Parameter map value must be single value " + " or array of type [" + String.class.getName() + - "]"); - } - } - } - - /** - * Add a single value for the specified HTTP parameter. - *

If there are already one or more values registered for the given - * parameter name, the given value will be added to the end of the list. - */ - public void addParameter(String name, String value) { - addParameter(name, new String[] {value}); - } - - /** - * Add an array of values for the specified HTTP parameter. - *

If there are already one or more values registered for the given - * parameter name, the given values will be added to the end of the list. - */ - public void addParameter(String name, String[] values) { - Assert.notNull(name, "Parameter name must not be null"); - String[] oldArr = this.parameters.get(name); - if (oldArr != null) { - String[] newArr = new String[oldArr.length + values.length]; - System.arraycopy(oldArr, 0, newArr, 0, oldArr.length); - System.arraycopy(values, 0, newArr, oldArr.length, values.length); - this.parameters.put(name, newArr); - } - else { - this.parameters.put(name, values); - } - } - - /** - * Adds all provided parameters without replacing - * any existing values. To replace existing values, use - * {@link #setParameters(java.util.Map)}. - */ - public void addParameters(Map params) { - Assert.notNull(params, "Parameter map must not be null"); - for (Object key : params.keySet()) { - Assert.isInstanceOf(String.class, key, - "Parameter map key must be of type [" + String.class.getName() + "]"); - Object value = params.get(key); - if (value instanceof String) { - this.addParameter((String) key, (String) value); - } - else if (value instanceof String[]) { - this.addParameter((String) key, (String[]) value); - } - else { - throw new IllegalArgumentException("Parameter map value must be single value " + - " or array of type [" + String.class.getName() + "]"); - } - } - } - - /** - * Remove already registered values for the specified HTTP parameter, if any. - */ - public void removeParameter(String name) { - Assert.notNull(name, "Parameter name must not be null"); - this.parameters.remove(name); - } - - /** - * Removes all existing parameters. - */ - public void removeAllParameters() { - this.parameters.clear(); - } - - public String getParameter(String name) { - Assert.notNull(name, "Parameter name must not be null"); - String[] arr = this.parameters.get(name); - return (arr != null && arr.length > 0 ? arr[0] : null); - } - - public Enumeration getParameterNames() { - return Collections.enumeration(this.parameters.keySet()); - } - - public String[] getParameterValues(String name) { - Assert.notNull(name, "Parameter name must not be null"); - return this.parameters.get(name); - } - - public Map getParameterMap() { - return Collections.unmodifiableMap(this.parameters); - } - - public void setProtocol(String protocol) { - this.protocol = protocol; - } - - public String getProtocol() { - return this.protocol; - } - - public void setScheme(String scheme) { - this.scheme = scheme; - } - - public String getScheme() { - return this.scheme; - } - - public void setServerName(String serverName) { - this.serverName = serverName; - } - - public String getServerName() { - return this.serverName; - } - - public void setServerPort(int serverPort) { - this.serverPort = serverPort; - } - - public int getServerPort() { - return this.serverPort; - } - - public BufferedReader getReader() throws UnsupportedEncodingException { - if (this.content != null) { - InputStream sourceStream = new ByteArrayInputStream(this.content); - Reader sourceReader = (this.characterEncoding != null) ? - new InputStreamReader(sourceStream, this.characterEncoding) : new InputStreamReader(sourceStream); - return new BufferedReader(sourceReader); - } - else { - return null; - } - } - - public void setRemoteAddr(String remoteAddr) { - this.remoteAddr = remoteAddr; - } - - public String getRemoteAddr() { - return this.remoteAddr; - } - - public void setRemoteHost(String remoteHost) { - this.remoteHost = remoteHost; - } - - public String getRemoteHost() { - return this.remoteHost; - } - - public void setAttribute(String name, Object value) { - checkActive(); - Assert.notNull(name, "Attribute name must not be null"); - if (value != null) { - this.attributes.put(name, value); - } - else { - this.attributes.remove(name); - } - } - - public void removeAttribute(String name) { - checkActive(); - Assert.notNull(name, "Attribute name must not be null"); - this.attributes.remove(name); - } - - /** - * Clear all of this request's attributes. - */ - public void clearAttributes() { - this.attributes.clear(); - } - - /** - * Add a new preferred locale, before any existing locales. - */ - public void addPreferredLocale(Locale locale) { - Assert.notNull(locale, "Locale must not be null"); - this.locales.add(0, locale); - } - - public Locale getLocale() { - return this.locales.get(0); - } - - public Enumeration getLocales() { - return Collections.enumeration(this.locales); - } - - public void setSecure(boolean secure) { - this.secure = secure; - } - - public boolean isSecure() { - return this.secure; - } - - public RequestDispatcher getRequestDispatcher(String path) { - return new MockRequestDispatcher(path); - } - - public String getRealPath(String path) { - return this.servletContext.getRealPath(path); - } - - public void setRemotePort(int remotePort) { - this.remotePort = remotePort; - } - - public int getRemotePort() { - return this.remotePort; - } - - public void setLocalName(String localName) { - this.localName = localName; - } - - public String getLocalName() { - return this.localName; - } - - public void setLocalAddr(String localAddr) { - this.localAddr = localAddr; - } - - public String getLocalAddr() { - return this.localAddr; - } - - public void setLocalPort(int localPort) { - this.localPort = localPort; - } - - public int getLocalPort() { - return this.localPort; - } - - - //--------------------------------------------------------------------- - // HttpServletRequest interface - //--------------------------------------------------------------------- - - public void setAuthType(String authType) { - this.authType = authType; - } - - public String getAuthType() { - return this.authType; - } - - public void setCookies(Cookie... cookies) { - this.cookies = cookies; - } - - public Cookie[] getCookies() { - return this.cookies; - } - - /** - * Add a header entry for the given name. - *

If there was no entry for that header name before, - * the value will be used as-is. In case of an existing entry, - * a String array will be created, adding the given value (more - * specifically, its toString representation) as further element. - *

Multiple values can only be stored as list of Strings, - * following the Servlet spec (see getHeaders accessor). - * As alternative to repeated addHeader calls for - * individual elements, you can use a single call with an entire - * array or Collection of values as parameter. - * @see #getHeaderNames - * @see #getHeader - * @see #getHeaders - * @see #getDateHeader - * @see #getIntHeader - */ - public void addHeader(String name, Object value) { - if (CONTENT_TYPE_HEADER.equalsIgnoreCase(name)) { - setContentType((String) value); - return; - } - doAddHeaderValue(name, value, false); - } - - @SuppressWarnings("rawtypes") - private void doAddHeaderValue(String name, Object value, boolean replace) { - HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); - Assert.notNull(value, "Header value must not be null"); - if (header == null || replace) { - header = new HeaderValueHolder(); - this.headers.put(name, header); - } - if (value instanceof Collection) { - header.addValues((Collection) value); - } - else if (value.getClass().isArray()) { - header.addValueArray(value); - } - else { - header.addValue(value); - } - } - - public long getDateHeader(String name) { - HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); - Object value = (header != null ? header.getValue() : null); - if (value instanceof Date) { - return ((Date) value).getTime(); - } - else if (value instanceof Number) { - return ((Number) value).longValue(); - } - else if (value != null) { - throw new IllegalArgumentException( - "Value for header '" + name + "' is neither a Date nor a Number: " + value); - } - else { - return -1L; - } - } - - public String getHeader(String name) { - HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); - return (header != null ? header.getValue().toString() : null); - } - - public Enumeration getHeaders(String name) { - HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); - return Collections.enumeration(header != null ? header.getStringValues() : new LinkedList()); - } - - public Enumeration getHeaderNames() { - return Collections.enumeration(this.headers.keySet()); - } - - public int getIntHeader(String name) { - HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); - Object value = (header != null ? header.getValue() : null); - if (value instanceof Number) { - return ((Number) value).intValue(); - } - else if (value instanceof String) { - return Integer.parseInt((String) value); - } - else if (value != null) { - throw new NumberFormatException("Value for header '" + name + "' is not a Number: " + value); - } - else { - return -1; - } - } - - public void setMethod(String method) { - this.method = method; - } - - public String getMethod() { - return this.method; - } - - public void setPathInfo(String pathInfo) { - this.pathInfo = pathInfo; - } - - public String getPathInfo() { - return this.pathInfo; - } - - public String getPathTranslated() { - return (this.pathInfo != null ? getRealPath(this.pathInfo) : null); - } - - public void setContextPath(String contextPath) { - this.contextPath = contextPath; - } - - public String getContextPath() { - return this.contextPath; - } - - public void setQueryString(String queryString) { - this.queryString = queryString; - } - - public String getQueryString() { - return this.queryString; - } - - public void setRemoteUser(String remoteUser) { - this.remoteUser = remoteUser; - } - - public String getRemoteUser() { - return this.remoteUser; - } - - public void addUserRole(String role) { - this.userRoles.add(role); - } - - public boolean isUserInRole(String role) { - return this.userRoles.contains(role); - } - - public void setUserPrincipal(Principal userPrincipal) { - this.userPrincipal = userPrincipal; - } - - public Principal getUserPrincipal() { - return this.userPrincipal; - } - - public void setRequestedSessionId(String requestedSessionId) { - this.requestedSessionId = requestedSessionId; - } - - public String getRequestedSessionId() { - return this.requestedSessionId; - } - - public void setRequestURI(String requestURI) { - this.requestURI = requestURI; - } - - public String getRequestURI() { - return this.requestURI; - } - - public StringBuffer getRequestURL() { - StringBuffer url = new StringBuffer(this.scheme); - url.append("://").append(this.serverName).append(':').append(this.serverPort); - url.append(getRequestURI()); - return url; - } - - public void setServletPath(String servletPath) { - this.servletPath = servletPath; - } - - public String getServletPath() { - return this.servletPath; - } - - public void setSession(HttpSession session) { - this.session = session; - if (session instanceof MockHttpSession) { - MockHttpSession mockSession = ((MockHttpSession) session); - mockSession.access(); - } - } - - public HttpSession getSession(boolean create) { - checkActive(); - // Reset session if invalidated. - if (this.session instanceof MockHttpSession && ((MockHttpSession) this.session).isInvalid()) { - this.session = null; - } - // Create new session if necessary. - if (this.session == null && create) { - this.session = new MockHttpSession(this.servletContext); - } - return this.session; - } - - public HttpSession getSession() { - return getSession(true); - } - - public void setRequestedSessionIdValid(boolean requestedSessionIdValid) { - this.requestedSessionIdValid = requestedSessionIdValid; - } - - public boolean isRequestedSessionIdValid() { - return this.requestedSessionIdValid; - } - - public void setRequestedSessionIdFromCookie(boolean requestedSessionIdFromCookie) { - this.requestedSessionIdFromCookie = requestedSessionIdFromCookie; - } - - public boolean isRequestedSessionIdFromCookie() { - return this.requestedSessionIdFromCookie; - } - - public void setRequestedSessionIdFromURL(boolean requestedSessionIdFromURL) { - this.requestedSessionIdFromURL = requestedSessionIdFromURL; - } - - public boolean isRequestedSessionIdFromURL() { - return this.requestedSessionIdFromURL; - } - - public boolean isRequestedSessionIdFromUrl() { - return isRequestedSessionIdFromURL(); - } - - - //--------------------------------------------------------------------- - // Methods introduced in Servlet 3.0 - //--------------------------------------------------------------------- - - public AsyncContext getAsyncContext() { - throw new UnsupportedOperationException(); - } - - public DispatcherType getDispatcherType() { - throw new UnsupportedOperationException(); - } - - public boolean isAsyncSupported() { - throw new UnsupportedOperationException(); - } - - public AsyncContext startAsync() { - throw new UnsupportedOperationException(); - } - - public AsyncContext startAsync(ServletRequest arg0, ServletResponse arg1) { - throw new UnsupportedOperationException(); - } - - public boolean isAsyncStarted() { - throw new UnsupportedOperationException(); - } - - public boolean authenticate(HttpServletResponse arg0) throws IOException, ServletException { - throw new UnsupportedOperationException(); - } - - public void addPart(Part part) { - parts.put(part.getName(), part); - } - - public Part getPart(String key) throws IOException, IllegalStateException, ServletException { - return parts.get(key); - } - - public Collection getParts() throws IOException, IllegalStateException, ServletException { - return parts.values(); - } - - public void login(String arg0, String arg1) throws ServletException { - throw new UnsupportedOperationException(); - } - - public void logout() throws ServletException { - throw new UnsupportedOperationException(); - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.security.Principal; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import javax.servlet.AsyncContext; +import javax.servlet.DispatcherType; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import javax.servlet.http.Part; + +import org.springframework.util.Assert; +import org.springframework.util.LinkedCaseInsensitiveMap; + +/** + * Mock implementation of the {@link javax.servlet.http.HttpServletRequest} + * interface. Supports the Servlet 2.5 API level; throws + * {@link UnsupportedOperationException} for all methods introduced in Servlet 3.0. + * + *

Used for testing the web framework; also useful for testing + * application controllers. + * + * @author Juergen Hoeller + * @author Rod Johnson + * @author Rick Evans + * @author Mark Fisher + * @author Chris Beams + * @since 1.0.2 + */ +public class MockHttpServletRequest implements HttpServletRequest { + + /** + * The default protocol: 'http'. + */ + public static final String DEFAULT_PROTOCOL = "http"; + + /** + * The default server address: '127.0.0.1'. + */ + public static final String DEFAULT_SERVER_ADDR = "127.0.0.1"; + + /** + * The default server name: 'localhost'. + */ + public static final String DEFAULT_SERVER_NAME = "localhost"; + + /** + * The default server port: '80'. + */ + public static final int DEFAULT_SERVER_PORT = 80; + + /** + * The default remote address: '127.0.0.1'. + */ + public static final String DEFAULT_REMOTE_ADDR = "127.0.0.1"; + + /** + * The default remote host: 'localhost'. + */ + public static final String DEFAULT_REMOTE_HOST = "localhost"; + + private static final String CONTENT_TYPE_HEADER = "Content-Type"; + + private static final String CHARSET_PREFIX = "charset="; + + + private boolean active = true; + + + //--------------------------------------------------------------------- + // ServletRequest properties + //--------------------------------------------------------------------- + + private final Map attributes = new LinkedHashMap(); + + private String characterEncoding; + + private byte[] content; + + private String contentType; + + private final Map parameters = new LinkedHashMap(16); + + private String protocol = DEFAULT_PROTOCOL; + + private String scheme = DEFAULT_PROTOCOL; + + private String serverName = DEFAULT_SERVER_NAME; + + private int serverPort = DEFAULT_SERVER_PORT; + + private String remoteAddr = DEFAULT_REMOTE_ADDR; + + private String remoteHost = DEFAULT_REMOTE_HOST; + + /** List of locales in descending order */ + private final List locales = new LinkedList(); + + private boolean secure = false; + + private final ServletContext servletContext; + + private int remotePort = DEFAULT_SERVER_PORT; + + private String localName = DEFAULT_SERVER_NAME; + + private String localAddr = DEFAULT_SERVER_ADDR; + + private int localPort = DEFAULT_SERVER_PORT; + + private Map parts = new HashMap(); + + //--------------------------------------------------------------------- + // HttpServletRequest properties + //--------------------------------------------------------------------- + + private String authType; + + private Cookie[] cookies; + + private final Map headers = new LinkedCaseInsensitiveMap(); + + private String method; + + private String pathInfo; + + private String contextPath = ""; + + private String queryString; + + private String remoteUser; + + private final Set userRoles = new HashSet(); + + private Principal userPrincipal; + + private String requestedSessionId; + + private String requestURI; + + private String servletPath = ""; + + private HttpSession session; + + private boolean requestedSessionIdValid = true; + + private boolean requestedSessionIdFromCookie = true; + + private boolean requestedSessionIdFromURL = false; + + + //--------------------------------------------------------------------- + // Constructors + //--------------------------------------------------------------------- + + /** + * Create a new MockHttpServletRequest with a default + * {@link MockServletContext}. + * @see MockServletContext + */ + public MockHttpServletRequest() { + this(null, "", ""); + } + + /** + * Create a new MockHttpServletRequest with a default + * {@link MockServletContext}. + * @param method the request method (may be null) + * @param requestURI the request URI (may be null) + * @see #setMethod + * @see #setRequestURI + * @see MockServletContext + */ + public MockHttpServletRequest(String method, String requestURI) { + this(null, method, requestURI); + } + + /** + * Create a new MockHttpServletRequest. + * @param servletContext the ServletContext that the request runs in + * (may be null to use a default MockServletContext) + * @see MockServletContext + */ + public MockHttpServletRequest(ServletContext servletContext) { + this(servletContext, "", ""); + } + + /** + * Create a new MockHttpServletRequest. + * @param servletContext the ServletContext that the request runs in + * (may be null to use a default MockServletContext) + * @param method the request method (may be null) + * @param requestURI the request URI (may be null) + * @see #setMethod + * @see #setRequestURI + * @see MockServletContext + */ + public MockHttpServletRequest(ServletContext servletContext, String method, String requestURI) { + this.servletContext = (servletContext != null ? servletContext : new MockServletContext()); + this.method = method; + this.requestURI = requestURI; + this.locales.add(Locale.ENGLISH); + } + + + //--------------------------------------------------------------------- + // Lifecycle methods + //--------------------------------------------------------------------- + + /** + * Return the ServletContext that this request is associated with. + * (Not available in the standard HttpServletRequest interface for some reason.) + */ + public ServletContext getServletContext() { + return this.servletContext; + } + + /** + * Return whether this request is still active (that is, not completed yet). + */ + public boolean isActive() { + return this.active; + } + + /** + * Mark this request as completed, keeping its state. + */ + public void close() { + this.active = false; + } + + /** + * Invalidate this request, clearing its state. + */ + public void invalidate() { + close(); + clearAttributes(); + } + + /** + * Check whether this request is still active (that is, not completed yet), + * throwing an IllegalStateException if not active anymore. + */ + protected void checkActive() throws IllegalStateException { + if (!this.active) { + throw new IllegalStateException("Request is not active anymore"); + } + } + + + //--------------------------------------------------------------------- + // ServletRequest interface + //--------------------------------------------------------------------- + + public Object getAttribute(String name) { + checkActive(); + return this.attributes.get(name); + } + + public Enumeration getAttributeNames() { + checkActive(); + return Collections.enumeration(this.attributes.keySet()); + } + + public String getCharacterEncoding() { + return this.characterEncoding; + } + + public void setCharacterEncoding(String characterEncoding) { + this.characterEncoding = characterEncoding; + updateContentTypeHeader(); + } + + private void updateContentTypeHeader() { + if (this.contentType != null) { + StringBuilder sb = new StringBuilder(this.contentType); + if (this.contentType.toLowerCase().indexOf(CHARSET_PREFIX) == -1 && this.characterEncoding != null) { + sb.append(";").append(CHARSET_PREFIX).append(this.characterEncoding); + } + doAddHeaderValue(CONTENT_TYPE_HEADER, sb.toString(), true); + } + } + + public void setContent(byte[] content) { + this.content = content; + } + + public int getContentLength() { + return (this.content != null ? this.content.length : -1); + } + + public void setContentType(String contentType) { + this.contentType = contentType; + if (contentType != null) { + int charsetIndex = contentType.toLowerCase().indexOf(CHARSET_PREFIX); + if (charsetIndex != -1) { + String encoding = contentType.substring(charsetIndex + CHARSET_PREFIX.length()); + this.characterEncoding = encoding; + } + updateContentTypeHeader(); + } + } + + public String getContentType() { + return this.contentType; + } + + public ServletInputStream getInputStream() { + if (this.content != null) { + return new DelegatingServletInputStream(new ByteArrayInputStream(this.content)); + } + else { + return null; + } + } + + /** + * Set a single value for the specified HTTP parameter. + *

If there are already one or more values registered for the given + * parameter name, they will be replaced. + */ + public void setParameter(String name, String value) { + setParameter(name, new String[] {value}); + } + + /** + * Set an array of values for the specified HTTP parameter. + *

If there are already one or more values registered for the given + * parameter name, they will be replaced. + */ + public void setParameter(String name, String[] values) { + Assert.notNull(name, "Parameter name must not be null"); + this.parameters.put(name, values); + } + + /** + * Sets all provided parameters replacing any + * existing values for the provided parameter names. To add without + * replacing existing values, use {@link #addParameters(java.util.Map)}. + */ + public void setParameters(Map params) { + Assert.notNull(params, "Parameter map must not be null"); + for (Object key : params.keySet()) { + Assert.isInstanceOf(String.class, key, + "Parameter map key must be of type [" + String.class.getName() + "]"); + Object value = params.get(key); + if (value instanceof String) { + this.setParameter((String) key, (String) value); + } + else if (value instanceof String[]) { + this.setParameter((String) key, (String[]) value); + } + else { + throw new IllegalArgumentException( + "Parameter map value must be single value " + " or array of type [" + String.class.getName() + + "]"); + } + } + } + + /** + * Add a single value for the specified HTTP parameter. + *

If there are already one or more values registered for the given + * parameter name, the given value will be added to the end of the list. + */ + public void addParameter(String name, String value) { + addParameter(name, new String[] {value}); + } + + /** + * Add an array of values for the specified HTTP parameter. + *

If there are already one or more values registered for the given + * parameter name, the given values will be added to the end of the list. + */ + public void addParameter(String name, String[] values) { + Assert.notNull(name, "Parameter name must not be null"); + String[] oldArr = this.parameters.get(name); + if (oldArr != null) { + String[] newArr = new String[oldArr.length + values.length]; + System.arraycopy(oldArr, 0, newArr, 0, oldArr.length); + System.arraycopy(values, 0, newArr, oldArr.length, values.length); + this.parameters.put(name, newArr); + } + else { + this.parameters.put(name, values); + } + } + + /** + * Adds all provided parameters without replacing + * any existing values. To replace existing values, use + * {@link #setParameters(java.util.Map)}. + */ + public void addParameters(Map params) { + Assert.notNull(params, "Parameter map must not be null"); + for (Object key : params.keySet()) { + Assert.isInstanceOf(String.class, key, + "Parameter map key must be of type [" + String.class.getName() + "]"); + Object value = params.get(key); + if (value instanceof String) { + this.addParameter((String) key, (String) value); + } + else if (value instanceof String[]) { + this.addParameter((String) key, (String[]) value); + } + else { + throw new IllegalArgumentException("Parameter map value must be single value " + + " or array of type [" + String.class.getName() + "]"); + } + } + } + + /** + * Remove already registered values for the specified HTTP parameter, if any. + */ + public void removeParameter(String name) { + Assert.notNull(name, "Parameter name must not be null"); + this.parameters.remove(name); + } + + /** + * Removes all existing parameters. + */ + public void removeAllParameters() { + this.parameters.clear(); + } + + public String getParameter(String name) { + Assert.notNull(name, "Parameter name must not be null"); + String[] arr = this.parameters.get(name); + return (arr != null && arr.length > 0 ? arr[0] : null); + } + + public Enumeration getParameterNames() { + return Collections.enumeration(this.parameters.keySet()); + } + + public String[] getParameterValues(String name) { + Assert.notNull(name, "Parameter name must not be null"); + return this.parameters.get(name); + } + + public Map getParameterMap() { + return Collections.unmodifiableMap(this.parameters); + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public String getProtocol() { + return this.protocol; + } + + public void setScheme(String scheme) { + this.scheme = scheme; + } + + public String getScheme() { + return this.scheme; + } + + public void setServerName(String serverName) { + this.serverName = serverName; + } + + public String getServerName() { + return this.serverName; + } + + public void setServerPort(int serverPort) { + this.serverPort = serverPort; + } + + public int getServerPort() { + return this.serverPort; + } + + public BufferedReader getReader() throws UnsupportedEncodingException { + if (this.content != null) { + InputStream sourceStream = new ByteArrayInputStream(this.content); + Reader sourceReader = (this.characterEncoding != null) ? + new InputStreamReader(sourceStream, this.characterEncoding) : new InputStreamReader(sourceStream); + return new BufferedReader(sourceReader); + } + else { + return null; + } + } + + public void setRemoteAddr(String remoteAddr) { + this.remoteAddr = remoteAddr; + } + + public String getRemoteAddr() { + return this.remoteAddr; + } + + public void setRemoteHost(String remoteHost) { + this.remoteHost = remoteHost; + } + + public String getRemoteHost() { + return this.remoteHost; + } + + public void setAttribute(String name, Object value) { + checkActive(); + Assert.notNull(name, "Attribute name must not be null"); + if (value != null) { + this.attributes.put(name, value); + } + else { + this.attributes.remove(name); + } + } + + public void removeAttribute(String name) { + checkActive(); + Assert.notNull(name, "Attribute name must not be null"); + this.attributes.remove(name); + } + + /** + * Clear all of this request's attributes. + */ + public void clearAttributes() { + this.attributes.clear(); + } + + /** + * Add a new preferred locale, before any existing locales. + */ + public void addPreferredLocale(Locale locale) { + Assert.notNull(locale, "Locale must not be null"); + this.locales.add(0, locale); + } + + public Locale getLocale() { + return this.locales.get(0); + } + + public Enumeration getLocales() { + return Collections.enumeration(this.locales); + } + + public void setSecure(boolean secure) { + this.secure = secure; + } + + public boolean isSecure() { + return this.secure; + } + + public RequestDispatcher getRequestDispatcher(String path) { + return new MockRequestDispatcher(path); + } + + public String getRealPath(String path) { + return this.servletContext.getRealPath(path); + } + + public void setRemotePort(int remotePort) { + this.remotePort = remotePort; + } + + public int getRemotePort() { + return this.remotePort; + } + + public void setLocalName(String localName) { + this.localName = localName; + } + + public String getLocalName() { + return this.localName; + } + + public void setLocalAddr(String localAddr) { + this.localAddr = localAddr; + } + + public String getLocalAddr() { + return this.localAddr; + } + + public void setLocalPort(int localPort) { + this.localPort = localPort; + } + + public int getLocalPort() { + return this.localPort; + } + + + //--------------------------------------------------------------------- + // HttpServletRequest interface + //--------------------------------------------------------------------- + + public void setAuthType(String authType) { + this.authType = authType; + } + + public String getAuthType() { + return this.authType; + } + + public void setCookies(Cookie... cookies) { + this.cookies = cookies; + } + + public Cookie[] getCookies() { + return this.cookies; + } + + /** + * Add a header entry for the given name. + *

If there was no entry for that header name before, + * the value will be used as-is. In case of an existing entry, + * a String array will be created, adding the given value (more + * specifically, its toString representation) as further element. + *

Multiple values can only be stored as list of Strings, + * following the Servlet spec (see getHeaders accessor). + * As alternative to repeated addHeader calls for + * individual elements, you can use a single call with an entire + * array or Collection of values as parameter. + * @see #getHeaderNames + * @see #getHeader + * @see #getHeaders + * @see #getDateHeader + * @see #getIntHeader + */ + public void addHeader(String name, Object value) { + if (CONTENT_TYPE_HEADER.equalsIgnoreCase(name)) { + setContentType((String) value); + return; + } + doAddHeaderValue(name, value, false); + } + + @SuppressWarnings("rawtypes") + private void doAddHeaderValue(String name, Object value, boolean replace) { + HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); + Assert.notNull(value, "Header value must not be null"); + if (header == null || replace) { + header = new HeaderValueHolder(); + this.headers.put(name, header); + } + if (value instanceof Collection) { + header.addValues((Collection) value); + } + else if (value.getClass().isArray()) { + header.addValueArray(value); + } + else { + header.addValue(value); + } + } + + public long getDateHeader(String name) { + HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); + Object value = (header != null ? header.getValue() : null); + if (value instanceof Date) { + return ((Date) value).getTime(); + } + else if (value instanceof Number) { + return ((Number) value).longValue(); + } + else if (value != null) { + throw new IllegalArgumentException( + "Value for header '" + name + "' is neither a Date nor a Number: " + value); + } + else { + return -1L; + } + } + + public String getHeader(String name) { + HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); + return (header != null ? header.getValue().toString() : null); + } + + public Enumeration getHeaders(String name) { + HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); + return Collections.enumeration(header != null ? header.getStringValues() : new LinkedList()); + } + + public Enumeration getHeaderNames() { + return Collections.enumeration(this.headers.keySet()); + } + + public int getIntHeader(String name) { + HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); + Object value = (header != null ? header.getValue() : null); + if (value instanceof Number) { + return ((Number) value).intValue(); + } + else if (value instanceof String) { + return Integer.parseInt((String) value); + } + else if (value != null) { + throw new NumberFormatException("Value for header '" + name + "' is not a Number: " + value); + } + else { + return -1; + } + } + + public void setMethod(String method) { + this.method = method; + } + + public String getMethod() { + return this.method; + } + + public void setPathInfo(String pathInfo) { + this.pathInfo = pathInfo; + } + + public String getPathInfo() { + return this.pathInfo; + } + + public String getPathTranslated() { + return (this.pathInfo != null ? getRealPath(this.pathInfo) : null); + } + + public void setContextPath(String contextPath) { + this.contextPath = contextPath; + } + + public String getContextPath() { + return this.contextPath; + } + + public void setQueryString(String queryString) { + this.queryString = queryString; + } + + public String getQueryString() { + return this.queryString; + } + + public void setRemoteUser(String remoteUser) { + this.remoteUser = remoteUser; + } + + public String getRemoteUser() { + return this.remoteUser; + } + + public void addUserRole(String role) { + this.userRoles.add(role); + } + + public boolean isUserInRole(String role) { + return this.userRoles.contains(role); + } + + public void setUserPrincipal(Principal userPrincipal) { + this.userPrincipal = userPrincipal; + } + + public Principal getUserPrincipal() { + return this.userPrincipal; + } + + public void setRequestedSessionId(String requestedSessionId) { + this.requestedSessionId = requestedSessionId; + } + + public String getRequestedSessionId() { + return this.requestedSessionId; + } + + public void setRequestURI(String requestURI) { + this.requestURI = requestURI; + } + + public String getRequestURI() { + return this.requestURI; + } + + public StringBuffer getRequestURL() { + StringBuffer url = new StringBuffer(this.scheme); + url.append("://").append(this.serverName).append(':').append(this.serverPort); + url.append(getRequestURI()); + return url; + } + + public void setServletPath(String servletPath) { + this.servletPath = servletPath; + } + + public String getServletPath() { + return this.servletPath; + } + + public void setSession(HttpSession session) { + this.session = session; + if (session instanceof MockHttpSession) { + MockHttpSession mockSession = ((MockHttpSession) session); + mockSession.access(); + } + } + + public HttpSession getSession(boolean create) { + checkActive(); + // Reset session if invalidated. + if (this.session instanceof MockHttpSession && ((MockHttpSession) this.session).isInvalid()) { + this.session = null; + } + // Create new session if necessary. + if (this.session == null && create) { + this.session = new MockHttpSession(this.servletContext); + } + return this.session; + } + + public HttpSession getSession() { + return getSession(true); + } + + public void setRequestedSessionIdValid(boolean requestedSessionIdValid) { + this.requestedSessionIdValid = requestedSessionIdValid; + } + + public boolean isRequestedSessionIdValid() { + return this.requestedSessionIdValid; + } + + public void setRequestedSessionIdFromCookie(boolean requestedSessionIdFromCookie) { + this.requestedSessionIdFromCookie = requestedSessionIdFromCookie; + } + + public boolean isRequestedSessionIdFromCookie() { + return this.requestedSessionIdFromCookie; + } + + public void setRequestedSessionIdFromURL(boolean requestedSessionIdFromURL) { + this.requestedSessionIdFromURL = requestedSessionIdFromURL; + } + + public boolean isRequestedSessionIdFromURL() { + return this.requestedSessionIdFromURL; + } + + public boolean isRequestedSessionIdFromUrl() { + return isRequestedSessionIdFromURL(); + } + + + //--------------------------------------------------------------------- + // Methods introduced in Servlet 3.0 + //--------------------------------------------------------------------- + + public AsyncContext getAsyncContext() { + throw new UnsupportedOperationException(); + } + + public DispatcherType getDispatcherType() { + throw new UnsupportedOperationException(); + } + + public boolean isAsyncSupported() { + throw new UnsupportedOperationException(); + } + + public AsyncContext startAsync() { + throw new UnsupportedOperationException(); + } + + public AsyncContext startAsync(ServletRequest arg0, ServletResponse arg1) { + throw new UnsupportedOperationException(); + } + + public boolean isAsyncStarted() { + throw new UnsupportedOperationException(); + } + + public boolean authenticate(HttpServletResponse arg0) throws IOException, ServletException { + throw new UnsupportedOperationException(); + } + + public void addPart(Part part) { + parts.put(part.getName(), part); + } + + public Part getPart(String key) throws IOException, IllegalStateException, ServletException { + return parts.get(key); + } + + public Collection getParts() throws IOException, IllegalStateException, ServletException { + return parts.values(); + } + + public void login(String arg0, String arg1) throws ServletException { + throw new UnsupportedOperationException(); + } + + public void logout() throws ServletException { + throw new UnsupportedOperationException(); + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpSession.java b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpSession.java index 3803e93712..757414dbbc 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpSession.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpSession.java @@ -1,246 +1,246 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import java.io.Serializable; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; -import javax.servlet.ServletContext; -import javax.servlet.http.HttpSession; -import javax.servlet.http.HttpSessionBindingEvent; -import javax.servlet.http.HttpSessionBindingListener; -import javax.servlet.http.HttpSessionContext; - -import org.springframework.util.Assert; - -/** - * Mock implementation of the {@link javax.servlet.http.HttpSession} interface. - * Supports the Servlet 2.4 API level. - * - *

Used for testing the web framework; also useful for testing - * application controllers. - * - * @author Juergen Hoeller - * @author Rod Johnson - * @author Mark Fisher - * @since 1.0.2 - */ -public class MockHttpSession implements HttpSession { - - public static final String SESSION_COOKIE_NAME = "JSESSION"; - - private static int nextId = 1; - - - private final String id; - - private final long creationTime = System.currentTimeMillis(); - - private int maxInactiveInterval; - - private long lastAccessedTime = System.currentTimeMillis(); - - private final ServletContext servletContext; - - private final Map attributes = new LinkedHashMap(); - - private boolean invalid = false; - - private boolean isNew = true; - - - /** - * Create a new MockHttpSession with a default {@link MockServletContext}. - * @see MockServletContext - */ - public MockHttpSession() { - this(null); - } - - /** - * Create a new MockHttpSession. - * @param servletContext the ServletContext that the session runs in - */ - public MockHttpSession(ServletContext servletContext) { - this(servletContext, null); - } - - /** - * Create a new MockHttpSession. - * @param servletContext the ServletContext that the session runs in - * @param id a unique identifier for this session - */ - public MockHttpSession(ServletContext servletContext, String id) { - this.servletContext = (servletContext != null ? servletContext : new MockServletContext()); - this.id = (id != null ? id : Integer.toString(nextId++)); - } - - - public long getCreationTime() { - return this.creationTime; - } - - public String getId() { - return this.id; - } - - public void access() { - this.lastAccessedTime = System.currentTimeMillis(); - this.isNew = false; - } - - public long getLastAccessedTime() { - return this.lastAccessedTime; - } - - public ServletContext getServletContext() { - return this.servletContext; - } - - public void setMaxInactiveInterval(int interval) { - this.maxInactiveInterval = interval; - } - - public int getMaxInactiveInterval() { - return this.maxInactiveInterval; - } - - public HttpSessionContext getSessionContext() { - throw new UnsupportedOperationException("getSessionContext"); - } - - public Object getAttribute(String name) { - Assert.notNull(name, "Attribute name must not be null"); - return this.attributes.get(name); - } - - public Object getValue(String name) { - return getAttribute(name); - } - - public Enumeration getAttributeNames() { - return Collections.enumeration(this.attributes.keySet()); - } - - public String[] getValueNames() { - return this.attributes.keySet().toArray(new String[this.attributes.size()]); - } - - public void setAttribute(String name, Object value) { - Assert.notNull(name, "Attribute name must not be null"); - if (value != null) { - this.attributes.put(name, value); - if (value instanceof HttpSessionBindingListener) { - ((HttpSessionBindingListener) value).valueBound(new HttpSessionBindingEvent(this, name, value)); - } - } - else { - removeAttribute(name); - } - } - - public void putValue(String name, Object value) { - setAttribute(name, value); - } - - public void removeAttribute(String name) { - Assert.notNull(name, "Attribute name must not be null"); - Object value = this.attributes.remove(name); - if (value instanceof HttpSessionBindingListener) { - ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value)); - } - } - - public void removeValue(String name) { - removeAttribute(name); - } - - /** - * Clear all of this session's attributes. - */ - public void clearAttributes() { - for (Iterator> it = this.attributes.entrySet().iterator(); it.hasNext();) { - Map.Entry entry = it.next(); - String name = entry.getKey(); - Object value = entry.getValue(); - it.remove(); - if (value instanceof HttpSessionBindingListener) { - ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value)); - } - } - } - - public void invalidate() { - this.invalid = true; - clearAttributes(); - } - - public boolean isInvalid() { - return this.invalid; - } - - public void setNew(boolean value) { - this.isNew = value; - } - - public boolean isNew() { - return this.isNew; - } - - - /** - * Serialize the attributes of this session into an object that can - * be turned into a byte array with standard Java serialization. - * @return a representation of this session's serialized state - */ - public Serializable serializeState() { - HashMap state = new HashMap(); - for (Iterator> it = this.attributes.entrySet().iterator(); it.hasNext();) { - Map.Entry entry = it.next(); - String name = entry.getKey(); - Object value = entry.getValue(); - it.remove(); - if (value instanceof Serializable) { - state.put(name, (Serializable) value); - } - else { - // Not serializable... Servlet containers usually automatically - // unbind the attribute in this case. - if (value instanceof HttpSessionBindingListener) { - ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value)); - } - } - } - return state; - } - - /** - * Deserialize the attributes of this session from a state object - * created by {@link #serializeState()}. - * @param state a representation of this session's serialized state - */ - @SuppressWarnings("unchecked") - public void deserializeState(Serializable state) { - Assert.isTrue(state instanceof Map, "Serialized state needs to be of type [java.util.Map]"); - this.attributes.putAll((Map) state); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.io.Serializable; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpSessionBindingEvent; +import javax.servlet.http.HttpSessionBindingListener; +import javax.servlet.http.HttpSessionContext; + +import org.springframework.util.Assert; + +/** + * Mock implementation of the {@link javax.servlet.http.HttpSession} interface. + * Supports the Servlet 2.4 API level. + * + *

Used for testing the web framework; also useful for testing + * application controllers. + * + * @author Juergen Hoeller + * @author Rod Johnson + * @author Mark Fisher + * @since 1.0.2 + */ +public class MockHttpSession implements HttpSession { + + public static final String SESSION_COOKIE_NAME = "JSESSION"; + + private static int nextId = 1; + + + private final String id; + + private final long creationTime = System.currentTimeMillis(); + + private int maxInactiveInterval; + + private long lastAccessedTime = System.currentTimeMillis(); + + private final ServletContext servletContext; + + private final Map attributes = new LinkedHashMap(); + + private boolean invalid = false; + + private boolean isNew = true; + + + /** + * Create a new MockHttpSession with a default {@link MockServletContext}. + * @see MockServletContext + */ + public MockHttpSession() { + this(null); + } + + /** + * Create a new MockHttpSession. + * @param servletContext the ServletContext that the session runs in + */ + public MockHttpSession(ServletContext servletContext) { + this(servletContext, null); + } + + /** + * Create a new MockHttpSession. + * @param servletContext the ServletContext that the session runs in + * @param id a unique identifier for this session + */ + public MockHttpSession(ServletContext servletContext, String id) { + this.servletContext = (servletContext != null ? servletContext : new MockServletContext()); + this.id = (id != null ? id : Integer.toString(nextId++)); + } + + + public long getCreationTime() { + return this.creationTime; + } + + public String getId() { + return this.id; + } + + public void access() { + this.lastAccessedTime = System.currentTimeMillis(); + this.isNew = false; + } + + public long getLastAccessedTime() { + return this.lastAccessedTime; + } + + public ServletContext getServletContext() { + return this.servletContext; + } + + public void setMaxInactiveInterval(int interval) { + this.maxInactiveInterval = interval; + } + + public int getMaxInactiveInterval() { + return this.maxInactiveInterval; + } + + public HttpSessionContext getSessionContext() { + throw new UnsupportedOperationException("getSessionContext"); + } + + public Object getAttribute(String name) { + Assert.notNull(name, "Attribute name must not be null"); + return this.attributes.get(name); + } + + public Object getValue(String name) { + return getAttribute(name); + } + + public Enumeration getAttributeNames() { + return Collections.enumeration(this.attributes.keySet()); + } + + public String[] getValueNames() { + return this.attributes.keySet().toArray(new String[this.attributes.size()]); + } + + public void setAttribute(String name, Object value) { + Assert.notNull(name, "Attribute name must not be null"); + if (value != null) { + this.attributes.put(name, value); + if (value instanceof HttpSessionBindingListener) { + ((HttpSessionBindingListener) value).valueBound(new HttpSessionBindingEvent(this, name, value)); + } + } + else { + removeAttribute(name); + } + } + + public void putValue(String name, Object value) { + setAttribute(name, value); + } + + public void removeAttribute(String name) { + Assert.notNull(name, "Attribute name must not be null"); + Object value = this.attributes.remove(name); + if (value instanceof HttpSessionBindingListener) { + ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value)); + } + } + + public void removeValue(String name) { + removeAttribute(name); + } + + /** + * Clear all of this session's attributes. + */ + public void clearAttributes() { + for (Iterator> it = this.attributes.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = it.next(); + String name = entry.getKey(); + Object value = entry.getValue(); + it.remove(); + if (value instanceof HttpSessionBindingListener) { + ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value)); + } + } + } + + public void invalidate() { + this.invalid = true; + clearAttributes(); + } + + public boolean isInvalid() { + return this.invalid; + } + + public void setNew(boolean value) { + this.isNew = value; + } + + public boolean isNew() { + return this.isNew; + } + + + /** + * Serialize the attributes of this session into an object that can + * be turned into a byte array with standard Java serialization. + * @return a representation of this session's serialized state + */ + public Serializable serializeState() { + HashMap state = new HashMap(); + for (Iterator> it = this.attributes.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = it.next(); + String name = entry.getKey(); + Object value = entry.getValue(); + it.remove(); + if (value instanceof Serializable) { + state.put(name, (Serializable) value); + } + else { + // Not serializable... Servlet containers usually automatically + // unbind the attribute in this case. + if (value instanceof HttpSessionBindingListener) { + ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value)); + } + } + } + return state; + } + + /** + * Deserialize the attributes of this session from a state object + * created by {@link #serializeState()}. + * @param state a representation of this session's serialized state + */ + @SuppressWarnings("unchecked") + public void deserializeState(Serializable state) { + Assert.isTrue(state instanceof Map, "Serialized state needs to be of type [java.util.Map]"); + this.attributes.putAll((Map) state); + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockJspWriter.java b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockJspWriter.java index ab47080e75..1d5bf928bf 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockJspWriter.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockJspWriter.java @@ -1,191 +1,191 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import java.io.IOException; -import java.io.PrintWriter; -import java.io.Writer; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.jsp.JspWriter; - -/** - * Mock implementation of the {@link javax.servlet.jsp.JspWriter} class. - * - *

Used for testing the web framework; only necessary for testing - * applications when testing custom JSP tags. - * - * @author Juergen Hoeller - * @since 2.5 - */ -public class MockJspWriter extends JspWriter { - - private final HttpServletResponse response; - - private PrintWriter targetWriter; - - - /** - * Create a MockJspWriter for the given response, - * using the response's default Writer. - * @param response the servlet response to wrap - */ - public MockJspWriter(HttpServletResponse response) { - this(response, null); - } - - /** - * Create a MockJspWriter for the given plain Writer. - * @param targetWriter the target Writer to wrap - */ - public MockJspWriter(Writer targetWriter) { - this(null, targetWriter); - } - - /** - * Create a MockJspWriter for the given response. - * @param response the servlet response to wrap - * @param targetWriter the target Writer to wrap - */ - public MockJspWriter(HttpServletResponse response, Writer targetWriter) { - super(DEFAULT_BUFFER, true); - this.response = (response != null ? response : new MockHttpServletResponse()); - if (targetWriter instanceof PrintWriter) { - this.targetWriter = (PrintWriter) targetWriter; - } - else if (targetWriter != null) { - this.targetWriter = new PrintWriter(targetWriter); - } - } - - /** - * Lazily initialize the target Writer. - */ - protected PrintWriter getTargetWriter() throws IOException { - if (this.targetWriter == null) { - this.targetWriter = this.response.getWriter(); - } - return this.targetWriter; - } - - - public void clear() throws IOException { - if (this.response.isCommitted()) { - throw new IOException("Response already committed"); - } - this.response.resetBuffer(); - } - - public void clearBuffer() throws IOException { - } - - public void flush() throws IOException { - this.response.flushBuffer(); - } - - public void close() throws IOException { - flush(); - } - - public int getRemaining() { - return Integer.MAX_VALUE; - } - - public void newLine() throws IOException { - getTargetWriter().println(); - } - - public void write(char value[], int offset, int length) throws IOException { - getTargetWriter().write(value, offset, length); - } - - public void print(boolean value) throws IOException { - getTargetWriter().print(value); - } - - public void print(char value) throws IOException { - getTargetWriter().print(value); - } - - public void print(char[] value) throws IOException { - getTargetWriter().print(value); - } - - public void print(double value) throws IOException { - getTargetWriter().print(value); - } - - public void print(float value) throws IOException { - getTargetWriter().print(value); - } - - public void print(int value) throws IOException { - getTargetWriter().print(value); - } - - public void print(long value) throws IOException { - getTargetWriter().print(value); - } - - public void print(Object value) throws IOException { - getTargetWriter().print(value); - } - - public void print(String value) throws IOException { - getTargetWriter().print(value); - } - - public void println() throws IOException { - getTargetWriter().println(); - } - - public void println(boolean value) throws IOException { - getTargetWriter().println(value); - } - - public void println(char value) throws IOException { - getTargetWriter().println(value); - } - - public void println(char[] value) throws IOException { - getTargetWriter().println(value); - } - - public void println(double value) throws IOException { - getTargetWriter().println(value); - } - - public void println(float value) throws IOException { - getTargetWriter().println(value); - } - - public void println(int value) throws IOException { - getTargetWriter().println(value); - } - - public void println(long value) throws IOException { - getTargetWriter().println(value); - } - - public void println(Object value) throws IOException { - getTargetWriter().println(value); - } - - public void println(String value) throws IOException { - getTargetWriter().println(value); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Writer; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.jsp.JspWriter; + +/** + * Mock implementation of the {@link javax.servlet.jsp.JspWriter} class. + * + *

Used for testing the web framework; only necessary for testing + * applications when testing custom JSP tags. + * + * @author Juergen Hoeller + * @since 2.5 + */ +public class MockJspWriter extends JspWriter { + + private final HttpServletResponse response; + + private PrintWriter targetWriter; + + + /** + * Create a MockJspWriter for the given response, + * using the response's default Writer. + * @param response the servlet response to wrap + */ + public MockJspWriter(HttpServletResponse response) { + this(response, null); + } + + /** + * Create a MockJspWriter for the given plain Writer. + * @param targetWriter the target Writer to wrap + */ + public MockJspWriter(Writer targetWriter) { + this(null, targetWriter); + } + + /** + * Create a MockJspWriter for the given response. + * @param response the servlet response to wrap + * @param targetWriter the target Writer to wrap + */ + public MockJspWriter(HttpServletResponse response, Writer targetWriter) { + super(DEFAULT_BUFFER, true); + this.response = (response != null ? response : new MockHttpServletResponse()); + if (targetWriter instanceof PrintWriter) { + this.targetWriter = (PrintWriter) targetWriter; + } + else if (targetWriter != null) { + this.targetWriter = new PrintWriter(targetWriter); + } + } + + /** + * Lazily initialize the target Writer. + */ + protected PrintWriter getTargetWriter() throws IOException { + if (this.targetWriter == null) { + this.targetWriter = this.response.getWriter(); + } + return this.targetWriter; + } + + + public void clear() throws IOException { + if (this.response.isCommitted()) { + throw new IOException("Response already committed"); + } + this.response.resetBuffer(); + } + + public void clearBuffer() throws IOException { + } + + public void flush() throws IOException { + this.response.flushBuffer(); + } + + public void close() throws IOException { + flush(); + } + + public int getRemaining() { + return Integer.MAX_VALUE; + } + + public void newLine() throws IOException { + getTargetWriter().println(); + } + + public void write(char value[], int offset, int length) throws IOException { + getTargetWriter().write(value, offset, length); + } + + public void print(boolean value) throws IOException { + getTargetWriter().print(value); + } + + public void print(char value) throws IOException { + getTargetWriter().print(value); + } + + public void print(char[] value) throws IOException { + getTargetWriter().print(value); + } + + public void print(double value) throws IOException { + getTargetWriter().print(value); + } + + public void print(float value) throws IOException { + getTargetWriter().print(value); + } + + public void print(int value) throws IOException { + getTargetWriter().print(value); + } + + public void print(long value) throws IOException { + getTargetWriter().print(value); + } + + public void print(Object value) throws IOException { + getTargetWriter().print(value); + } + + public void print(String value) throws IOException { + getTargetWriter().print(value); + } + + public void println() throws IOException { + getTargetWriter().println(); + } + + public void println(boolean value) throws IOException { + getTargetWriter().println(value); + } + + public void println(char value) throws IOException { + getTargetWriter().println(value); + } + + public void println(char[] value) throws IOException { + getTargetWriter().println(value); + } + + public void println(double value) throws IOException { + getTargetWriter().println(value); + } + + public void println(float value) throws IOException { + getTargetWriter().println(value); + } + + public void println(int value) throws IOException { + getTargetWriter().println(value); + } + + public void println(long value) throws IOException { + getTargetWriter().println(value); + } + + public void println(Object value) throws IOException { + getTargetWriter().println(value); + } + + public void println(String value) throws IOException { + getTargetWriter().println(value); + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockMultipartFile.java b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockMultipartFile.java index e91936de86..24518968c3 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockMultipartFile.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockMultipartFile.java @@ -1,134 +1,134 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.Collections; -import java.util.Iterator; - -import org.springframework.util.Assert; -import org.springframework.util.FileCopyUtils; -import org.springframework.web.multipart.MultipartFile; - -/** - * Mock implementation of the {@link org.springframework.web.multipart.MultipartFile} - * interface. - * - *

Useful in conjunction with a {@link MockMultipartHttpServletRequest} - * for testing application controllers that access multipart uploads. - * - * @author Juergen Hoeller - * @author Eric Crampton - * @since 2.0 - * @see MockMultipartHttpServletRequest - */ -public class MockMultipartFile implements MultipartFile { - - private final String name; - - private String originalFilename; - - private String contentType; - - private final byte[] content; - - - /** - * Create a new MockMultipartFile with the given content. - * @param name the name of the file - * @param content the content of the file - */ - public MockMultipartFile(String name, byte[] content) { - this(name, "", null, content); - } - - /** - * Create a new MockMultipartFile with the given content. - * @param name the name of the file - * @param contentStream the content of the file as stream - * @throws IOException if reading from the stream failed - */ - public MockMultipartFile(String name, InputStream contentStream) throws IOException { - this(name, "", null, FileCopyUtils.copyToByteArray(contentStream)); - } - - /** - * Create a new MockMultipartFile with the given content. - * @param name the name of the file - * @param originalFilename the original filename (as on the client's machine) - * @param contentType the content type (if known) - * @param content the content of the file - */ - public MockMultipartFile(String name, String originalFilename, String contentType, byte[] content) { - Assert.hasLength(name, "Name must not be null"); - this.name = name; - this.originalFilename = (originalFilename != null ? originalFilename : ""); - this.contentType = contentType; - this.content = (content != null ? content : new byte[0]); - } - - /** - * Create a new MockMultipartFile with the given content. - * @param name the name of the file - * @param originalFilename the original filename (as on the client's machine) - * @param contentType the content type (if known) - * @param contentStream the content of the file as stream - * @throws IOException if reading from the stream failed - */ - public MockMultipartFile(String name, String originalFilename, String contentType, InputStream contentStream) - throws IOException { - - this(name, originalFilename, contentType, FileCopyUtils.copyToByteArray(contentStream)); - } - - - public String getName() { - return this.name; - } - - public String getOriginalFilename() { - return this.originalFilename; - } - - public String getContentType() { - return this.contentType; - } - - public boolean isEmpty() { - return (this.content.length == 0); - } - - public long getSize() { - return this.content.length; - } - - public byte[] getBytes() throws IOException { - return this.content; - } - - public InputStream getInputStream() throws IOException { - return new ByteArrayInputStream(this.content); - } - - public void transferTo(File dest) throws IOException, IllegalStateException { - FileCopyUtils.copy(this.content, dest); - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; +import java.util.Iterator; + +import org.springframework.util.Assert; +import org.springframework.util.FileCopyUtils; +import org.springframework.web.multipart.MultipartFile; + +/** + * Mock implementation of the {@link org.springframework.web.multipart.MultipartFile} + * interface. + * + *

Useful in conjunction with a {@link MockMultipartHttpServletRequest} + * for testing application controllers that access multipart uploads. + * + * @author Juergen Hoeller + * @author Eric Crampton + * @since 2.0 + * @see MockMultipartHttpServletRequest + */ +public class MockMultipartFile implements MultipartFile { + + private final String name; + + private String originalFilename; + + private String contentType; + + private final byte[] content; + + + /** + * Create a new MockMultipartFile with the given content. + * @param name the name of the file + * @param content the content of the file + */ + public MockMultipartFile(String name, byte[] content) { + this(name, "", null, content); + } + + /** + * Create a new MockMultipartFile with the given content. + * @param name the name of the file + * @param contentStream the content of the file as stream + * @throws IOException if reading from the stream failed + */ + public MockMultipartFile(String name, InputStream contentStream) throws IOException { + this(name, "", null, FileCopyUtils.copyToByteArray(contentStream)); + } + + /** + * Create a new MockMultipartFile with the given content. + * @param name the name of the file + * @param originalFilename the original filename (as on the client's machine) + * @param contentType the content type (if known) + * @param content the content of the file + */ + public MockMultipartFile(String name, String originalFilename, String contentType, byte[] content) { + Assert.hasLength(name, "Name must not be null"); + this.name = name; + this.originalFilename = (originalFilename != null ? originalFilename : ""); + this.contentType = contentType; + this.content = (content != null ? content : new byte[0]); + } + + /** + * Create a new MockMultipartFile with the given content. + * @param name the name of the file + * @param originalFilename the original filename (as on the client's machine) + * @param contentType the content type (if known) + * @param contentStream the content of the file as stream + * @throws IOException if reading from the stream failed + */ + public MockMultipartFile(String name, String originalFilename, String contentType, InputStream contentStream) + throws IOException { + + this(name, originalFilename, contentType, FileCopyUtils.copyToByteArray(contentStream)); + } + + + public String getName() { + return this.name; + } + + public String getOriginalFilename() { + return this.originalFilename; + } + + public String getContentType() { + return this.contentType; + } + + public boolean isEmpty() { + return (this.content.length == 0); + } + + public long getSize() { + return this.content.length; + } + + public byte[] getBytes() throws IOException { + return this.content; + } + + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(this.content); + } + + public void transferTo(File dest) throws IOException, IllegalStateException { + FileCopyUtils.copy(this.content, dest); + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockMultipartHttpServletRequest.java b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockMultipartHttpServletRequest.java index e8720dfa0a..b01c4fdcf8 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockMultipartHttpServletRequest.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockMultipartHttpServletRequest.java @@ -1,131 +1,131 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import java.util.Collections; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.util.Assert; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.multipart.MultipartFile; -import org.springframework.web.multipart.MultipartHttpServletRequest; - -/** - * Mock implementation of the - * {@link org.springframework.web.multipart.MultipartHttpServletRequest} interface. - * - *

Useful for testing application controllers that access multipart uploads. - * The {@link MockMultipartFile} can be used to populate these mock requests - * with files. - * - * @author Juergen Hoeller - * @author Eric Crampton - * @author Arjen Poutsma - * @since 2.0 - * @see MockMultipartFile - */ -public class MockMultipartHttpServletRequest extends MockHttpServletRequest implements MultipartHttpServletRequest { - - private final MultiValueMap multipartFiles = - new LinkedMultiValueMap(); - - - public MockMultipartHttpServletRequest() { - setMethod("POST"); - setContentType("multipart/form-data"); - } - - - /** - * Add a file to this request. The parameter name from the multipart - * form is taken from the {@link MultipartFile#getName()}. - * @param file multipart file to be added - */ - public void addFile(MultipartFile file) { - Assert.notNull(file, "MultipartFile must not be null"); - this.multipartFiles.add(file.getName(), file); - } - - public Iterator getFileNames() { - return this.multipartFiles.keySet().iterator(); - } - - public MultipartFile getFile(String name) { - return this.multipartFiles.getFirst(name); - } - - public List getFiles(String name) { - List multipartFiles = this.multipartFiles.get(name); - if (multipartFiles != null) { - return multipartFiles; - } - else { - return Collections.emptyList(); - } - } - - public Map getFileMap() { - return this.multipartFiles.toSingleValueMap(); - } - - public MultiValueMap getMultiFileMap() { - return new LinkedMultiValueMap(this.multipartFiles); - } - - public String getMultipartContentType(String paramOrFileName) { - MultipartFile file = getFile(paramOrFileName); - if (file != null) { - return file.getContentType(); - } - else { - return null; - } - } - - public HttpMethod getRequestMethod() { - return HttpMethod.valueOf(getMethod()); - } - - public HttpHeaders getRequestHeaders() { - HttpHeaders headers = new HttpHeaders(); - Enumeration headerNames = getHeaderNames(); - while (headerNames.hasMoreElements()) { - String headerName = headerNames.nextElement(); - headers.put(headerName, Collections.list(getHeaders(headerName))); - } - return headers; - } - - public HttpHeaders getMultipartHeaders(String paramOrFileName) { - String contentType = getMultipartContentType(paramOrFileName); - if (contentType != null) { - HttpHeaders headers = new HttpHeaders(); - headers.add("Content-Type", contentType); - return headers; - } - else { - return null; - } - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.util.Assert; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; + +/** + * Mock implementation of the + * {@link org.springframework.web.multipart.MultipartHttpServletRequest} interface. + * + *

Useful for testing application controllers that access multipart uploads. + * The {@link MockMultipartFile} can be used to populate these mock requests + * with files. + * + * @author Juergen Hoeller + * @author Eric Crampton + * @author Arjen Poutsma + * @since 2.0 + * @see MockMultipartFile + */ +public class MockMultipartHttpServletRequest extends MockHttpServletRequest implements MultipartHttpServletRequest { + + private final MultiValueMap multipartFiles = + new LinkedMultiValueMap(); + + + public MockMultipartHttpServletRequest() { + setMethod("POST"); + setContentType("multipart/form-data"); + } + + + /** + * Add a file to this request. The parameter name from the multipart + * form is taken from the {@link MultipartFile#getName()}. + * @param file multipart file to be added + */ + public void addFile(MultipartFile file) { + Assert.notNull(file, "MultipartFile must not be null"); + this.multipartFiles.add(file.getName(), file); + } + + public Iterator getFileNames() { + return this.multipartFiles.keySet().iterator(); + } + + public MultipartFile getFile(String name) { + return this.multipartFiles.getFirst(name); + } + + public List getFiles(String name) { + List multipartFiles = this.multipartFiles.get(name); + if (multipartFiles != null) { + return multipartFiles; + } + else { + return Collections.emptyList(); + } + } + + public Map getFileMap() { + return this.multipartFiles.toSingleValueMap(); + } + + public MultiValueMap getMultiFileMap() { + return new LinkedMultiValueMap(this.multipartFiles); + } + + public String getMultipartContentType(String paramOrFileName) { + MultipartFile file = getFile(paramOrFileName); + if (file != null) { + return file.getContentType(); + } + else { + return null; + } + } + + public HttpMethod getRequestMethod() { + return HttpMethod.valueOf(getMethod()); + } + + public HttpHeaders getRequestHeaders() { + HttpHeaders headers = new HttpHeaders(); + Enumeration headerNames = getHeaderNames(); + while (headerNames.hasMoreElements()) { + String headerName = headerNames.nextElement(); + headers.put(headerName, Collections.list(getHeaders(headerName))); + } + return headers; + } + + public HttpHeaders getMultipartHeaders(String paramOrFileName) { + String contentType = getMultipartContentType(paramOrFileName); + if (contentType != null) { + HttpHeaders headers = new HttpHeaders(); + headers.add("Content-Type", contentType); + return headers; + } + else { + return null; + } + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockPageContext.java b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockPageContext.java index 919b50fe41..f0f2433efc 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockPageContext.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockPageContext.java @@ -1,370 +1,370 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.Collections; -import java.util.Enumeration; -import java.util.LinkedHashMap; -import java.util.Map; -import javax.el.ELContext; -import javax.servlet.Servlet; -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import javax.servlet.jsp.JspWriter; -import javax.servlet.jsp.PageContext; -import javax.servlet.jsp.el.ELException; -import javax.servlet.jsp.el.Expression; -import javax.servlet.jsp.el.ExpressionEvaluator; -import javax.servlet.jsp.el.FunctionMapper; -import javax.servlet.jsp.el.VariableResolver; - -import org.springframework.util.Assert; - -/** - * Mock implementation of the {@link javax.servlet.jsp.PageContext} interface. - * - *

Used for testing the web framework; only necessary for testing - * applications when testing custom JSP tags. - * - *

Note: Expects initialization via the constructor rather than via the - * PageContext.initialize method. Does not support writing to - * a JspWriter, request dispatching, and handlePageException calls. - * - * @author Juergen Hoeller - * @since 1.0.2 - */ -public class MockPageContext extends PageContext { - - private final ServletContext servletContext; - - private final HttpServletRequest request; - - private final HttpServletResponse response; - - private final ServletConfig servletConfig; - - private final Map attributes = new LinkedHashMap(); - - private JspWriter out; - - - /** - * Create new MockPageContext with a default {@link MockServletContext}, - * {@link MockHttpServletRequest}, {@link MockHttpServletResponse}, - * {@link MockServletConfig}. - */ - public MockPageContext() { - this(null, null, null, null); - } - - /** - * Create new MockPageContext with a default {@link MockHttpServletRequest}, - * {@link MockHttpServletResponse}, {@link MockServletConfig}. - * @param servletContext the ServletContext that the JSP page runs in - * (only necessary when actually accessing the ServletContext) - */ - public MockPageContext(ServletContext servletContext) { - this(servletContext, null, null, null); - } - - /** - * Create new MockPageContext with a MockHttpServletResponse, - * MockServletConfig. - * @param servletContext the ServletContext that the JSP page runs in - * @param request the current HttpServletRequest - * (only necessary when actually accessing the request) - */ - public MockPageContext(ServletContext servletContext, HttpServletRequest request) { - this(servletContext, request, null, null); - } - - /** - * Create new MockPageContext with a MockServletConfig. - * @param servletContext the ServletContext that the JSP page runs in - * @param request the current HttpServletRequest - * @param response the current HttpServletResponse - * (only necessary when actually writing to the response) - */ - public MockPageContext(ServletContext servletContext, HttpServletRequest request, HttpServletResponse response) { - this(servletContext, request, response, null); - } - - /** - * Create new MockServletConfig. - * @param servletContext the ServletContext that the JSP page runs in - * @param request the current HttpServletRequest - * @param response the current HttpServletResponse - * @param servletConfig the ServletConfig (hardly ever accessed from within a tag) - */ - public MockPageContext(ServletContext servletContext, HttpServletRequest request, - HttpServletResponse response, ServletConfig servletConfig) { - - this.servletContext = (servletContext != null ? servletContext : new MockServletContext()); - this.request = (request != null ? request : new MockHttpServletRequest(servletContext)); - this.response = (response != null ? response : new MockHttpServletResponse()); - this.servletConfig = (servletConfig != null ? servletConfig : new MockServletConfig(servletContext)); - } - - - public void initialize( - Servlet servlet, ServletRequest request, ServletResponse response, - String errorPageURL, boolean needsSession, int bufferSize, boolean autoFlush) { - - throw new UnsupportedOperationException("Use appropriate constructor"); - } - - public void release() { - } - - public void setAttribute(String name, Object value) { - Assert.notNull(name, "Attribute name must not be null"); - if (value != null) { - this.attributes.put(name, value); - } - else { - this.attributes.remove(name); - } - } - - public void setAttribute(String name, Object value, int scope) { - Assert.notNull(name, "Attribute name must not be null"); - switch (scope) { - case PAGE_SCOPE: - setAttribute(name, value); - break; - case REQUEST_SCOPE: - this.request.setAttribute(name, value); - break; - case SESSION_SCOPE: - this.request.getSession().setAttribute(name, value); - break; - case APPLICATION_SCOPE: - this.servletContext.setAttribute(name, value); - break; - default: - throw new IllegalArgumentException("Invalid scope: " + scope); - } - } - - public Object getAttribute(String name) { - Assert.notNull(name, "Attribute name must not be null"); - return this.attributes.get(name); - } - - public Object getAttribute(String name, int scope) { - Assert.notNull(name, "Attribute name must not be null"); - switch (scope) { - case PAGE_SCOPE: - return getAttribute(name); - case REQUEST_SCOPE: - return this.request.getAttribute(name); - case SESSION_SCOPE: - HttpSession session = this.request.getSession(false); - return (session != null ? session.getAttribute(name) : null); - case APPLICATION_SCOPE: - return this.servletContext.getAttribute(name); - default: - throw new IllegalArgumentException("Invalid scope: " + scope); - } - } - - public Object findAttribute(String name) { - Object value = getAttribute(name); - if (value == null) { - value = getAttribute(name, REQUEST_SCOPE); - if (value == null) { - value = getAttribute(name, SESSION_SCOPE); - if (value == null) { - value = getAttribute(name, APPLICATION_SCOPE); - } - } - } - return value; - } - - public void removeAttribute(String name) { - Assert.notNull(name, "Attribute name must not be null"); - this.removeAttribute(name, PageContext.PAGE_SCOPE); - this.removeAttribute(name, PageContext.REQUEST_SCOPE); - this.removeAttribute(name, PageContext.SESSION_SCOPE); - this.removeAttribute(name, PageContext.APPLICATION_SCOPE); - } - - public void removeAttribute(String name, int scope) { - Assert.notNull(name, "Attribute name must not be null"); - switch (scope) { - case PAGE_SCOPE: - this.attributes.remove(name); - break; - case REQUEST_SCOPE: - this.request.removeAttribute(name); - break; - case SESSION_SCOPE: - this.request.getSession().removeAttribute(name); - break; - case APPLICATION_SCOPE: - this.servletContext.removeAttribute(name); - break; - default: - throw new IllegalArgumentException("Invalid scope: " + scope); - } - } - - public int getAttributesScope(String name) { - if (getAttribute(name) != null) { - return PAGE_SCOPE; - } - else if (getAttribute(name, REQUEST_SCOPE) != null) { - return REQUEST_SCOPE; - } - else if (getAttribute(name, SESSION_SCOPE) != null) { - return SESSION_SCOPE; - } - else if (getAttribute(name, APPLICATION_SCOPE) != null) { - return APPLICATION_SCOPE; - } - else { - return 0; - } - } - - public Enumeration getAttributeNames() { - return Collections.enumeration(this.attributes.keySet()); - } - - @SuppressWarnings("unchecked") - public Enumeration getAttributeNamesInScope(int scope) { - switch (scope) { - case PAGE_SCOPE: - return getAttributeNames(); - case REQUEST_SCOPE: - return this.request.getAttributeNames(); - case SESSION_SCOPE: - HttpSession session = this.request.getSession(false); - return (session != null ? session.getAttributeNames() : null); - case APPLICATION_SCOPE: - return this.servletContext.getAttributeNames(); - default: - throw new IllegalArgumentException("Invalid scope: " + scope); - } - } - - public JspWriter getOut() { - if (this.out == null) { - this.out = new MockJspWriter(this.response); - } - return this.out; - } - - public ExpressionEvaluator getExpressionEvaluator() { - return new ExpressionEvaluator() { - public Expression parseExpression(String expression, Class expectedType, FunctionMapper fMapper) throws ELException { - throw new UnsupportedOperationException(); - } - public Object evaluate(String expression, Class expectedType, VariableResolver vResolver, FunctionMapper fMapper) throws ELException { - String key = expression.substring(2, expression.length() - 1); - return findAttribute(key); - } - }; - } - - public ELContext getELContext() { - return null; - } - - public VariableResolver getVariableResolver() { - return new VariableResolver() { - public Object resolveVariable(String pName) throws ELException { - if (pName.equals("pageContext")) { - return this; - } else { - return null; - } - } - }; - } - - public HttpSession getSession() { - return this.request.getSession(); - } - - public Object getPage() { - return this; - } - - public ServletRequest getRequest() { - return this.request; - } - - public ServletResponse getResponse() { - return this.response; - } - - public Exception getException() { - return null; - } - - public ServletConfig getServletConfig() { - return this.servletConfig; - } - - public ServletContext getServletContext() { - return this.servletContext; - } - - public void forward(String path) throws ServletException, IOException { - this.request.getRequestDispatcher(path).forward(this.request, this.response); - } - - public void include(String path) throws ServletException, IOException { - this.request.getRequestDispatcher(path).include(this.request, this.response); - } - - public void include(String path, boolean flush) throws ServletException, IOException { - this.request.getRequestDispatcher(path).include(this.request, this.response); - if (flush) { - this.response.flushBuffer(); - } - } - - public byte[] getContentAsByteArray() { - Assert.isTrue(this.response instanceof MockHttpServletResponse); - return ((MockHttpServletResponse) this.response).getContentAsByteArray(); - } - - public String getContentAsString() throws UnsupportedEncodingException { - Assert.isTrue(this.response instanceof MockHttpServletResponse); - return ((MockHttpServletResponse) this.response).getContentAsString(); - } - - public void handlePageException(Exception ex) throws ServletException, IOException { - throw new ServletException("Page exception", ex); - } - - public void handlePageException(Throwable ex) throws ServletException, IOException { - throw new ServletException("Page exception", ex); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.Collections; +import java.util.Enumeration; +import java.util.LinkedHashMap; +import java.util.Map; +import javax.el.ELContext; +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import javax.servlet.jsp.JspWriter; +import javax.servlet.jsp.PageContext; +import javax.servlet.jsp.el.ELException; +import javax.servlet.jsp.el.Expression; +import javax.servlet.jsp.el.ExpressionEvaluator; +import javax.servlet.jsp.el.FunctionMapper; +import javax.servlet.jsp.el.VariableResolver; + +import org.springframework.util.Assert; + +/** + * Mock implementation of the {@link javax.servlet.jsp.PageContext} interface. + * + *

Used for testing the web framework; only necessary for testing + * applications when testing custom JSP tags. + * + *

Note: Expects initialization via the constructor rather than via the + * PageContext.initialize method. Does not support writing to + * a JspWriter, request dispatching, and handlePageException calls. + * + * @author Juergen Hoeller + * @since 1.0.2 + */ +public class MockPageContext extends PageContext { + + private final ServletContext servletContext; + + private final HttpServletRequest request; + + private final HttpServletResponse response; + + private final ServletConfig servletConfig; + + private final Map attributes = new LinkedHashMap(); + + private JspWriter out; + + + /** + * Create new MockPageContext with a default {@link MockServletContext}, + * {@link MockHttpServletRequest}, {@link MockHttpServletResponse}, + * {@link MockServletConfig}. + */ + public MockPageContext() { + this(null, null, null, null); + } + + /** + * Create new MockPageContext with a default {@link MockHttpServletRequest}, + * {@link MockHttpServletResponse}, {@link MockServletConfig}. + * @param servletContext the ServletContext that the JSP page runs in + * (only necessary when actually accessing the ServletContext) + */ + public MockPageContext(ServletContext servletContext) { + this(servletContext, null, null, null); + } + + /** + * Create new MockPageContext with a MockHttpServletResponse, + * MockServletConfig. + * @param servletContext the ServletContext that the JSP page runs in + * @param request the current HttpServletRequest + * (only necessary when actually accessing the request) + */ + public MockPageContext(ServletContext servletContext, HttpServletRequest request) { + this(servletContext, request, null, null); + } + + /** + * Create new MockPageContext with a MockServletConfig. + * @param servletContext the ServletContext that the JSP page runs in + * @param request the current HttpServletRequest + * @param response the current HttpServletResponse + * (only necessary when actually writing to the response) + */ + public MockPageContext(ServletContext servletContext, HttpServletRequest request, HttpServletResponse response) { + this(servletContext, request, response, null); + } + + /** + * Create new MockServletConfig. + * @param servletContext the ServletContext that the JSP page runs in + * @param request the current HttpServletRequest + * @param response the current HttpServletResponse + * @param servletConfig the ServletConfig (hardly ever accessed from within a tag) + */ + public MockPageContext(ServletContext servletContext, HttpServletRequest request, + HttpServletResponse response, ServletConfig servletConfig) { + + this.servletContext = (servletContext != null ? servletContext : new MockServletContext()); + this.request = (request != null ? request : new MockHttpServletRequest(servletContext)); + this.response = (response != null ? response : new MockHttpServletResponse()); + this.servletConfig = (servletConfig != null ? servletConfig : new MockServletConfig(servletContext)); + } + + + public void initialize( + Servlet servlet, ServletRequest request, ServletResponse response, + String errorPageURL, boolean needsSession, int bufferSize, boolean autoFlush) { + + throw new UnsupportedOperationException("Use appropriate constructor"); + } + + public void release() { + } + + public void setAttribute(String name, Object value) { + Assert.notNull(name, "Attribute name must not be null"); + if (value != null) { + this.attributes.put(name, value); + } + else { + this.attributes.remove(name); + } + } + + public void setAttribute(String name, Object value, int scope) { + Assert.notNull(name, "Attribute name must not be null"); + switch (scope) { + case PAGE_SCOPE: + setAttribute(name, value); + break; + case REQUEST_SCOPE: + this.request.setAttribute(name, value); + break; + case SESSION_SCOPE: + this.request.getSession().setAttribute(name, value); + break; + case APPLICATION_SCOPE: + this.servletContext.setAttribute(name, value); + break; + default: + throw new IllegalArgumentException("Invalid scope: " + scope); + } + } + + public Object getAttribute(String name) { + Assert.notNull(name, "Attribute name must not be null"); + return this.attributes.get(name); + } + + public Object getAttribute(String name, int scope) { + Assert.notNull(name, "Attribute name must not be null"); + switch (scope) { + case PAGE_SCOPE: + return getAttribute(name); + case REQUEST_SCOPE: + return this.request.getAttribute(name); + case SESSION_SCOPE: + HttpSession session = this.request.getSession(false); + return (session != null ? session.getAttribute(name) : null); + case APPLICATION_SCOPE: + return this.servletContext.getAttribute(name); + default: + throw new IllegalArgumentException("Invalid scope: " + scope); + } + } + + public Object findAttribute(String name) { + Object value = getAttribute(name); + if (value == null) { + value = getAttribute(name, REQUEST_SCOPE); + if (value == null) { + value = getAttribute(name, SESSION_SCOPE); + if (value == null) { + value = getAttribute(name, APPLICATION_SCOPE); + } + } + } + return value; + } + + public void removeAttribute(String name) { + Assert.notNull(name, "Attribute name must not be null"); + this.removeAttribute(name, PageContext.PAGE_SCOPE); + this.removeAttribute(name, PageContext.REQUEST_SCOPE); + this.removeAttribute(name, PageContext.SESSION_SCOPE); + this.removeAttribute(name, PageContext.APPLICATION_SCOPE); + } + + public void removeAttribute(String name, int scope) { + Assert.notNull(name, "Attribute name must not be null"); + switch (scope) { + case PAGE_SCOPE: + this.attributes.remove(name); + break; + case REQUEST_SCOPE: + this.request.removeAttribute(name); + break; + case SESSION_SCOPE: + this.request.getSession().removeAttribute(name); + break; + case APPLICATION_SCOPE: + this.servletContext.removeAttribute(name); + break; + default: + throw new IllegalArgumentException("Invalid scope: " + scope); + } + } + + public int getAttributesScope(String name) { + if (getAttribute(name) != null) { + return PAGE_SCOPE; + } + else if (getAttribute(name, REQUEST_SCOPE) != null) { + return REQUEST_SCOPE; + } + else if (getAttribute(name, SESSION_SCOPE) != null) { + return SESSION_SCOPE; + } + else if (getAttribute(name, APPLICATION_SCOPE) != null) { + return APPLICATION_SCOPE; + } + else { + return 0; + } + } + + public Enumeration getAttributeNames() { + return Collections.enumeration(this.attributes.keySet()); + } + + @SuppressWarnings("unchecked") + public Enumeration getAttributeNamesInScope(int scope) { + switch (scope) { + case PAGE_SCOPE: + return getAttributeNames(); + case REQUEST_SCOPE: + return this.request.getAttributeNames(); + case SESSION_SCOPE: + HttpSession session = this.request.getSession(false); + return (session != null ? session.getAttributeNames() : null); + case APPLICATION_SCOPE: + return this.servletContext.getAttributeNames(); + default: + throw new IllegalArgumentException("Invalid scope: " + scope); + } + } + + public JspWriter getOut() { + if (this.out == null) { + this.out = new MockJspWriter(this.response); + } + return this.out; + } + + public ExpressionEvaluator getExpressionEvaluator() { + return new ExpressionEvaluator() { + public Expression parseExpression(String expression, Class expectedType, FunctionMapper fMapper) throws ELException { + throw new UnsupportedOperationException(); + } + public Object evaluate(String expression, Class expectedType, VariableResolver vResolver, FunctionMapper fMapper) throws ELException { + String key = expression.substring(2, expression.length() - 1); + return findAttribute(key); + } + }; + } + + public ELContext getELContext() { + return null; + } + + public VariableResolver getVariableResolver() { + return new VariableResolver() { + public Object resolveVariable(String pName) throws ELException { + if (pName.equals("pageContext")) { + return this; + } else { + return null; + } + } + }; + } + + public HttpSession getSession() { + return this.request.getSession(); + } + + public Object getPage() { + return this; + } + + public ServletRequest getRequest() { + return this.request; + } + + public ServletResponse getResponse() { + return this.response; + } + + public Exception getException() { + return null; + } + + public ServletConfig getServletConfig() { + return this.servletConfig; + } + + public ServletContext getServletContext() { + return this.servletContext; + } + + public void forward(String path) throws ServletException, IOException { + this.request.getRequestDispatcher(path).forward(this.request, this.response); + } + + public void include(String path) throws ServletException, IOException { + this.request.getRequestDispatcher(path).include(this.request, this.response); + } + + public void include(String path, boolean flush) throws ServletException, IOException { + this.request.getRequestDispatcher(path).include(this.request, this.response); + if (flush) { + this.response.flushBuffer(); + } + } + + public byte[] getContentAsByteArray() { + Assert.isTrue(this.response instanceof MockHttpServletResponse); + return ((MockHttpServletResponse) this.response).getContentAsByteArray(); + } + + public String getContentAsString() throws UnsupportedEncodingException { + Assert.isTrue(this.response instanceof MockHttpServletResponse); + return ((MockHttpServletResponse) this.response).getContentAsString(); + } + + public void handlePageException(Exception ex) throws ServletException, IOException { + throw new ServletException("Page exception", ex); + } + + public void handlePageException(Throwable ex) throws ServletException, IOException { + throw new ServletException("Page exception", ex); + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java index 396f0e7fd5..a87bea43c9 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java @@ -1,91 +1,91 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.util.Assert; - -/** - * Mock implementation of the {@link javax.servlet.RequestDispatcher} interface. - * - *

Used for testing the web framework; typically not necessary for - * testing application controllers. - * - * @author Rod Johnson - * @author Juergen Hoeller - * @since 1.0.2 - */ -public class MockRequestDispatcher implements RequestDispatcher { - - private final Log logger = LogFactory.getLog(getClass()); - - private final String url; - - - /** - * Create a new MockRequestDispatcher for the given URL. - * @param url the URL to dispatch to. - */ - public MockRequestDispatcher(String url) { - Assert.notNull(url, "URL must not be null"); - this.url = url; - } - - - public void forward(ServletRequest request, ServletResponse response) { - Assert.notNull(request, "Request must not be null"); - Assert.notNull(response, "Response must not be null"); - if (response.isCommitted()) { - throw new IllegalStateException("Cannot perform forward - response is already committed"); - } - getMockHttpServletResponse(response).setForwardedUrl(this.url); - if (logger.isDebugEnabled()) { - logger.debug("MockRequestDispatcher: forwarding to URL [" + this.url + "]"); - } - } - - public void include(ServletRequest request, ServletResponse response) { - Assert.notNull(request, "Request must not be null"); - Assert.notNull(response, "Response must not be null"); - getMockHttpServletResponse(response).addIncludedUrl(this.url); - if (logger.isDebugEnabled()) { - logger.debug("MockRequestDispatcher: including URL [" + this.url + "]"); - } - } - - /** - * Obtain the underlying MockHttpServletResponse, - * unwrapping {@link HttpServletResponseWrapper} decorators if necessary. - */ - protected MockHttpServletResponse getMockHttpServletResponse(ServletResponse response) { - if (response instanceof MockHttpServletResponse) { - return (MockHttpServletResponse) response; - } - if (response instanceof HttpServletResponseWrapper) { - return getMockHttpServletResponse(((HttpServletResponseWrapper) response).getResponse()); - } - throw new IllegalArgumentException("MockRequestDispatcher requires MockHttpServletResponse"); - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.util.Assert; + +/** + * Mock implementation of the {@link javax.servlet.RequestDispatcher} interface. + * + *

Used for testing the web framework; typically not necessary for + * testing application controllers. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @since 1.0.2 + */ +public class MockRequestDispatcher implements RequestDispatcher { + + private final Log logger = LogFactory.getLog(getClass()); + + private final String url; + + + /** + * Create a new MockRequestDispatcher for the given URL. + * @param url the URL to dispatch to. + */ + public MockRequestDispatcher(String url) { + Assert.notNull(url, "URL must not be null"); + this.url = url; + } + + + public void forward(ServletRequest request, ServletResponse response) { + Assert.notNull(request, "Request must not be null"); + Assert.notNull(response, "Response must not be null"); + if (response.isCommitted()) { + throw new IllegalStateException("Cannot perform forward - response is already committed"); + } + getMockHttpServletResponse(response).setForwardedUrl(this.url); + if (logger.isDebugEnabled()) { + logger.debug("MockRequestDispatcher: forwarding to URL [" + this.url + "]"); + } + } + + public void include(ServletRequest request, ServletResponse response) { + Assert.notNull(request, "Request must not be null"); + Assert.notNull(response, "Response must not be null"); + getMockHttpServletResponse(response).addIncludedUrl(this.url); + if (logger.isDebugEnabled()) { + logger.debug("MockRequestDispatcher: including URL [" + this.url + "]"); + } + } + + /** + * Obtain the underlying MockHttpServletResponse, + * unwrapping {@link HttpServletResponseWrapper} decorators if necessary. + */ + protected MockHttpServletResponse getMockHttpServletResponse(ServletResponse response) { + if (response instanceof MockHttpServletResponse) { + return (MockHttpServletResponse) response; + } + if (response instanceof HttpServletResponseWrapper) { + return getMockHttpServletResponse(((HttpServletResponseWrapper) response).getResponse()); + } + throw new IllegalArgumentException("MockRequestDispatcher requires MockHttpServletResponse"); + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockServletConfig.java b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockServletConfig.java index 7d67a6cd41..c62ec1520d 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockServletConfig.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockServletConfig.java @@ -1,103 +1,103 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import java.util.Collections; -import java.util.Enumeration; -import java.util.LinkedHashMap; -import java.util.Map; -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; - -import org.springframework.util.Assert; - -/** - * Mock implementation of the {@link javax.servlet.ServletConfig} interface. - * - *

Used for testing the web framework; typically not necessary for - * testing application controllers. - * - * @author Rod Johnson - * @author Juergen Hoeller - * @since 1.0.2 - */ -public class MockServletConfig implements ServletConfig { - - private final ServletContext servletContext; - - private final String servletName; - - private final Map initParameters = new LinkedHashMap(); - - - /** - * Create a new MockServletConfig with a default {@link MockServletContext}. - */ - public MockServletConfig() { - this(null, ""); - } - - /** - * Create a new MockServletConfig with a default {@link MockServletContext}. - * @param servletName the name of the servlet - */ - public MockServletConfig(String servletName) { - this(null, servletName); - } - - /** - * Create a new MockServletConfig. - * @param servletContext the ServletContext that the servlet runs in - */ - public MockServletConfig(ServletContext servletContext) { - this(servletContext, ""); - } - - /** - * Create a new MockServletConfig. - * @param servletContext the ServletContext that the servlet runs in - * @param servletName the name of the servlet - */ - public MockServletConfig(ServletContext servletContext, String servletName) { - this.servletContext = (servletContext != null ? servletContext : new MockServletContext()); - this.servletName = servletName; - } - - - public String getServletName() { - return this.servletName; - } - - public ServletContext getServletContext() { - return this.servletContext; - } - - public void addInitParameter(String name, String value) { - Assert.notNull(name, "Parameter name must not be null"); - this.initParameters.put(name, value); - } - - public String getInitParameter(String name) { - Assert.notNull(name, "Parameter name must not be null"); - return this.initParameters.get(name); - } - - public Enumeration getInitParameterNames() { - return Collections.enumeration(this.initParameters.keySet()); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.util.Collections; +import java.util.Enumeration; +import java.util.LinkedHashMap; +import java.util.Map; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; + +import org.springframework.util.Assert; + +/** + * Mock implementation of the {@link javax.servlet.ServletConfig} interface. + * + *

Used for testing the web framework; typically not necessary for + * testing application controllers. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @since 1.0.2 + */ +public class MockServletConfig implements ServletConfig { + + private final ServletContext servletContext; + + private final String servletName; + + private final Map initParameters = new LinkedHashMap(); + + + /** + * Create a new MockServletConfig with a default {@link MockServletContext}. + */ + public MockServletConfig() { + this(null, ""); + } + + /** + * Create a new MockServletConfig with a default {@link MockServletContext}. + * @param servletName the name of the servlet + */ + public MockServletConfig(String servletName) { + this(null, servletName); + } + + /** + * Create a new MockServletConfig. + * @param servletContext the ServletContext that the servlet runs in + */ + public MockServletConfig(ServletContext servletContext) { + this(servletContext, ""); + } + + /** + * Create a new MockServletConfig. + * @param servletContext the ServletContext that the servlet runs in + * @param servletName the name of the servlet + */ + public MockServletConfig(ServletContext servletContext, String servletName) { + this.servletContext = (servletContext != null ? servletContext : new MockServletContext()); + this.servletName = servletName; + } + + + public String getServletName() { + return this.servletName; + } + + public ServletContext getServletContext() { + return this.servletContext; + } + + public void addInitParameter(String name, String value) { + Assert.notNull(name, "Parameter name must not be null"); + this.initParameters.put(name, value); + } + + public String getInitParameter(String name) { + Assert.notNull(name, "Parameter name must not be null"); + return this.initParameters.get(name); + } + + public Enumeration getInitParameterNames() { + return Collections.enumeration(this.initParameters.keySet()); + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockServletContext.java b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockServletContext.java index 828b430e6c..3e340f463a 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockServletContext.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockServletContext.java @@ -1,492 +1,492 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Collections; -import java.util.Enumeration; -import java.util.EventListener; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; -import javax.activation.FileTypeMap; -import javax.servlet.Filter; -import javax.servlet.FilterRegistration; -import javax.servlet.FilterRegistration.Dynamic; -import javax.servlet.RequestDispatcher; -import javax.servlet.Servlet; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRegistration; -import javax.servlet.SessionCookieConfig; -import javax.servlet.SessionTrackingMode; -import javax.servlet.descriptor.JspConfigDescriptor; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.core.io.DefaultResourceLoader; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; -import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; -import org.springframework.web.util.WebUtils; - -/** - * Mock implementation of the {@link javax.servlet.ServletContext} interface. - * - *

Used for testing the Spring web framework; only rarely necessary for testing - * application controllers. As long as application components don't explicitly - * access the ServletContext, ClassPathXmlApplicationContext or - * FileSystemXmlApplicationContext can be used to load the context files for testing, - * even for DispatcherServlet context definitions. - * - *

For setting up a full WebApplicationContext in a test environment, you can - * use XmlWebApplicationContext (or GenericWebApplicationContext), passing in an - * appropriate MockServletContext instance. You might want to configure your - * MockServletContext with a FileSystemResourceLoader in that case, to make your - * resource paths interpreted as relative file system locations. - * - *

A common setup is to point your JVM working directory to the root of your - * web application directory, in combination with filesystem-based resource loading. - * This allows to load the context files as used in the web application, with - * relative paths getting interpreted correctly. Such a setup will work with both - * FileSystemXmlApplicationContext (which will load straight from the file system) - * and XmlWebApplicationContext with an underlying MockServletContext (as long as - * the MockServletContext has been configured with a FileSystemResourceLoader). - * - * Supports the Servlet 3.0 API level, but throws {@link UnsupportedOperationException} - * for all methods introduced in Servlet 3.0. - * - * @author Rod Johnson - * @author Juergen Hoeller - * @author Chris Beams - * @since 1.0.2 - * @see #MockServletContext(org.springframework.core.io.ResourceLoader) - * @see org.springframework.web.context.support.XmlWebApplicationContext - * @see org.springframework.web.context.support.GenericWebApplicationContext - * @see org.springframework.context.support.ClassPathXmlApplicationContext - * @see org.springframework.context.support.FileSystemXmlApplicationContext - */ -public class MockServletContext implements ServletContext { - - private static final String TEMP_DIR_SYSTEM_PROPERTY = "java.io.tmpdir"; - - - private final Log logger = LogFactory.getLog(getClass()); - - private final ResourceLoader resourceLoader; - - private final String resourceBasePath; - - private String contextPath = ""; - - private int minorVersion = 5; - - private final Map contexts = new HashMap(); - - private final Map initParameters = new LinkedHashMap(); - - private final Map attributes = new LinkedHashMap(); - - private String servletContextName = "MockServletContext"; - - - /** - * Create a new MockServletContext, using no base path and a - * DefaultResourceLoader (i.e. the classpath root as WAR root). - * @see org.springframework.core.io.DefaultResourceLoader - */ - public MockServletContext() { - this("", null); - } - - /** - * Create a new MockServletContext, using a DefaultResourceLoader. - * @param resourceBasePath the WAR root directory (should not end with a slash) - * @see org.springframework.core.io.DefaultResourceLoader - */ - public MockServletContext(String resourceBasePath) { - this(resourceBasePath, null); - } - - /** - * Create a new MockServletContext, using the specified ResourceLoader - * and no base path. - * @param resourceLoader the ResourceLoader to use (or null for the default) - */ - public MockServletContext(ResourceLoader resourceLoader) { - this("", resourceLoader); - } - - /** - * Create a new MockServletContext. - * @param resourceBasePath the WAR root directory (should not end with a slash) - * @param resourceLoader the ResourceLoader to use (or null for the default) - */ - public MockServletContext(String resourceBasePath, ResourceLoader resourceLoader) { - this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader()); - this.resourceBasePath = (resourceBasePath != null ? resourceBasePath : ""); - - // Use JVM temp dir as ServletContext temp dir. - String tempDir = System.getProperty(TEMP_DIR_SYSTEM_PROPERTY); - if (tempDir != null) { - this.attributes.put(WebUtils.TEMP_DIR_CONTEXT_ATTRIBUTE, new File(tempDir)); - } - } - - - /** - * Build a full resource location for the given path, - * prepending the resource base path of this MockServletContext. - * @param path the path as specified - * @return the full resource path - */ - protected String getResourceLocation(String path) { - if (!path.startsWith("/")) { - path = "/" + path; - } - return this.resourceBasePath + path; - } - - - public void setContextPath(String contextPath) { - this.contextPath = (contextPath != null ? contextPath : ""); - } - - /* This is a Servlet API 2.5 method. */ - public String getContextPath() { - return this.contextPath; - } - - public void registerContext(String contextPath, ServletContext context) { - this.contexts.put(contextPath, context); - } - - public ServletContext getContext(String contextPath) { - if (this.contextPath.equals(contextPath)) { - return this; - } - return this.contexts.get(contextPath); - } - - public int getMajorVersion() { - return 2; - } - - public void setMinorVersion(int minorVersion) { - if (minorVersion < 3 || minorVersion > 5) { - throw new IllegalArgumentException("Only Servlet minor versions between 3 and 5 are supported"); - } - this.minorVersion = minorVersion; - } - - public int getMinorVersion() { - return this.minorVersion; - } - - public String getMimeType(String filePath) { - return MimeTypeResolver.getMimeType(filePath); - } - - public Set getResourcePaths(String path) { - String actualPath = (path.endsWith("/") ? path : path + "/"); - Resource resource = this.resourceLoader.getResource(getResourceLocation(actualPath)); - try { - File file = resource.getFile(); - String[] fileList = file.list(); - if (ObjectUtils.isEmpty(fileList)) { - return null; - } - Set resourcePaths = new LinkedHashSet(fileList.length); - for (String fileEntry : fileList) { - String resultPath = actualPath + fileEntry; - if (resource.createRelative(fileEntry).getFile().isDirectory()) { - resultPath += "/"; - } - resourcePaths.add(resultPath); - } - return resourcePaths; - } - catch (IOException ex) { - logger.warn("Couldn't get resource paths for " + resource, ex); - return null; - } - } - - public URL getResource(String path) throws MalformedURLException { - Resource resource = this.resourceLoader.getResource(getResourceLocation(path)); - if (!resource.exists()) { - return null; - } - try { - return resource.getURL(); - } - catch (MalformedURLException ex) { - throw ex; - } - catch (IOException ex) { - logger.warn("Couldn't get URL for " + resource, ex); - return null; - } - } - - public InputStream getResourceAsStream(String path) { - Resource resource = this.resourceLoader.getResource(getResourceLocation(path)); - if (!resource.exists()) { - return null; - } - try { - return resource.getInputStream(); - } - catch (IOException ex) { - logger.warn("Couldn't open InputStream for " + resource, ex); - return null; - } - } - - public RequestDispatcher getRequestDispatcher(String path) { - if (!path.startsWith("/")) { - throw new IllegalArgumentException("RequestDispatcher path at ServletContext level must start with '/'"); - } - return new MockRequestDispatcher(path); - } - - public RequestDispatcher getNamedDispatcher(String path) { - return null; - } - - public Servlet getServlet(String name) { - return null; - } - - public Enumeration getServlets() { - return Collections.enumeration(new HashSet()); - } - - public Enumeration getServletNames() { - return Collections.enumeration(new HashSet()); - } - - public void log(String message) { - logger.info(message); - } - - public void log(Exception ex, String message) { - logger.info(message, ex); - } - - public void log(String message, Throwable ex) { - logger.info(message, ex); - } - - public String getRealPath(String path) { - Resource resource = this.resourceLoader.getResource(getResourceLocation(path)); - try { - return resource.getFile().getAbsolutePath(); - } - catch (IOException ex) { - logger.warn("Couldn't determine real path of resource " + resource, ex); - return null; - } - } - - public String getServerInfo() { - return "MockServletContext"; - } - - public String getInitParameter(String name) { - Assert.notNull(name, "Parameter name must not be null"); - return this.initParameters.get(name); - } - - public void addInitParameter(String name, String value) { - Assert.notNull(name, "Parameter name must not be null"); - this.initParameters.put(name, value); - } - - public Enumeration getInitParameterNames() { - return Collections.enumeration(this.initParameters.keySet()); - } - - public Object getAttribute(String name) { - Assert.notNull(name, "Attribute name must not be null"); - return this.attributes.get(name); - } - - public Enumeration getAttributeNames() { - return Collections.enumeration(this.attributes.keySet()); - } - - public void setAttribute(String name, Object value) { - Assert.notNull(name, "Attribute name must not be null"); - if (value != null) { - this.attributes.put(name, value); - } - else { - this.attributes.remove(name); - } - } - - public void removeAttribute(String name) { - Assert.notNull(name, "Attribute name must not be null"); - this.attributes.remove(name); - } - - public void setServletContextName(String servletContextName) { - this.servletContextName = servletContextName; - } - - public String getServletContextName() { - return this.servletContextName; - } - - - /** - * Inner factory class used to just introduce a Java Activation Framework - * dependency when actually asked to resolve a MIME type. - */ - private static class MimeTypeResolver { - - public static String getMimeType(String filePath) { - return FileTypeMap.getDefaultFileTypeMap().getContentType(filePath); - } - } - - - //--------------------------------------------------------------------- - // Methods introduced in Servlet 3.0 - //--------------------------------------------------------------------- - - public Dynamic addFilter(String arg0, String arg1) { - throw new UnsupportedOperationException(); - } - - public Dynamic addFilter(String arg0, Filter arg1) { - throw new UnsupportedOperationException(); - } - - public Dynamic addFilter(String arg0, Class arg1) { - throw new UnsupportedOperationException(); - } - - public void addListener(Class arg0) { - throw new UnsupportedOperationException(); - } - - public void addListener(String arg0) { - throw new UnsupportedOperationException(); - } - - public void addListener(T arg0) { - throw new UnsupportedOperationException(); - } - - public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, String arg1) { - throw new UnsupportedOperationException(); - } - - public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, - Servlet arg1) { - throw new UnsupportedOperationException(); - } - - public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, - Class arg1) { - throw new UnsupportedOperationException(); - } - - public T createFilter(Class arg0) - throws ServletException { - throw new UnsupportedOperationException(); - } - - public T createListener(Class arg0) - throws ServletException { - throw new UnsupportedOperationException(); - } - - public T createServlet(Class arg0) - throws ServletException { - throw new UnsupportedOperationException(); - } - - public void declareRoles(String... arg0) { - throw new UnsupportedOperationException(); - } - - public ClassLoader getClassLoader() { - throw new UnsupportedOperationException(); - } - - public Set getDefaultSessionTrackingModes() { - throw new UnsupportedOperationException(); - } - - public int getEffectiveMajorVersion() { - throw new UnsupportedOperationException(); - } - - public int getEffectiveMinorVersion() { - throw new UnsupportedOperationException(); - } - - public Set getEffectiveSessionTrackingModes() { - throw new UnsupportedOperationException(); - } - - public FilterRegistration getFilterRegistration(String arg0) { - throw new UnsupportedOperationException(); - } - - public Map getFilterRegistrations() { - throw new UnsupportedOperationException(); - } - - public JspConfigDescriptor getJspConfigDescriptor() { - throw new UnsupportedOperationException(); - } - - public ServletRegistration getServletRegistration(String arg0) { - throw new UnsupportedOperationException(); - } - - public Map getServletRegistrations() { - throw new UnsupportedOperationException(); - } - - public SessionCookieConfig getSessionCookieConfig() { - throw new UnsupportedOperationException(); - } - - public boolean setInitParameter(String arg0, String arg1) { - throw new UnsupportedOperationException(); - } - - public void setSessionTrackingModes(Set arg0) - throws IllegalStateException, IllegalArgumentException { - throw new UnsupportedOperationException(); - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import java.util.EventListener; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import javax.activation.FileTypeMap; +import javax.servlet.Filter; +import javax.servlet.FilterRegistration; +import javax.servlet.FilterRegistration.Dynamic; +import javax.servlet.RequestDispatcher; +import javax.servlet.Servlet; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; +import javax.servlet.SessionCookieConfig; +import javax.servlet.SessionTrackingMode; +import javax.servlet.descriptor.JspConfigDescriptor; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; +import org.springframework.web.util.WebUtils; + +/** + * Mock implementation of the {@link javax.servlet.ServletContext} interface. + * + *

Used for testing the Spring web framework; only rarely necessary for testing + * application controllers. As long as application components don't explicitly + * access the ServletContext, ClassPathXmlApplicationContext or + * FileSystemXmlApplicationContext can be used to load the context files for testing, + * even for DispatcherServlet context definitions. + * + *

For setting up a full WebApplicationContext in a test environment, you can + * use XmlWebApplicationContext (or GenericWebApplicationContext), passing in an + * appropriate MockServletContext instance. You might want to configure your + * MockServletContext with a FileSystemResourceLoader in that case, to make your + * resource paths interpreted as relative file system locations. + * + *

A common setup is to point your JVM working directory to the root of your + * web application directory, in combination with filesystem-based resource loading. + * This allows to load the context files as used in the web application, with + * relative paths getting interpreted correctly. Such a setup will work with both + * FileSystemXmlApplicationContext (which will load straight from the file system) + * and XmlWebApplicationContext with an underlying MockServletContext (as long as + * the MockServletContext has been configured with a FileSystemResourceLoader). + * + * Supports the Servlet 3.0 API level, but throws {@link UnsupportedOperationException} + * for all methods introduced in Servlet 3.0. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @author Chris Beams + * @since 1.0.2 + * @see #MockServletContext(org.springframework.core.io.ResourceLoader) + * @see org.springframework.web.context.support.XmlWebApplicationContext + * @see org.springframework.web.context.support.GenericWebApplicationContext + * @see org.springframework.context.support.ClassPathXmlApplicationContext + * @see org.springframework.context.support.FileSystemXmlApplicationContext + */ +public class MockServletContext implements ServletContext { + + private static final String TEMP_DIR_SYSTEM_PROPERTY = "java.io.tmpdir"; + + + private final Log logger = LogFactory.getLog(getClass()); + + private final ResourceLoader resourceLoader; + + private final String resourceBasePath; + + private String contextPath = ""; + + private int minorVersion = 5; + + private final Map contexts = new HashMap(); + + private final Map initParameters = new LinkedHashMap(); + + private final Map attributes = new LinkedHashMap(); + + private String servletContextName = "MockServletContext"; + + + /** + * Create a new MockServletContext, using no base path and a + * DefaultResourceLoader (i.e. the classpath root as WAR root). + * @see org.springframework.core.io.DefaultResourceLoader + */ + public MockServletContext() { + this("", null); + } + + /** + * Create a new MockServletContext, using a DefaultResourceLoader. + * @param resourceBasePath the WAR root directory (should not end with a slash) + * @see org.springframework.core.io.DefaultResourceLoader + */ + public MockServletContext(String resourceBasePath) { + this(resourceBasePath, null); + } + + /** + * Create a new MockServletContext, using the specified ResourceLoader + * and no base path. + * @param resourceLoader the ResourceLoader to use (or null for the default) + */ + public MockServletContext(ResourceLoader resourceLoader) { + this("", resourceLoader); + } + + /** + * Create a new MockServletContext. + * @param resourceBasePath the WAR root directory (should not end with a slash) + * @param resourceLoader the ResourceLoader to use (or null for the default) + */ + public MockServletContext(String resourceBasePath, ResourceLoader resourceLoader) { + this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader()); + this.resourceBasePath = (resourceBasePath != null ? resourceBasePath : ""); + + // Use JVM temp dir as ServletContext temp dir. + String tempDir = System.getProperty(TEMP_DIR_SYSTEM_PROPERTY); + if (tempDir != null) { + this.attributes.put(WebUtils.TEMP_DIR_CONTEXT_ATTRIBUTE, new File(tempDir)); + } + } + + + /** + * Build a full resource location for the given path, + * prepending the resource base path of this MockServletContext. + * @param path the path as specified + * @return the full resource path + */ + protected String getResourceLocation(String path) { + if (!path.startsWith("/")) { + path = "/" + path; + } + return this.resourceBasePath + path; + } + + + public void setContextPath(String contextPath) { + this.contextPath = (contextPath != null ? contextPath : ""); + } + + /* This is a Servlet API 2.5 method. */ + public String getContextPath() { + return this.contextPath; + } + + public void registerContext(String contextPath, ServletContext context) { + this.contexts.put(contextPath, context); + } + + public ServletContext getContext(String contextPath) { + if (this.contextPath.equals(contextPath)) { + return this; + } + return this.contexts.get(contextPath); + } + + public int getMajorVersion() { + return 2; + } + + public void setMinorVersion(int minorVersion) { + if (minorVersion < 3 || minorVersion > 5) { + throw new IllegalArgumentException("Only Servlet minor versions between 3 and 5 are supported"); + } + this.minorVersion = minorVersion; + } + + public int getMinorVersion() { + return this.minorVersion; + } + + public String getMimeType(String filePath) { + return MimeTypeResolver.getMimeType(filePath); + } + + public Set getResourcePaths(String path) { + String actualPath = (path.endsWith("/") ? path : path + "/"); + Resource resource = this.resourceLoader.getResource(getResourceLocation(actualPath)); + try { + File file = resource.getFile(); + String[] fileList = file.list(); + if (ObjectUtils.isEmpty(fileList)) { + return null; + } + Set resourcePaths = new LinkedHashSet(fileList.length); + for (String fileEntry : fileList) { + String resultPath = actualPath + fileEntry; + if (resource.createRelative(fileEntry).getFile().isDirectory()) { + resultPath += "/"; + } + resourcePaths.add(resultPath); + } + return resourcePaths; + } + catch (IOException ex) { + logger.warn("Couldn't get resource paths for " + resource, ex); + return null; + } + } + + public URL getResource(String path) throws MalformedURLException { + Resource resource = this.resourceLoader.getResource(getResourceLocation(path)); + if (!resource.exists()) { + return null; + } + try { + return resource.getURL(); + } + catch (MalformedURLException ex) { + throw ex; + } + catch (IOException ex) { + logger.warn("Couldn't get URL for " + resource, ex); + return null; + } + } + + public InputStream getResourceAsStream(String path) { + Resource resource = this.resourceLoader.getResource(getResourceLocation(path)); + if (!resource.exists()) { + return null; + } + try { + return resource.getInputStream(); + } + catch (IOException ex) { + logger.warn("Couldn't open InputStream for " + resource, ex); + return null; + } + } + + public RequestDispatcher getRequestDispatcher(String path) { + if (!path.startsWith("/")) { + throw new IllegalArgumentException("RequestDispatcher path at ServletContext level must start with '/'"); + } + return new MockRequestDispatcher(path); + } + + public RequestDispatcher getNamedDispatcher(String path) { + return null; + } + + public Servlet getServlet(String name) { + return null; + } + + public Enumeration getServlets() { + return Collections.enumeration(new HashSet()); + } + + public Enumeration getServletNames() { + return Collections.enumeration(new HashSet()); + } + + public void log(String message) { + logger.info(message); + } + + public void log(Exception ex, String message) { + logger.info(message, ex); + } + + public void log(String message, Throwable ex) { + logger.info(message, ex); + } + + public String getRealPath(String path) { + Resource resource = this.resourceLoader.getResource(getResourceLocation(path)); + try { + return resource.getFile().getAbsolutePath(); + } + catch (IOException ex) { + logger.warn("Couldn't determine real path of resource " + resource, ex); + return null; + } + } + + public String getServerInfo() { + return "MockServletContext"; + } + + public String getInitParameter(String name) { + Assert.notNull(name, "Parameter name must not be null"); + return this.initParameters.get(name); + } + + public void addInitParameter(String name, String value) { + Assert.notNull(name, "Parameter name must not be null"); + this.initParameters.put(name, value); + } + + public Enumeration getInitParameterNames() { + return Collections.enumeration(this.initParameters.keySet()); + } + + public Object getAttribute(String name) { + Assert.notNull(name, "Attribute name must not be null"); + return this.attributes.get(name); + } + + public Enumeration getAttributeNames() { + return Collections.enumeration(this.attributes.keySet()); + } + + public void setAttribute(String name, Object value) { + Assert.notNull(name, "Attribute name must not be null"); + if (value != null) { + this.attributes.put(name, value); + } + else { + this.attributes.remove(name); + } + } + + public void removeAttribute(String name) { + Assert.notNull(name, "Attribute name must not be null"); + this.attributes.remove(name); + } + + public void setServletContextName(String servletContextName) { + this.servletContextName = servletContextName; + } + + public String getServletContextName() { + return this.servletContextName; + } + + + /** + * Inner factory class used to just introduce a Java Activation Framework + * dependency when actually asked to resolve a MIME type. + */ + private static class MimeTypeResolver { + + public static String getMimeType(String filePath) { + return FileTypeMap.getDefaultFileTypeMap().getContentType(filePath); + } + } + + + //--------------------------------------------------------------------- + // Methods introduced in Servlet 3.0 + //--------------------------------------------------------------------- + + public Dynamic addFilter(String arg0, String arg1) { + throw new UnsupportedOperationException(); + } + + public Dynamic addFilter(String arg0, Filter arg1) { + throw new UnsupportedOperationException(); + } + + public Dynamic addFilter(String arg0, Class arg1) { + throw new UnsupportedOperationException(); + } + + public void addListener(Class arg0) { + throw new UnsupportedOperationException(); + } + + public void addListener(String arg0) { + throw new UnsupportedOperationException(); + } + + public void addListener(T arg0) { + throw new UnsupportedOperationException(); + } + + public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, String arg1) { + throw new UnsupportedOperationException(); + } + + public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, + Servlet arg1) { + throw new UnsupportedOperationException(); + } + + public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, + Class arg1) { + throw new UnsupportedOperationException(); + } + + public T createFilter(Class arg0) + throws ServletException { + throw new UnsupportedOperationException(); + } + + public T createListener(Class arg0) + throws ServletException { + throw new UnsupportedOperationException(); + } + + public T createServlet(Class arg0) + throws ServletException { + throw new UnsupportedOperationException(); + } + + public void declareRoles(String... arg0) { + throw new UnsupportedOperationException(); + } + + public ClassLoader getClassLoader() { + throw new UnsupportedOperationException(); + } + + public Set getDefaultSessionTrackingModes() { + throw new UnsupportedOperationException(); + } + + public int getEffectiveMajorVersion() { + throw new UnsupportedOperationException(); + } + + public int getEffectiveMinorVersion() { + throw new UnsupportedOperationException(); + } + + public Set getEffectiveSessionTrackingModes() { + throw new UnsupportedOperationException(); + } + + public FilterRegistration getFilterRegistration(String arg0) { + throw new UnsupportedOperationException(); + } + + public Map getFilterRegistrations() { + throw new UnsupportedOperationException(); + } + + public JspConfigDescriptor getJspConfigDescriptor() { + throw new UnsupportedOperationException(); + } + + public ServletRegistration getServletRegistration(String arg0) { + throw new UnsupportedOperationException(); + } + + public Map getServletRegistrations() { + throw new UnsupportedOperationException(); + } + + public SessionCookieConfig getSessionCookieConfig() { + throw new UnsupportedOperationException(); + } + + public boolean setInitParameter(String arg0, String arg1) { + throw new UnsupportedOperationException(); + } + + public void setSessionTrackingModes(Set arg0) + throws IllegalStateException, IllegalArgumentException { + throw new UnsupportedOperationException(); + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/util/SerializationTestUtils.java b/org.springframework.web.servlet/src/test/java/org/springframework/util/SerializationTestUtils.java index d920a3b4ff..9ae4f54ec2 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/util/SerializationTestUtils.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/util/SerializationTestUtils.java @@ -1,65 +1,65 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.util; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.NotSerializableException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.OutputStream; - -/** - * Utilities for testing serializability of objects. - * Exposes static methods for use in other test cases. - * - * @author Rod Johnson - */ -public class SerializationTestUtils { - - public static void testSerialization(Object o) throws IOException { - OutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(o); - } - - public static boolean isSerializable(Object o) throws IOException { - try { - testSerialization(o); - return true; - } - catch (NotSerializableException ex) { - return false; - } - } - - public static Object serializeAndDeserialize(Object o) throws IOException, ClassNotFoundException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(o); - oos.flush(); - baos.flush(); - byte[] bytes = baos.toByteArray(); - - ByteArrayInputStream is = new ByteArrayInputStream(bytes); - ObjectInputStream ois = new ObjectInputStream(is); - Object o2 = ois.readObject(); - return o2; - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.NotSerializableException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; + +/** + * Utilities for testing serializability of objects. + * Exposes static methods for use in other test cases. + * + * @author Rod Johnson + */ +public class SerializationTestUtils { + + public static void testSerialization(Object o) throws IOException { + OutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(o); + } + + public static boolean isSerializable(Object o) throws IOException { + try { + testSerialization(o); + return true; + } + catch (NotSerializableException ex) { + return false; + } + } + + public static Object serializeAndDeserialize(Object o) throws IOException, ClassNotFoundException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(o); + oos.flush(); + baos.flush(); + byte[] bytes = baos.toByteArray(); + + ByteArrayInputStream is = new ByteArrayInputStream(bytes); + ObjectInputStream ois = new ObjectInputStream(is); + Object o2 = ois.readObject(); + return o2; + } + +} diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/tiles2/TilesConfigurerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/tiles2/TilesConfigurerTests.java index 341b98eb59..3c9045b32f 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/tiles2/TilesConfigurerTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/tiles2/TilesConfigurerTests.java @@ -1,52 +1,52 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.servlet.view.tiles2; - -import org.apache.tiles.context.TilesRequestContext; -import org.apache.tiles.impl.BasicTilesContainer; -import org.apache.tiles.servlet.context.ServletTilesRequestContext; -import org.apache.tiles.servlet.context.ServletUtil; -import static org.junit.Assert.*; -import org.junit.Test; - -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; -import org.springframework.mock.web.MockServletContext; - -/** - * @author Juergen Hoeller - * */ -public class TilesConfigurerTests { - - @Test - public void simpleBootstrap() { - MockServletContext sc = new MockServletContext(); - TilesConfigurer tc = new TilesConfigurer(); - tc.setDefinitions(new String[] {"/org/springframework/web/servlet/view/tiles2/tiles-definitions.xml"}); - tc.setCheckRefresh(true); - tc.setServletContext(sc); - tc.afterPropertiesSet(); - - BasicTilesContainer container = (BasicTilesContainer) ServletUtil.getContainer(sc); - TilesRequestContext requestContext = new ServletTilesRequestContext( - container.getApplicationContext(), new MockHttpServletRequest(), new MockHttpServletResponse()); - assertNotNull(container.getDefinitionsFactory().getDefinition("test", requestContext)); - - tc.destroy(); - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.servlet.view.tiles2; + +import org.apache.tiles.context.TilesRequestContext; +import org.apache.tiles.impl.BasicTilesContainer; +import org.apache.tiles.servlet.context.ServletTilesRequestContext; +import org.apache.tiles.servlet.context.ServletUtil; +import static org.junit.Assert.*; +import org.junit.Test; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletContext; + +/** + * @author Juergen Hoeller + * */ +public class TilesConfigurerTests { + + @Test + public void simpleBootstrap() { + MockServletContext sc = new MockServletContext(); + TilesConfigurer tc = new TilesConfigurer(); + tc.setDefinitions(new String[] {"/org/springframework/web/servlet/view/tiles2/tiles-definitions.xml"}); + tc.setCheckRefresh(true); + tc.setServletContext(sc); + tc.afterPropertiesSet(); + + BasicTilesContainer container = (BasicTilesContainer) ServletUtil.getContainer(sc); + TilesRequestContext requestContext = new ServletTilesRequestContext( + container.getApplicationContext(), new MockHttpServletRequest(), new MockHttpServletResponse()); + assertNotNull(container.getDefinitionsFactory().getDefinition("test", requestContext)); + + tc.destroy(); + } + +} diff --git a/org.springframework.web/src/main/java/org/springframework/http/MediaTypeEditor.java b/org.springframework.web/src/main/java/org/springframework/http/MediaTypeEditor.java index 1ae84df853..be3f73c37a 100644 --- a/org.springframework.web/src/main/java/org/springframework/http/MediaTypeEditor.java +++ b/org.springframework.web/src/main/java/org/springframework/http/MediaTypeEditor.java @@ -1,50 +1,50 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.http; - -import java.beans.PropertyEditorSupport; - -import org.springframework.util.StringUtils; - -/** - * {@link java.beans.PropertyEditor Editor} for {@link MediaType} - * descriptors, to automatically convert String specifications - * (e.g. "text/html") to MediaType properties. - * - * @author Juergen Hoeller - * @since 3.0 - * @see MediaType - */ -public class MediaTypeEditor extends PropertyEditorSupport { - - @Override - public void setAsText(String text) { - if (StringUtils.hasText(text)) { - setValue(MediaType.parseMediaType(text)); - } - else { - setValue(null); - } - } - - @Override - public String getAsText() { - MediaType mediaType = (MediaType) getValue(); - return (mediaType != null ? mediaType.toString() : ""); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.http; + +import java.beans.PropertyEditorSupport; + +import org.springframework.util.StringUtils; + +/** + * {@link java.beans.PropertyEditor Editor} for {@link MediaType} + * descriptors, to automatically convert String specifications + * (e.g. "text/html") to MediaType properties. + * + * @author Juergen Hoeller + * @since 3.0 + * @see MediaType + */ +public class MediaTypeEditor extends PropertyEditorSupport { + + @Override + public void setAsText(String text) { + if (StringUtils.hasText(text)) { + setValue(MediaType.parseMediaType(text)); + } + else { + setValue(null); + } + } + + @Override + public String getAsText() { + MediaType mediaType = (MediaType) getValue(); + return (mediaType != null ? mediaType.toString() : ""); + } + +} diff --git a/org.springframework.web/src/main/java/org/springframework/http/converter/xml/XmlAwareFormHttpMessageConverter.java b/org.springframework.web/src/main/java/org/springframework/http/converter/xml/XmlAwareFormHttpMessageConverter.java index 0db64e2b87..788fc13241 100644 --- a/org.springframework.web/src/main/java/org/springframework/http/converter/xml/XmlAwareFormHttpMessageConverter.java +++ b/org.springframework.web/src/main/java/org/springframework/http/converter/xml/XmlAwareFormHttpMessageConverter.java @@ -1,35 +1,35 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.http.converter.xml; - -import org.springframework.http.converter.FormHttpMessageConverter; - -/** - * Extension of {@link org.springframework.http.converter.FormHttpMessageConverter}, - * adding support for XML-based parts through a {@link SourceHttpMessageConverter}. - * - * @author Juergen Hoeller - * @since 3.0.3 - */ -public class XmlAwareFormHttpMessageConverter extends FormHttpMessageConverter { - - public XmlAwareFormHttpMessageConverter() { - super(); - addPartConverter(new SourceHttpMessageConverter()); - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.http.converter.xml; + +import org.springframework.http.converter.FormHttpMessageConverter; + +/** + * Extension of {@link org.springframework.http.converter.FormHttpMessageConverter}, + * adding support for XML-based parts through a {@link SourceHttpMessageConverter}. + * + * @author Juergen Hoeller + * @since 3.0.3 + */ +public class XmlAwareFormHttpMessageConverter extends FormHttpMessageConverter { + + public XmlAwareFormHttpMessageConverter() { + super(); + addPartConverter(new SourceHttpMessageConverter()); + } + +} diff --git a/org.springframework.web/src/main/java/org/springframework/web/bind/UnsatisfiedServletRequestParameterException.java b/org.springframework.web/src/main/java/org/springframework/web/bind/UnsatisfiedServletRequestParameterException.java index 8cd7d019bc..c067b432ee 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/bind/UnsatisfiedServletRequestParameterException.java +++ b/org.springframework.web/src/main/java/org/springframework/web/bind/UnsatisfiedServletRequestParameterException.java @@ -1,88 +1,88 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.bind; - -import java.util.Iterator; -import java.util.Map; - -import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; - -/** - * {@link ServletRequestBindingException} subclass that indicates an unsatisfied - * parameter condition, as typically expressed using an @RequestMapping - * annotation at the @Controller type level. - * - * @author Juergen Hoeller - * @since 3.0 - * @see org.springframework.web.bind.annotation.RequestMapping#params() - */ -public class UnsatisfiedServletRequestParameterException extends ServletRequestBindingException { - - private final String[] paramConditions; - - private final Map actualParams; - - - /** - * Create a new UnsatisfiedServletRequestParameterException. - * @param paramConditions the parameter conditions that have been violated - * @param actualParams the actual parameter Map associated with the ServletRequest - */ - @SuppressWarnings("unchecked") - public UnsatisfiedServletRequestParameterException(String[] paramConditions, Map actualParams) { - super(""); - this.paramConditions = paramConditions; - this.actualParams = (Map) actualParams; - } - - - @Override - public String getMessage() { - return "Parameter conditions \"" + StringUtils.arrayToDelimitedString(this.paramConditions, ", ") + - "\" not met for actual request parameters: " + requestParameterMapToString(this.actualParams); - } - - private static String requestParameterMapToString(Map actualParams) { - StringBuilder result = new StringBuilder(); - for (Iterator> it = actualParams.entrySet().iterator(); it.hasNext();) { - Map.Entry entry = it.next(); - result.append(entry.getKey()).append('=').append(ObjectUtils.nullSafeToString(entry.getValue())); - if (it.hasNext()) { - result.append(", "); - } - } - return result.toString(); - } - - /** - * Return the parameter conditions that have been violated. - * @see org.springframework.web.bind.annotation.RequestMapping#params() - */ - public final String[] getParamConditions() { - return this.paramConditions; - } - - /** - * Return the actual parameter Map associated with the ServletRequest. - * @see javax.servlet.ServletRequest#getParameterMap() - */ - public final Map getActualParams() { - return this.actualParams; - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.bind; + +import java.util.Iterator; +import java.util.Map; + +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; + +/** + * {@link ServletRequestBindingException} subclass that indicates an unsatisfied + * parameter condition, as typically expressed using an @RequestMapping + * annotation at the @Controller type level. + * + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.web.bind.annotation.RequestMapping#params() + */ +public class UnsatisfiedServletRequestParameterException extends ServletRequestBindingException { + + private final String[] paramConditions; + + private final Map actualParams; + + + /** + * Create a new UnsatisfiedServletRequestParameterException. + * @param paramConditions the parameter conditions that have been violated + * @param actualParams the actual parameter Map associated with the ServletRequest + */ + @SuppressWarnings("unchecked") + public UnsatisfiedServletRequestParameterException(String[] paramConditions, Map actualParams) { + super(""); + this.paramConditions = paramConditions; + this.actualParams = (Map) actualParams; + } + + + @Override + public String getMessage() { + return "Parameter conditions \"" + StringUtils.arrayToDelimitedString(this.paramConditions, ", ") + + "\" not met for actual request parameters: " + requestParameterMapToString(this.actualParams); + } + + private static String requestParameterMapToString(Map actualParams) { + StringBuilder result = new StringBuilder(); + for (Iterator> it = actualParams.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = it.next(); + result.append(entry.getKey()).append('=').append(ObjectUtils.nullSafeToString(entry.getValue())); + if (it.hasNext()) { + result.append(", "); + } + } + return result.toString(); + } + + /** + * Return the parameter conditions that have been violated. + * @see org.springframework.web.bind.annotation.RequestMapping#params() + */ + public final String[] getParamConditions() { + return this.paramConditions; + } + + /** + * Return the actual parameter Map associated with the ServletRequest. + * @see javax.servlet.ServletRequest#getParameterMap() + */ + public final Map getActualParams() { + return this.actualParams; + } + +} diff --git a/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/Mapping.java b/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/Mapping.java index afbd1f2e72..020d497321 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/Mapping.java +++ b/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/Mapping.java @@ -1,35 +1,35 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.bind.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Meta annotation that indicates a web mapping annotation. - * - * @author Juergen Hoeller - * @since 3.0 - * @see RequestMapping - */ -@Target({ElementType.ANNOTATION_TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface Mapping { - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.bind.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Meta annotation that indicates a web mapping annotation. + * + * @author Juergen Hoeller + * @since 3.0 + * @see RequestMapping + */ +@Target({ElementType.ANNOTATION_TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Mapping { + +} diff --git a/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/ValueConstants.java b/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/ValueConstants.java index e7f9c1a132..a5095f296e 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/ValueConstants.java +++ b/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/ValueConstants.java @@ -1,38 +1,38 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.bind.annotation; - -/** - * Common value constants shared between bind annotations. - * - * @author Juergen Hoeller - * @since 3.0.1 - */ -public interface ValueConstants { - - /** - * Constant defining a value for no default - as a replacement for - * null which we cannot use in annotation attributes. - *

This is an artificial arrangement of 16 unicode characters, - * with its sole purpose being to never match user-declared values. - * @see RequestParam#defaultValue() - * @see RequestHeader#defaultValue() - * @see CookieValue#defaultValue() - */ - String DEFAULT_NONE = "\n\t\t\n\t\t\n\uE000\uE001\uE002\n\t\t\t\t\n"; - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.bind.annotation; + +/** + * Common value constants shared between bind annotations. + * + * @author Juergen Hoeller + * @since 3.0.1 + */ +public interface ValueConstants { + + /** + * Constant defining a value for no default - as a replacement for + * null which we cannot use in annotation attributes. + *

This is an artificial arrangement of 16 unicode characters, + * with its sole purpose being to never match user-declared values. + * @see RequestParam#defaultValue() + * @see RequestHeader#defaultValue() + * @see CookieValue#defaultValue() + */ + String DEFAULT_NONE = "\n\t\t\n\t\t\n\uE000\uE001\uE002\n\t\t\t\t\n"; + +} diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/ContextCleanupListener.java b/org.springframework.web/src/main/java/org/springframework/web/context/ContextCleanupListener.java index 71db226277..4dc269a1b4 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/context/ContextCleanupListener.java +++ b/org.springframework.web/src/main/java/org/springframework/web/context/ContextCleanupListener.java @@ -1,77 +1,77 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.context; - -import java.util.Enumeration; -import javax.servlet.ServletContext; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.beans.factory.DisposableBean; - -/** - * Web application listener that cleans up remaining disposable attributes - * in the ServletContext, i.e. attributes which implement {@link DisposableBean} - * and haven't been removed before. This is typically used for destroying objects - * in "application" scope, for which the lifecycle implies destruction at the - * very end of the web application's shutdown phase. - * - * @author Juergen Hoeller - * @since 3.0 - * @see org.springframework.web.context.support.ServletContextScope - * @see ContextLoaderListener - */ -public class ContextCleanupListener implements ServletContextListener { - - private static final Log logger = LogFactory.getLog(ContextCleanupListener.class); - - - public void contextInitialized(ServletContextEvent event) { - } - - public void contextDestroyed(ServletContextEvent event) { - cleanupAttributes(event.getServletContext()); - } - - - /** - * Find all ServletContext attributes which implement {@link DisposableBean} - * and destroy them, removing all affected ServletContext attributes eventually. - * @param sc the ServletContext to check - */ - static void cleanupAttributes(ServletContext sc) { - Enumeration attrNames = sc.getAttributeNames(); - while (attrNames.hasMoreElements()) { - String attrName = (String) attrNames.nextElement(); - if (attrName.startsWith("org.springframework.")) { - Object attrValue = sc.getAttribute(attrName); - if (attrValue instanceof DisposableBean) { - try { - ((DisposableBean) attrValue).destroy(); - } - catch (Throwable ex) { - logger.error("Couldn't invoke destroy method of attribute with name '" + attrName + "'", ex); - } - } - } - } - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context; + +import java.util.Enumeration; +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.factory.DisposableBean; + +/** + * Web application listener that cleans up remaining disposable attributes + * in the ServletContext, i.e. attributes which implement {@link DisposableBean} + * and haven't been removed before. This is typically used for destroying objects + * in "application" scope, for which the lifecycle implies destruction at the + * very end of the web application's shutdown phase. + * + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.web.context.support.ServletContextScope + * @see ContextLoaderListener + */ +public class ContextCleanupListener implements ServletContextListener { + + private static final Log logger = LogFactory.getLog(ContextCleanupListener.class); + + + public void contextInitialized(ServletContextEvent event) { + } + + public void contextDestroyed(ServletContextEvent event) { + cleanupAttributes(event.getServletContext()); + } + + + /** + * Find all ServletContext attributes which implement {@link DisposableBean} + * and destroy them, removing all affected ServletContext attributes eventually. + * @param sc the ServletContext to check + */ + static void cleanupAttributes(ServletContext sc) { + Enumeration attrNames = sc.getAttributeNames(); + while (attrNames.hasMoreElements()) { + String attrName = (String) attrNames.nextElement(); + if (attrName.startsWith("org.springframework.")) { + Object attrValue = sc.getAttribute(attrName); + if (attrValue instanceof DisposableBean) { + try { + ((DisposableBean) attrValue).destroy(); + } + catch (Throwable ex) { + logger.error("Couldn't invoke destroy method of attribute with name '" + attrName + "'", ex); + } + } + } + } + } + +} diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/request/DestructionCallbackBindingListener.java b/org.springframework.web/src/main/java/org/springframework/web/context/request/DestructionCallbackBindingListener.java index 2c64b07901..04789512aa 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/context/request/DestructionCallbackBindingListener.java +++ b/org.springframework.web/src/main/java/org/springframework/web/context/request/DestructionCallbackBindingListener.java @@ -1,54 +1,54 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.context.request; - -import java.io.Serializable; -import javax.servlet.http.HttpSessionBindingEvent; -import javax.servlet.http.HttpSessionBindingListener; - -/** - * Adapter that implements the Servlet 2.3 HttpSessionBindingListener - * interface, wrapping a session destruction callback. - * - * @author Juergen Hoeller - * @since 3.0 - * @see RequestAttributes#registerDestructionCallback - * @see ServletRequestAttributes#registerSessionDestructionCallback - */ -public class DestructionCallbackBindingListener implements HttpSessionBindingListener, Serializable { - - private final Runnable destructionCallback; - - - /** - * Create a new DestructionCallbackBindingListener for the given callback. - * @param destructionCallback the Runnable to execute when this listener - * object gets unbound from the session - */ - public DestructionCallbackBindingListener(Runnable destructionCallback) { - this.destructionCallback = destructionCallback; - } - - - public void valueBound(HttpSessionBindingEvent event) { - } - - public void valueUnbound(HttpSessionBindingEvent event) { - this.destructionCallback.run(); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context.request; + +import java.io.Serializable; +import javax.servlet.http.HttpSessionBindingEvent; +import javax.servlet.http.HttpSessionBindingListener; + +/** + * Adapter that implements the Servlet 2.3 HttpSessionBindingListener + * interface, wrapping a session destruction callback. + * + * @author Juergen Hoeller + * @since 3.0 + * @see RequestAttributes#registerDestructionCallback + * @see ServletRequestAttributes#registerSessionDestructionCallback + */ +public class DestructionCallbackBindingListener implements HttpSessionBindingListener, Serializable { + + private final Runnable destructionCallback; + + + /** + * Create a new DestructionCallbackBindingListener for the given callback. + * @param destructionCallback the Runnable to execute when this listener + * object gets unbound from the session + */ + public DestructionCallbackBindingListener(Runnable destructionCallback) { + this.destructionCallback = destructionCallback; + } + + + public void valueBound(HttpSessionBindingEvent event) { + } + + public void valueUnbound(HttpSessionBindingEvent event) { + this.destructionCallback.run(); + } + +} diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/support/ServletContextScope.java b/org.springframework.web/src/main/java/org/springframework/web/context/support/ServletContextScope.java index a4cc9fc814..90301719e4 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/context/support/ServletContextScope.java +++ b/org.springframework.web/src/main/java/org/springframework/web/context/support/ServletContextScope.java @@ -1,111 +1,111 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.context.support; - -import java.util.LinkedHashMap; -import java.util.Map; -import javax.servlet.ServletContext; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.ObjectFactory; -import org.springframework.beans.factory.config.Scope; -import org.springframework.util.Assert; - -/** - * {@link Scope} wrapper for a ServletContext, i.e. for global web application attributes. - * - *

This differs from traditional Spring singletons in that it exposes attributes in the - * ServletContext. Those attributes will get destroyed whenever the entire application - * shuts down, which might be earlier or later than the shutdown of the containing Spring - * ApplicationContext. - * - *

The associated destruction mechanism relies on a - * {@link org.springframework.web.context.ContextCleanupListener} being registered in - * web.xml. Note that {@link org.springframework.web.context.ContextLoaderListener} - * includes ContextCleanupListener's functionality. - * - *

This scope is registered as default scope with key - * {@link org.springframework.web.context.WebApplicationContext#SCOPE_APPLICATION "application"}. - * - * @author Juergen Hoeller - * @since 3.0 - * @see org.springframework.web.context.ContextCleanupListener - */ -public class ServletContextScope implements Scope, DisposableBean { - - private final ServletContext servletContext; - - private final Map destructionCallbacks = new LinkedHashMap(); - - - /** - * Create a new Scope wrapper for the given ServletContext. - * @param servletContext the ServletContext to wrap - */ - public ServletContextScope(ServletContext servletContext) { - Assert.notNull(servletContext, "ServletContext must not be null"); - this.servletContext = servletContext; - } - - - public Object get(String name, ObjectFactory objectFactory) { - Object scopedObject = this.servletContext.getAttribute(name); - if (scopedObject == null) { - scopedObject = objectFactory.getObject(); - this.servletContext.setAttribute(name, scopedObject); - } - return scopedObject; - } - - public Object remove(String name) { - Object scopedObject = this.servletContext.getAttribute(name); - if (scopedObject != null) { - this.servletContext.removeAttribute(name); - this.destructionCallbacks.remove(name); - return scopedObject; - } - else { - return null; - } - } - - public void registerDestructionCallback(String name, Runnable callback) { - this.destructionCallbacks.put(name, callback); - } - - public Object resolveContextualObject(String key) { - return null; - } - - public String getConversationId() { - return null; - } - - - /** - * Invoke all registered destruction callbacks. - * To be called on ServletContext shutdown. - * @see org.springframework.web.context.ContextCleanupListener - */ - public void destroy() { - for (Runnable runnable : this.destructionCallbacks.values()) { - runnable.run(); - } - this.destructionCallbacks.clear(); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context.support; + +import java.util.LinkedHashMap; +import java.util.Map; +import javax.servlet.ServletContext; + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.ObjectFactory; +import org.springframework.beans.factory.config.Scope; +import org.springframework.util.Assert; + +/** + * {@link Scope} wrapper for a ServletContext, i.e. for global web application attributes. + * + *

This differs from traditional Spring singletons in that it exposes attributes in the + * ServletContext. Those attributes will get destroyed whenever the entire application + * shuts down, which might be earlier or later than the shutdown of the containing Spring + * ApplicationContext. + * + *

The associated destruction mechanism relies on a + * {@link org.springframework.web.context.ContextCleanupListener} being registered in + * web.xml. Note that {@link org.springframework.web.context.ContextLoaderListener} + * includes ContextCleanupListener's functionality. + * + *

This scope is registered as default scope with key + * {@link org.springframework.web.context.WebApplicationContext#SCOPE_APPLICATION "application"}. + * + * @author Juergen Hoeller + * @since 3.0 + * @see org.springframework.web.context.ContextCleanupListener + */ +public class ServletContextScope implements Scope, DisposableBean { + + private final ServletContext servletContext; + + private final Map destructionCallbacks = new LinkedHashMap(); + + + /** + * Create a new Scope wrapper for the given ServletContext. + * @param servletContext the ServletContext to wrap + */ + public ServletContextScope(ServletContext servletContext) { + Assert.notNull(servletContext, "ServletContext must not be null"); + this.servletContext = servletContext; + } + + + public Object get(String name, ObjectFactory objectFactory) { + Object scopedObject = this.servletContext.getAttribute(name); + if (scopedObject == null) { + scopedObject = objectFactory.getObject(); + this.servletContext.setAttribute(name, scopedObject); + } + return scopedObject; + } + + public Object remove(String name) { + Object scopedObject = this.servletContext.getAttribute(name); + if (scopedObject != null) { + this.servletContext.removeAttribute(name); + this.destructionCallbacks.remove(name); + return scopedObject; + } + else { + return null; + } + } + + public void registerDestructionCallback(String name, Runnable callback) { + this.destructionCallbacks.put(name, callback); + } + + public Object resolveContextualObject(String key) { + return null; + } + + public String getConversationId() { + return null; + } + + + /** + * Invoke all registered destruction callbacks. + * To be called on ServletContext shutdown. + * @see org.springframework.web.context.ContextCleanupListener + */ + public void destroy() { + for (Runnable runnable : this.destructionCallbacks.values()) { + runnable.run(); + } + this.destructionCallbacks.clear(); + } + +} diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/package-info.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/package-info.java index db95fbe4a3..43712dbba5 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/package-info.java +++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/package-info.java @@ -1,8 +1,8 @@ - -/** - * - * Support classes for annotation-based handler method processing. - * - */ -package org.springframework.web.method.annotation; - + +/** + * + * Support classes for annotation-based handler method processing. + * + */ +package org.springframework.web.method.annotation; + diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/support/package-info.java b/org.springframework.web/src/main/java/org/springframework/web/method/support/package-info.java index ee561dd1f3..1de7c0ed27 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/method/support/package-info.java +++ b/org.springframework.web/src/main/java/org/springframework/web/method/support/package-info.java @@ -1,8 +1,8 @@ - -/** - * - * Generic support classes for handler method processing. - * - */ -package org.springframework.web.method.support; - + +/** + * + * Generic support classes for handler method processing. + * + */ +package org.springframework.web.method.support; + diff --git a/org.springframework.web/src/main/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java b/org.springframework.web/src/main/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java index 6e7b7e641c..099a6bb249 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java +++ b/org.springframework.web/src/main/java/org/springframework/web/multipart/support/StandardMultipartHttpServletRequest.java @@ -1,175 +1,175 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.multipart.support; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.Part; - -import org.springframework.http.HttpHeaders; -import org.springframework.util.FileCopyUtils; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.multipart.MultipartException; -import org.springframework.web.multipart.MultipartFile; - -/** - * Spring MultipartHttpServletRequest adapter, wrapping a Servlet 3.0 HttpServletRequest - * and its Part objects. Parameters get exposed through the native request's getParameter - * methods - without any custom processing on our side. - * - * @author Juergen Hoeller - * @since 3.1 - */ -public class StandardMultipartHttpServletRequest extends AbstractMultipartHttpServletRequest { - - private static final String CONTENT_DISPOSITION = "Content-Disposition"; - - private static final String FILENAME_KEY = "filename="; - - - /** - * Create a new StandardMultipartHttpServletRequest wrapper for the given request. - * @param request the servlet request to wrap - * @throws MultipartException if parsing failed - */ - public StandardMultipartHttpServletRequest(HttpServletRequest request) throws MultipartException { - super(request); - try { - Collection parts = request.getParts(); - MultiValueMap files = new LinkedMultiValueMap(parts.size()); - for (Part part : parts) { - String filename = extractFilename(part.getHeader(CONTENT_DISPOSITION)); - if (filename != null) { - files.add(part.getName(), new StandardMultipartFile(part, filename)); - } - } - setMultipartFiles(files); - } - catch (Exception ex) { - throw new MultipartException("Could not parse multipart servlet request", ex); - } - } - - private String extractFilename(String contentDisposition) { - if (contentDisposition == null) { - return null; - } - // TODO: can only handle the typical case at the moment - int startIndex = contentDisposition.indexOf(FILENAME_KEY); - if (startIndex == -1) { - return null; - } - String filename = contentDisposition.substring(startIndex + FILENAME_KEY.length()); - if (filename.startsWith("\"")) { - int endIndex = filename.indexOf("\"", 1); - if (endIndex != -1) { - return filename.substring(1, endIndex); - } - } - else { - int endIndex = filename.indexOf(";"); - if (endIndex != -1) { - return filename.substring(0, endIndex); - } - } - return filename; - } - - - public String getMultipartContentType(String paramOrFileName) { - try { - Part part = getPart(paramOrFileName); - return (part != null ? part.getContentType() : null); - } - catch (Exception ex) { - throw new MultipartException("Could not access multipart servlet request", ex); - } - } - - public HttpHeaders getMultipartHeaders(String paramOrFileName) { - try { - Part part = getPart(paramOrFileName); - if (part != null) { - HttpHeaders headers = new HttpHeaders(); - for (String headerName : part.getHeaderNames()) { - headers.put(headerName, new ArrayList(part.getHeaders(headerName))); - } - return headers; - } - else { - return null; - } - } - catch (Exception ex) { - throw new MultipartException("Could not access multipart servlet request", ex); - } - } - - - /** - * Spring MultipartFile adapter, wrapping a Servlet 3.0 Part object. - */ - private static class StandardMultipartFile implements MultipartFile { - - private final Part part; - - private final String filename; - - public StandardMultipartFile(Part part, String filename) { - this.part = part; - this.filename = filename; - } - - public String getName() { - return this.part.getName(); - } - - public String getOriginalFilename() { - return this.filename; - } - - public String getContentType() { - return this.part.getContentType(); - } - - public boolean isEmpty() { - return (this.part.getSize() == 0); - } - - public long getSize() { - return this.part.getSize(); - } - - public byte[] getBytes() throws IOException { - return FileCopyUtils.copyToByteArray(this.part.getInputStream()); - } - - public InputStream getInputStream() throws IOException { - return this.part.getInputStream(); - } - - public void transferTo(File dest) throws IOException, IllegalStateException { - this.part.write(dest.getPath()); - } - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.multipart.support; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.Part; + +import org.springframework.http.HttpHeaders; +import org.springframework.util.FileCopyUtils; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.multipart.MultipartException; +import org.springframework.web.multipart.MultipartFile; + +/** + * Spring MultipartHttpServletRequest adapter, wrapping a Servlet 3.0 HttpServletRequest + * and its Part objects. Parameters get exposed through the native request's getParameter + * methods - without any custom processing on our side. + * + * @author Juergen Hoeller + * @since 3.1 + */ +public class StandardMultipartHttpServletRequest extends AbstractMultipartHttpServletRequest { + + private static final String CONTENT_DISPOSITION = "Content-Disposition"; + + private static final String FILENAME_KEY = "filename="; + + + /** + * Create a new StandardMultipartHttpServletRequest wrapper for the given request. + * @param request the servlet request to wrap + * @throws MultipartException if parsing failed + */ + public StandardMultipartHttpServletRequest(HttpServletRequest request) throws MultipartException { + super(request); + try { + Collection parts = request.getParts(); + MultiValueMap files = new LinkedMultiValueMap(parts.size()); + for (Part part : parts) { + String filename = extractFilename(part.getHeader(CONTENT_DISPOSITION)); + if (filename != null) { + files.add(part.getName(), new StandardMultipartFile(part, filename)); + } + } + setMultipartFiles(files); + } + catch (Exception ex) { + throw new MultipartException("Could not parse multipart servlet request", ex); + } + } + + private String extractFilename(String contentDisposition) { + if (contentDisposition == null) { + return null; + } + // TODO: can only handle the typical case at the moment + int startIndex = contentDisposition.indexOf(FILENAME_KEY); + if (startIndex == -1) { + return null; + } + String filename = contentDisposition.substring(startIndex + FILENAME_KEY.length()); + if (filename.startsWith("\"")) { + int endIndex = filename.indexOf("\"", 1); + if (endIndex != -1) { + return filename.substring(1, endIndex); + } + } + else { + int endIndex = filename.indexOf(";"); + if (endIndex != -1) { + return filename.substring(0, endIndex); + } + } + return filename; + } + + + public String getMultipartContentType(String paramOrFileName) { + try { + Part part = getPart(paramOrFileName); + return (part != null ? part.getContentType() : null); + } + catch (Exception ex) { + throw new MultipartException("Could not access multipart servlet request", ex); + } + } + + public HttpHeaders getMultipartHeaders(String paramOrFileName) { + try { + Part part = getPart(paramOrFileName); + if (part != null) { + HttpHeaders headers = new HttpHeaders(); + for (String headerName : part.getHeaderNames()) { + headers.put(headerName, new ArrayList(part.getHeaders(headerName))); + } + return headers; + } + else { + return null; + } + } + catch (Exception ex) { + throw new MultipartException("Could not access multipart servlet request", ex); + } + } + + + /** + * Spring MultipartFile adapter, wrapping a Servlet 3.0 Part object. + */ + private static class StandardMultipartFile implements MultipartFile { + + private final Part part; + + private final String filename; + + public StandardMultipartFile(Part part, String filename) { + this.part = part; + this.filename = filename; + } + + public String getName() { + return this.part.getName(); + } + + public String getOriginalFilename() { + return this.filename; + } + + public String getContentType() { + return this.part.getContentType(); + } + + public boolean isEmpty() { + return (this.part.getSize() == 0); + } + + public long getSize() { + return this.part.getSize(); + } + + public byte[] getBytes() throws IOException { + return FileCopyUtils.copyToByteArray(this.part.getInputStream()); + } + + public InputStream getInputStream() throws IOException { + return this.part.getInputStream(); + } + + public void transferTo(File dest) throws IOException, IllegalStateException { + this.part.write(dest.getPath()); + } + } + +} diff --git a/org.springframework.web/src/main/java/org/springframework/web/multipart/support/StandardServletMultipartResolver.java b/org.springframework.web/src/main/java/org/springframework/web/multipart/support/StandardServletMultipartResolver.java index 539c78c965..7356345aea 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/multipart/support/StandardServletMultipartResolver.java +++ b/org.springframework.web/src/main/java/org/springframework/web/multipart/support/StandardServletMultipartResolver.java @@ -1,73 +1,73 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.multipart.support; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.Part; - -import org.apache.commons.logging.LogFactory; - -import org.springframework.web.multipart.MultipartException; -import org.springframework.web.multipart.MultipartHttpServletRequest; -import org.springframework.web.multipart.MultipartResolver; - -/** - * Standard implementation of the {@link MultipartResolver} interface, - * based on the Servlet 3.0 {@link javax.servlet.http.Part} API. - * To be added as "multipartResolver" bean to a Spring DispatcherServlet context, - * without any extra configuration at the bean level (see below). - * - *

Note: In order to use Servlet 3.0 based multipart parsing, - * you need to mark the affected servlet with a "multipart-config" section in - * web.xml, or with a {@link javax.servlet.MultipartConfigElement} - * in programmatic servlet registration, or (in case of a custom servlet class) - * possibly with a {@link javax.servlet.annotation.MultipartConfig} annotation - * on your servlet class. Configuration settings such as maximum sizes or - * storage locations need to be applied at that servlet registration level; - * Servlet 3.0 does not allow for them to be set at the MultipartResolver level. - * - * @author Juergen Hoeller - * @since 3.1 - */ -public class StandardServletMultipartResolver implements MultipartResolver { - - public boolean isMultipart(HttpServletRequest request) { - // Same check as in Commons FileUpload... - if (!"post".equals(request.getMethod().toLowerCase())) { - return false; - } - String contentType = request.getContentType(); - return (contentType != null && contentType.toLowerCase().startsWith("multipart/")); - } - - public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException { - return new StandardMultipartHttpServletRequest(request); - } - - public void cleanupMultipart(MultipartHttpServletRequest request) { - // To be on the safe side: explicitly delete all parts. - try { - for (Part part : request.getParts()) { - part.delete(); - } - } - catch (Exception ex) { - LogFactory.getLog(getClass()).warn("Failed to perform cleanup of multipart items", ex); - } - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.multipart.support; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.Part; + +import org.apache.commons.logging.LogFactory; + +import org.springframework.web.multipart.MultipartException; +import org.springframework.web.multipart.MultipartHttpServletRequest; +import org.springframework.web.multipart.MultipartResolver; + +/** + * Standard implementation of the {@link MultipartResolver} interface, + * based on the Servlet 3.0 {@link javax.servlet.http.Part} API. + * To be added as "multipartResolver" bean to a Spring DispatcherServlet context, + * without any extra configuration at the bean level (see below). + * + *

Note: In order to use Servlet 3.0 based multipart parsing, + * you need to mark the affected servlet with a "multipart-config" section in + * web.xml, or with a {@link javax.servlet.MultipartConfigElement} + * in programmatic servlet registration, or (in case of a custom servlet class) + * possibly with a {@link javax.servlet.annotation.MultipartConfig} annotation + * on your servlet class. Configuration settings such as maximum sizes or + * storage locations need to be applied at that servlet registration level; + * Servlet 3.0 does not allow for them to be set at the MultipartResolver level. + * + * @author Juergen Hoeller + * @since 3.1 + */ +public class StandardServletMultipartResolver implements MultipartResolver { + + public boolean isMultipart(HttpServletRequest request) { + // Same check as in Commons FileUpload... + if (!"post".equals(request.getMethod().toLowerCase())) { + return false; + } + String contentType = request.getContentType(); + return (contentType != null && contentType.toLowerCase().startsWith("multipart/")); + } + + public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException { + return new StandardMultipartHttpServletRequest(request); + } + + public void cleanupMultipart(MultipartHttpServletRequest request) { + // To be on the safe side: explicitly delete all parts. + try { + for (Part part : request.getParts()) { + part.delete(); + } + } + catch (Exception ex) { + LogFactory.getLog(getClass()).warn("Failed to perform cleanup of multipart items", ex); + } + } + +} diff --git a/org.springframework.web/src/test/java/org/springframework/mock/web/DelegatingServletInputStream.java b/org.springframework.web/src/test/java/org/springframework/mock/web/DelegatingServletInputStream.java index 22dd38281e..b083e95b27 100644 --- a/org.springframework.web/src/test/java/org/springframework/mock/web/DelegatingServletInputStream.java +++ b/org.springframework.web/src/test/java/org/springframework/mock/web/DelegatingServletInputStream.java @@ -1,66 +1,66 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import java.io.IOException; -import java.io.InputStream; -import javax.servlet.ServletInputStream; - -import org.springframework.util.Assert; - -/** - * Delegating implementation of {@link javax.servlet.ServletInputStream}. - * - *

Used by {@link MockHttpServletRequest}; typically not directly - * used for testing application controllers. - * - * @author Juergen Hoeller - * @since 1.0.2 - * @see MockHttpServletRequest - */ -public class DelegatingServletInputStream extends ServletInputStream { - - private final InputStream sourceStream; - - - /** - * Create a DelegatingServletInputStream for the given source stream. - * @param sourceStream the source stream (never null) - */ - public DelegatingServletInputStream(InputStream sourceStream) { - Assert.notNull(sourceStream, "Source InputStream must not be null"); - this.sourceStream = sourceStream; - } - - /** - * Return the underlying source stream (never null). - */ - public final InputStream getSourceStream() { - return this.sourceStream; - } - - - public int read() throws IOException { - return this.sourceStream.read(); - } - - public void close() throws IOException { - super.close(); - this.sourceStream.close(); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.io.IOException; +import java.io.InputStream; +import javax.servlet.ServletInputStream; + +import org.springframework.util.Assert; + +/** + * Delegating implementation of {@link javax.servlet.ServletInputStream}. + * + *

Used by {@link MockHttpServletRequest}; typically not directly + * used for testing application controllers. + * + * @author Juergen Hoeller + * @since 1.0.2 + * @see MockHttpServletRequest + */ +public class DelegatingServletInputStream extends ServletInputStream { + + private final InputStream sourceStream; + + + /** + * Create a DelegatingServletInputStream for the given source stream. + * @param sourceStream the source stream (never null) + */ + public DelegatingServletInputStream(InputStream sourceStream) { + Assert.notNull(sourceStream, "Source InputStream must not be null"); + this.sourceStream = sourceStream; + } + + /** + * Return the underlying source stream (never null). + */ + public final InputStream getSourceStream() { + return this.sourceStream; + } + + + public int read() throws IOException { + return this.sourceStream.read(); + } + + public void close() throws IOException { + super.close(); + this.sourceStream.close(); + } + +} diff --git a/org.springframework.web/src/test/java/org/springframework/mock/web/DelegatingServletOutputStream.java b/org.springframework.web/src/test/java/org/springframework/mock/web/DelegatingServletOutputStream.java index 094391ae7d..66fca5df2f 100644 --- a/org.springframework.web/src/test/java/org/springframework/mock/web/DelegatingServletOutputStream.java +++ b/org.springframework.web/src/test/java/org/springframework/mock/web/DelegatingServletOutputStream.java @@ -1,71 +1,71 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import java.io.IOException; -import java.io.OutputStream; -import javax.servlet.ServletOutputStream; - -import org.springframework.util.Assert; - -/** - * Delegating implementation of {@link javax.servlet.ServletOutputStream}. - * - *

Used by {@link MockHttpServletResponse}; typically not directly - * used for testing application controllers. - * - * @author Juergen Hoeller - * @since 1.0.2 - * @see MockHttpServletResponse - */ -public class DelegatingServletOutputStream extends ServletOutputStream { - - private final OutputStream targetStream; - - - /** - * Create a DelegatingServletOutputStream for the given target stream. - * @param targetStream the target stream (never null) - */ - public DelegatingServletOutputStream(OutputStream targetStream) { - Assert.notNull(targetStream, "Target OutputStream must not be null"); - this.targetStream = targetStream; - } - - /** - * Return the underlying target stream (never null). - */ - public final OutputStream getTargetStream() { - return this.targetStream; - } - - - public void write(int b) throws IOException { - this.targetStream.write(b); - } - - public void flush() throws IOException { - super.flush(); - this.targetStream.flush(); - } - - public void close() throws IOException { - super.close(); - this.targetStream.close(); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.io.IOException; +import java.io.OutputStream; +import javax.servlet.ServletOutputStream; + +import org.springframework.util.Assert; + +/** + * Delegating implementation of {@link javax.servlet.ServletOutputStream}. + * + *

Used by {@link MockHttpServletResponse}; typically not directly + * used for testing application controllers. + * + * @author Juergen Hoeller + * @since 1.0.2 + * @see MockHttpServletResponse + */ +public class DelegatingServletOutputStream extends ServletOutputStream { + + private final OutputStream targetStream; + + + /** + * Create a DelegatingServletOutputStream for the given target stream. + * @param targetStream the target stream (never null) + */ + public DelegatingServletOutputStream(OutputStream targetStream) { + Assert.notNull(targetStream, "Target OutputStream must not be null"); + this.targetStream = targetStream; + } + + /** + * Return the underlying target stream (never null). + */ + public final OutputStream getTargetStream() { + return this.targetStream; + } + + + public void write(int b) throws IOException { + this.targetStream.write(b); + } + + public void flush() throws IOException { + super.flush(); + this.targetStream.flush(); + } + + public void close() throws IOException { + super.close(); + this.targetStream.close(); + } + +} diff --git a/org.springframework.web/src/test/java/org/springframework/mock/web/HeaderValueHolder.java b/org.springframework.web/src/test/java/org/springframework/mock/web/HeaderValueHolder.java index 48224a00d2..afe74ad8f0 100644 --- a/org.springframework.web/src/test/java/org/springframework/mock/web/HeaderValueHolder.java +++ b/org.springframework.web/src/test/java/org/springframework/mock/web/HeaderValueHolder.java @@ -1,96 +1,96 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import org.springframework.util.Assert; -import org.springframework.util.CollectionUtils; - -/** - * Internal helper class that serves as value holder for request headers. - * - * @author Juergen Hoeller - * @author Rick Evans - * @since 2.0.1 - */ -class HeaderValueHolder { - - private final List values = new LinkedList(); - - - public void setValue(Object value) { - this.values.clear(); - this.values.add(value); - } - - public void addValue(Object value) { - this.values.add(value); - } - - public void addValues(Collection values) { - this.values.addAll(values); - } - - public void addValueArray(Object values) { - CollectionUtils.mergeArrayIntoCollection(values, this.values); - } - - public List getValues() { - return Collections.unmodifiableList(this.values); - } - - public List getStringValues() { - List stringList = new ArrayList(this.values.size()); - for (Object value : this.values) { - stringList.add(value.toString()); - } - return Collections.unmodifiableList(stringList); - } - - public Object getValue() { - return (!this.values.isEmpty() ? this.values.get(0) : null); - } - - public String getStringValue() { - return (!this.values.isEmpty() ? this.values.get(0).toString() : null); - } - - - /** - * Find a HeaderValueHolder by name, ignoring casing. - * @param headers the Map of header names to HeaderValueHolders - * @param name the name of the desired header - * @return the corresponding HeaderValueHolder, - * or null if none found - */ - public static HeaderValueHolder getByName(Map headers, String name) { - Assert.notNull(name, "Header name must not be null"); - for (String headerName : headers.keySet()) { - if (headerName.equalsIgnoreCase(name)) { - return headers.get(headerName); - } - } - return null; - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +/** + * Internal helper class that serves as value holder for request headers. + * + * @author Juergen Hoeller + * @author Rick Evans + * @since 2.0.1 + */ +class HeaderValueHolder { + + private final List values = new LinkedList(); + + + public void setValue(Object value) { + this.values.clear(); + this.values.add(value); + } + + public void addValue(Object value) { + this.values.add(value); + } + + public void addValues(Collection values) { + this.values.addAll(values); + } + + public void addValueArray(Object values) { + CollectionUtils.mergeArrayIntoCollection(values, this.values); + } + + public List getValues() { + return Collections.unmodifiableList(this.values); + } + + public List getStringValues() { + List stringList = new ArrayList(this.values.size()); + for (Object value : this.values) { + stringList.add(value.toString()); + } + return Collections.unmodifiableList(stringList); + } + + public Object getValue() { + return (!this.values.isEmpty() ? this.values.get(0) : null); + } + + public String getStringValue() { + return (!this.values.isEmpty() ? this.values.get(0).toString() : null); + } + + + /** + * Find a HeaderValueHolder by name, ignoring casing. + * @param headers the Map of header names to HeaderValueHolders + * @param name the name of the desired header + * @return the corresponding HeaderValueHolder, + * or null if none found + */ + public static HeaderValueHolder getByName(Map headers, String name) { + Assert.notNull(name, "Header name must not be null"); + for (String headerName : headers.keySet()) { + if (headerName.equalsIgnoreCase(name)) { + return headers.get(headerName); + } + } + return null; + } + +} diff --git a/org.springframework.web/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java b/org.springframework.web/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java index f493d553cf..5d23662a3f 100644 --- a/org.springframework.web/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java +++ b/org.springframework.web/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java @@ -1,948 +1,948 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.UnsupportedEncodingException; -import java.security.Principal; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; - -import javax.servlet.AsyncContext; -import javax.servlet.DispatcherType; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import javax.servlet.http.Part; - -import org.springframework.util.Assert; -import org.springframework.util.LinkedCaseInsensitiveMap; - -/** - * Mock implementation of the {@link javax.servlet.http.HttpServletRequest} - * interface. Supports the Servlet 2.5 API level; throws - * {@link UnsupportedOperationException} for all methods introduced in Servlet 3.0. - * - *

Used for testing the web framework; also useful for testing - * application controllers. - * - * @author Juergen Hoeller - * @author Rod Johnson - * @author Rick Evans - * @author Mark Fisher - * @author Chris Beams - * @since 1.0.2 - */ -public class MockHttpServletRequest implements HttpServletRequest { - - /** - * The default protocol: 'http'. - */ - public static final String DEFAULT_PROTOCOL = "http"; - - /** - * The default server address: '127.0.0.1'. - */ - public static final String DEFAULT_SERVER_ADDR = "127.0.0.1"; - - /** - * The default server name: 'localhost'. - */ - public static final String DEFAULT_SERVER_NAME = "localhost"; - - /** - * The default server port: '80'. - */ - public static final int DEFAULT_SERVER_PORT = 80; - - /** - * The default remote address: '127.0.0.1'. - */ - public static final String DEFAULT_REMOTE_ADDR = "127.0.0.1"; - - /** - * The default remote host: 'localhost'. - */ - public static final String DEFAULT_REMOTE_HOST = "localhost"; - - private static final String CONTENT_TYPE_HEADER = "Content-Type"; - - private static final String CHARSET_PREFIX = "charset="; - - - private boolean active = true; - - - //--------------------------------------------------------------------- - // ServletRequest properties - //--------------------------------------------------------------------- - - private final Map attributes = new LinkedHashMap(); - - private String characterEncoding; - - private byte[] content; - - private String contentType; - - private final Map parameters = new LinkedHashMap(16); - - private String protocol = DEFAULT_PROTOCOL; - - private String scheme = DEFAULT_PROTOCOL; - - private String serverName = DEFAULT_SERVER_NAME; - - private int serverPort = DEFAULT_SERVER_PORT; - - private String remoteAddr = DEFAULT_REMOTE_ADDR; - - private String remoteHost = DEFAULT_REMOTE_HOST; - - /** List of locales in descending order */ - private final List locales = new LinkedList(); - - private boolean secure = false; - - private final ServletContext servletContext; - - private int remotePort = DEFAULT_SERVER_PORT; - - private String localName = DEFAULT_SERVER_NAME; - - private String localAddr = DEFAULT_SERVER_ADDR; - - private int localPort = DEFAULT_SERVER_PORT; - - private Map parts = new HashMap(); - - //--------------------------------------------------------------------- - // HttpServletRequest properties - //--------------------------------------------------------------------- - - private String authType; - - private Cookie[] cookies; - - private final Map headers = new LinkedCaseInsensitiveMap(); - - private String method; - - private String pathInfo; - - private String contextPath = ""; - - private String queryString; - - private String remoteUser; - - private final Set userRoles = new HashSet(); - - private Principal userPrincipal; - - private String requestedSessionId; - - private String requestURI; - - private String servletPath = ""; - - private HttpSession session; - - private boolean requestedSessionIdValid = true; - - private boolean requestedSessionIdFromCookie = true; - - private boolean requestedSessionIdFromURL = false; - - - //--------------------------------------------------------------------- - // Constructors - //--------------------------------------------------------------------- - - /** - * Create a new MockHttpServletRequest with a default - * {@link MockServletContext}. - * @see MockServletContext - */ - public MockHttpServletRequest() { - this(null, "", ""); - } - - /** - * Create a new MockHttpServletRequest with a default - * {@link MockServletContext}. - * @param method the request method (may be null) - * @param requestURI the request URI (may be null) - * @see #setMethod - * @see #setRequestURI - * @see MockServletContext - */ - public MockHttpServletRequest(String method, String requestURI) { - this(null, method, requestURI); - } - - /** - * Create a new MockHttpServletRequest. - * @param servletContext the ServletContext that the request runs in - * (may be null to use a default MockServletContext) - * @see MockServletContext - */ - public MockHttpServletRequest(ServletContext servletContext) { - this(servletContext, "", ""); - } - - /** - * Create a new MockHttpServletRequest. - * @param servletContext the ServletContext that the request runs in - * (may be null to use a default MockServletContext) - * @param method the request method (may be null) - * @param requestURI the request URI (may be null) - * @see #setMethod - * @see #setRequestURI - * @see MockServletContext - */ - public MockHttpServletRequest(ServletContext servletContext, String method, String requestURI) { - this.servletContext = (servletContext != null ? servletContext : new MockServletContext()); - this.method = method; - this.requestURI = requestURI; - this.locales.add(Locale.ENGLISH); - } - - - //--------------------------------------------------------------------- - // Lifecycle methods - //--------------------------------------------------------------------- - - /** - * Return the ServletContext that this request is associated with. - * (Not available in the standard HttpServletRequest interface for some reason.) - */ - public ServletContext getServletContext() { - return this.servletContext; - } - - /** - * Return whether this request is still active (that is, not completed yet). - */ - public boolean isActive() { - return this.active; - } - - /** - * Mark this request as completed, keeping its state. - */ - public void close() { - this.active = false; - } - - /** - * Invalidate this request, clearing its state. - */ - public void invalidate() { - close(); - clearAttributes(); - } - - /** - * Check whether this request is still active (that is, not completed yet), - * throwing an IllegalStateException if not active anymore. - */ - protected void checkActive() throws IllegalStateException { - if (!this.active) { - throw new IllegalStateException("Request is not active anymore"); - } - } - - - //--------------------------------------------------------------------- - // ServletRequest interface - //--------------------------------------------------------------------- - - public Object getAttribute(String name) { - checkActive(); - return this.attributes.get(name); - } - - public Enumeration getAttributeNames() { - checkActive(); - return Collections.enumeration(this.attributes.keySet()); - } - - public String getCharacterEncoding() { - return this.characterEncoding; - } - - public void setCharacterEncoding(String characterEncoding) { - this.characterEncoding = characterEncoding; - updateContentTypeHeader(); - } - - private void updateContentTypeHeader() { - if (this.contentType != null) { - StringBuilder sb = new StringBuilder(this.contentType); - if (this.contentType.toLowerCase().indexOf(CHARSET_PREFIX) == -1 && this.characterEncoding != null) { - sb.append(";").append(CHARSET_PREFIX).append(this.characterEncoding); - } - doAddHeaderValue(CONTENT_TYPE_HEADER, sb.toString(), true); - } - } - - public void setContent(byte[] content) { - this.content = content; - } - - public int getContentLength() { - return (this.content != null ? this.content.length : -1); - } - - public void setContentType(String contentType) { - this.contentType = contentType; - if (contentType != null) { - int charsetIndex = contentType.toLowerCase().indexOf(CHARSET_PREFIX); - if (charsetIndex != -1) { - String encoding = contentType.substring(charsetIndex + CHARSET_PREFIX.length()); - this.characterEncoding = encoding; - } - updateContentTypeHeader(); - } - } - - public String getContentType() { - return this.contentType; - } - - public ServletInputStream getInputStream() { - if (this.content != null) { - return new DelegatingServletInputStream(new ByteArrayInputStream(this.content)); - } - else { - return null; - } - } - - /** - * Set a single value for the specified HTTP parameter. - *

If there are already one or more values registered for the given - * parameter name, they will be replaced. - */ - public void setParameter(String name, String value) { - setParameter(name, new String[] {value}); - } - - /** - * Set an array of values for the specified HTTP parameter. - *

If there are already one or more values registered for the given - * parameter name, they will be replaced. - */ - public void setParameter(String name, String[] values) { - Assert.notNull(name, "Parameter name must not be null"); - this.parameters.put(name, values); - } - - /** - * Sets all provided parameters replacing any - * existing values for the provided parameter names. To add without - * replacing existing values, use {@link #addParameters(java.util.Map)}. - */ - public void setParameters(Map params) { - Assert.notNull(params, "Parameter map must not be null"); - for (Object key : params.keySet()) { - Assert.isInstanceOf(String.class, key, - "Parameter map key must be of type [" + String.class.getName() + "]"); - Object value = params.get(key); - if (value instanceof String) { - this.setParameter((String) key, (String) value); - } - else if (value instanceof String[]) { - this.setParameter((String) key, (String[]) value); - } - else { - throw new IllegalArgumentException( - "Parameter map value must be single value " + " or array of type [" + String.class.getName() + - "]"); - } - } - } - - /** - * Add a single value for the specified HTTP parameter. - *

If there are already one or more values registered for the given - * parameter name, the given value will be added to the end of the list. - */ - public void addParameter(String name, String value) { - addParameter(name, new String[] {value}); - } - - /** - * Add an array of values for the specified HTTP parameter. - *

If there are already one or more values registered for the given - * parameter name, the given values will be added to the end of the list. - */ - public void addParameter(String name, String[] values) { - Assert.notNull(name, "Parameter name must not be null"); - String[] oldArr = this.parameters.get(name); - if (oldArr != null) { - String[] newArr = new String[oldArr.length + values.length]; - System.arraycopy(oldArr, 0, newArr, 0, oldArr.length); - System.arraycopy(values, 0, newArr, oldArr.length, values.length); - this.parameters.put(name, newArr); - } - else { - this.parameters.put(name, values); - } - } - - /** - * Adds all provided parameters without replacing - * any existing values. To replace existing values, use - * {@link #setParameters(java.util.Map)}. - */ - public void addParameters(Map params) { - Assert.notNull(params, "Parameter map must not be null"); - for (Object key : params.keySet()) { - Assert.isInstanceOf(String.class, key, - "Parameter map key must be of type [" + String.class.getName() + "]"); - Object value = params.get(key); - if (value instanceof String) { - this.addParameter((String) key, (String) value); - } - else if (value instanceof String[]) { - this.addParameter((String) key, (String[]) value); - } - else { - throw new IllegalArgumentException("Parameter map value must be single value " + - " or array of type [" + String.class.getName() + "]"); - } - } - } - - /** - * Remove already registered values for the specified HTTP parameter, if any. - */ - public void removeParameter(String name) { - Assert.notNull(name, "Parameter name must not be null"); - this.parameters.remove(name); - } - - /** - * Removes all existing parameters. - */ - public void removeAllParameters() { - this.parameters.clear(); - } - - public String getParameter(String name) { - Assert.notNull(name, "Parameter name must not be null"); - String[] arr = this.parameters.get(name); - return (arr != null && arr.length > 0 ? arr[0] : null); - } - - public Enumeration getParameterNames() { - return Collections.enumeration(this.parameters.keySet()); - } - - public String[] getParameterValues(String name) { - Assert.notNull(name, "Parameter name must not be null"); - return this.parameters.get(name); - } - - public Map getParameterMap() { - return Collections.unmodifiableMap(this.parameters); - } - - public void setProtocol(String protocol) { - this.protocol = protocol; - } - - public String getProtocol() { - return this.protocol; - } - - public void setScheme(String scheme) { - this.scheme = scheme; - } - - public String getScheme() { - return this.scheme; - } - - public void setServerName(String serverName) { - this.serverName = serverName; - } - - public String getServerName() { - return this.serverName; - } - - public void setServerPort(int serverPort) { - this.serverPort = serverPort; - } - - public int getServerPort() { - return this.serverPort; - } - - public BufferedReader getReader() throws UnsupportedEncodingException { - if (this.content != null) { - InputStream sourceStream = new ByteArrayInputStream(this.content); - Reader sourceReader = (this.characterEncoding != null) ? - new InputStreamReader(sourceStream, this.characterEncoding) : new InputStreamReader(sourceStream); - return new BufferedReader(sourceReader); - } - else { - return null; - } - } - - public void setRemoteAddr(String remoteAddr) { - this.remoteAddr = remoteAddr; - } - - public String getRemoteAddr() { - return this.remoteAddr; - } - - public void setRemoteHost(String remoteHost) { - this.remoteHost = remoteHost; - } - - public String getRemoteHost() { - return this.remoteHost; - } - - public void setAttribute(String name, Object value) { - checkActive(); - Assert.notNull(name, "Attribute name must not be null"); - if (value != null) { - this.attributes.put(name, value); - } - else { - this.attributes.remove(name); - } - } - - public void removeAttribute(String name) { - checkActive(); - Assert.notNull(name, "Attribute name must not be null"); - this.attributes.remove(name); - } - - /** - * Clear all of this request's attributes. - */ - public void clearAttributes() { - this.attributes.clear(); - } - - /** - * Add a new preferred locale, before any existing locales. - */ - public void addPreferredLocale(Locale locale) { - Assert.notNull(locale, "Locale must not be null"); - this.locales.add(0, locale); - } - - public Locale getLocale() { - return this.locales.get(0); - } - - public Enumeration getLocales() { - return Collections.enumeration(this.locales); - } - - public void setSecure(boolean secure) { - this.secure = secure; - } - - public boolean isSecure() { - return this.secure; - } - - public RequestDispatcher getRequestDispatcher(String path) { - return new MockRequestDispatcher(path); - } - - public String getRealPath(String path) { - return this.servletContext.getRealPath(path); - } - - public void setRemotePort(int remotePort) { - this.remotePort = remotePort; - } - - public int getRemotePort() { - return this.remotePort; - } - - public void setLocalName(String localName) { - this.localName = localName; - } - - public String getLocalName() { - return this.localName; - } - - public void setLocalAddr(String localAddr) { - this.localAddr = localAddr; - } - - public String getLocalAddr() { - return this.localAddr; - } - - public void setLocalPort(int localPort) { - this.localPort = localPort; - } - - public int getLocalPort() { - return this.localPort; - } - - - //--------------------------------------------------------------------- - // HttpServletRequest interface - //--------------------------------------------------------------------- - - public void setAuthType(String authType) { - this.authType = authType; - } - - public String getAuthType() { - return this.authType; - } - - public void setCookies(Cookie... cookies) { - this.cookies = cookies; - } - - public Cookie[] getCookies() { - return this.cookies; - } - - /** - * Add a header entry for the given name. - *

If there was no entry for that header name before, - * the value will be used as-is. In case of an existing entry, - * a String array will be created, adding the given value (more - * specifically, its toString representation) as further element. - *

Multiple values can only be stored as list of Strings, - * following the Servlet spec (see getHeaders accessor). - * As alternative to repeated addHeader calls for - * individual elements, you can use a single call with an entire - * array or Collection of values as parameter. - * @see #getHeaderNames - * @see #getHeader - * @see #getHeaders - * @see #getDateHeader - * @see #getIntHeader - */ - public void addHeader(String name, Object value) { - if (CONTENT_TYPE_HEADER.equalsIgnoreCase(name)) { - setContentType((String) value); - return; - } - doAddHeaderValue(name, value, false); - } - - @SuppressWarnings("rawtypes") - private void doAddHeaderValue(String name, Object value, boolean replace) { - HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); - Assert.notNull(value, "Header value must not be null"); - if (header == null || replace) { - header = new HeaderValueHolder(); - this.headers.put(name, header); - } - if (value instanceof Collection) { - header.addValues((Collection) value); - } - else if (value.getClass().isArray()) { - header.addValueArray(value); - } - else { - header.addValue(value); - } - } - - public long getDateHeader(String name) { - HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); - Object value = (header != null ? header.getValue() : null); - if (value instanceof Date) { - return ((Date) value).getTime(); - } - else if (value instanceof Number) { - return ((Number) value).longValue(); - } - else if (value != null) { - throw new IllegalArgumentException( - "Value for header '" + name + "' is neither a Date nor a Number: " + value); - } - else { - return -1L; - } - } - - public String getHeader(String name) { - HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); - return (header != null ? header.getValue().toString() : null); - } - - public Enumeration getHeaders(String name) { - HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); - return Collections.enumeration(header != null ? header.getStringValues() : new LinkedList()); - } - - public Enumeration getHeaderNames() { - return Collections.enumeration(this.headers.keySet()); - } - - public int getIntHeader(String name) { - HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); - Object value = (header != null ? header.getValue() : null); - if (value instanceof Number) { - return ((Number) value).intValue(); - } - else if (value instanceof String) { - return Integer.parseInt((String) value); - } - else if (value != null) { - throw new NumberFormatException("Value for header '" + name + "' is not a Number: " + value); - } - else { - return -1; - } - } - - public void setMethod(String method) { - this.method = method; - } - - public String getMethod() { - return this.method; - } - - public void setPathInfo(String pathInfo) { - this.pathInfo = pathInfo; - } - - public String getPathInfo() { - return this.pathInfo; - } - - public String getPathTranslated() { - return (this.pathInfo != null ? getRealPath(this.pathInfo) : null); - } - - public void setContextPath(String contextPath) { - this.contextPath = contextPath; - } - - public String getContextPath() { - return this.contextPath; - } - - public void setQueryString(String queryString) { - this.queryString = queryString; - } - - public String getQueryString() { - return this.queryString; - } - - public void setRemoteUser(String remoteUser) { - this.remoteUser = remoteUser; - } - - public String getRemoteUser() { - return this.remoteUser; - } - - public void addUserRole(String role) { - this.userRoles.add(role); - } - - public boolean isUserInRole(String role) { - return this.userRoles.contains(role); - } - - public void setUserPrincipal(Principal userPrincipal) { - this.userPrincipal = userPrincipal; - } - - public Principal getUserPrincipal() { - return this.userPrincipal; - } - - public void setRequestedSessionId(String requestedSessionId) { - this.requestedSessionId = requestedSessionId; - } - - public String getRequestedSessionId() { - return this.requestedSessionId; - } - - public void setRequestURI(String requestURI) { - this.requestURI = requestURI; - } - - public String getRequestURI() { - return this.requestURI; - } - - public StringBuffer getRequestURL() { - StringBuffer url = new StringBuffer(this.scheme); - url.append("://").append(this.serverName).append(':').append(this.serverPort); - url.append(getRequestURI()); - return url; - } - - public void setServletPath(String servletPath) { - this.servletPath = servletPath; - } - - public String getServletPath() { - return this.servletPath; - } - - public void setSession(HttpSession session) { - this.session = session; - if (session instanceof MockHttpSession) { - MockHttpSession mockSession = ((MockHttpSession) session); - mockSession.access(); - } - } - - public HttpSession getSession(boolean create) { - checkActive(); - // Reset session if invalidated. - if (this.session instanceof MockHttpSession && ((MockHttpSession) this.session).isInvalid()) { - this.session = null; - } - // Create new session if necessary. - if (this.session == null && create) { - this.session = new MockHttpSession(this.servletContext); - } - return this.session; - } - - public HttpSession getSession() { - return getSession(true); - } - - public void setRequestedSessionIdValid(boolean requestedSessionIdValid) { - this.requestedSessionIdValid = requestedSessionIdValid; - } - - public boolean isRequestedSessionIdValid() { - return this.requestedSessionIdValid; - } - - public void setRequestedSessionIdFromCookie(boolean requestedSessionIdFromCookie) { - this.requestedSessionIdFromCookie = requestedSessionIdFromCookie; - } - - public boolean isRequestedSessionIdFromCookie() { - return this.requestedSessionIdFromCookie; - } - - public void setRequestedSessionIdFromURL(boolean requestedSessionIdFromURL) { - this.requestedSessionIdFromURL = requestedSessionIdFromURL; - } - - public boolean isRequestedSessionIdFromURL() { - return this.requestedSessionIdFromURL; - } - - public boolean isRequestedSessionIdFromUrl() { - return isRequestedSessionIdFromURL(); - } - - - //--------------------------------------------------------------------- - // Methods introduced in Servlet 3.0 - //--------------------------------------------------------------------- - - public AsyncContext getAsyncContext() { - throw new UnsupportedOperationException(); - } - - public DispatcherType getDispatcherType() { - throw new UnsupportedOperationException(); - } - - public boolean isAsyncSupported() { - throw new UnsupportedOperationException(); - } - - public AsyncContext startAsync() { - throw new UnsupportedOperationException(); - } - - public AsyncContext startAsync(ServletRequest arg0, ServletResponse arg1) { - throw new UnsupportedOperationException(); - } - - public boolean isAsyncStarted() { - throw new UnsupportedOperationException(); - } - - public boolean authenticate(HttpServletResponse arg0) throws IOException, ServletException { - throw new UnsupportedOperationException(); - } - - public void addPart(Part part) { - parts.put(part.getName(), part); - } - - public Part getPart(String key) throws IOException, IllegalStateException, ServletException { - return parts.get(key); - } - - public Collection getParts() throws IOException, IllegalStateException, ServletException { - return parts.values(); - } - - public void login(String arg0, String arg1) throws ServletException { - throw new UnsupportedOperationException(); - } - - public void logout() throws ServletException { - throw new UnsupportedOperationException(); - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.security.Principal; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import javax.servlet.AsyncContext; +import javax.servlet.DispatcherType; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import javax.servlet.http.Part; + +import org.springframework.util.Assert; +import org.springframework.util.LinkedCaseInsensitiveMap; + +/** + * Mock implementation of the {@link javax.servlet.http.HttpServletRequest} + * interface. Supports the Servlet 2.5 API level; throws + * {@link UnsupportedOperationException} for all methods introduced in Servlet 3.0. + * + *

Used for testing the web framework; also useful for testing + * application controllers. + * + * @author Juergen Hoeller + * @author Rod Johnson + * @author Rick Evans + * @author Mark Fisher + * @author Chris Beams + * @since 1.0.2 + */ +public class MockHttpServletRequest implements HttpServletRequest { + + /** + * The default protocol: 'http'. + */ + public static final String DEFAULT_PROTOCOL = "http"; + + /** + * The default server address: '127.0.0.1'. + */ + public static final String DEFAULT_SERVER_ADDR = "127.0.0.1"; + + /** + * The default server name: 'localhost'. + */ + public static final String DEFAULT_SERVER_NAME = "localhost"; + + /** + * The default server port: '80'. + */ + public static final int DEFAULT_SERVER_PORT = 80; + + /** + * The default remote address: '127.0.0.1'. + */ + public static final String DEFAULT_REMOTE_ADDR = "127.0.0.1"; + + /** + * The default remote host: 'localhost'. + */ + public static final String DEFAULT_REMOTE_HOST = "localhost"; + + private static final String CONTENT_TYPE_HEADER = "Content-Type"; + + private static final String CHARSET_PREFIX = "charset="; + + + private boolean active = true; + + + //--------------------------------------------------------------------- + // ServletRequest properties + //--------------------------------------------------------------------- + + private final Map attributes = new LinkedHashMap(); + + private String characterEncoding; + + private byte[] content; + + private String contentType; + + private final Map parameters = new LinkedHashMap(16); + + private String protocol = DEFAULT_PROTOCOL; + + private String scheme = DEFAULT_PROTOCOL; + + private String serverName = DEFAULT_SERVER_NAME; + + private int serverPort = DEFAULT_SERVER_PORT; + + private String remoteAddr = DEFAULT_REMOTE_ADDR; + + private String remoteHost = DEFAULT_REMOTE_HOST; + + /** List of locales in descending order */ + private final List locales = new LinkedList(); + + private boolean secure = false; + + private final ServletContext servletContext; + + private int remotePort = DEFAULT_SERVER_PORT; + + private String localName = DEFAULT_SERVER_NAME; + + private String localAddr = DEFAULT_SERVER_ADDR; + + private int localPort = DEFAULT_SERVER_PORT; + + private Map parts = new HashMap(); + + //--------------------------------------------------------------------- + // HttpServletRequest properties + //--------------------------------------------------------------------- + + private String authType; + + private Cookie[] cookies; + + private final Map headers = new LinkedCaseInsensitiveMap(); + + private String method; + + private String pathInfo; + + private String contextPath = ""; + + private String queryString; + + private String remoteUser; + + private final Set userRoles = new HashSet(); + + private Principal userPrincipal; + + private String requestedSessionId; + + private String requestURI; + + private String servletPath = ""; + + private HttpSession session; + + private boolean requestedSessionIdValid = true; + + private boolean requestedSessionIdFromCookie = true; + + private boolean requestedSessionIdFromURL = false; + + + //--------------------------------------------------------------------- + // Constructors + //--------------------------------------------------------------------- + + /** + * Create a new MockHttpServletRequest with a default + * {@link MockServletContext}. + * @see MockServletContext + */ + public MockHttpServletRequest() { + this(null, "", ""); + } + + /** + * Create a new MockHttpServletRequest with a default + * {@link MockServletContext}. + * @param method the request method (may be null) + * @param requestURI the request URI (may be null) + * @see #setMethod + * @see #setRequestURI + * @see MockServletContext + */ + public MockHttpServletRequest(String method, String requestURI) { + this(null, method, requestURI); + } + + /** + * Create a new MockHttpServletRequest. + * @param servletContext the ServletContext that the request runs in + * (may be null to use a default MockServletContext) + * @see MockServletContext + */ + public MockHttpServletRequest(ServletContext servletContext) { + this(servletContext, "", ""); + } + + /** + * Create a new MockHttpServletRequest. + * @param servletContext the ServletContext that the request runs in + * (may be null to use a default MockServletContext) + * @param method the request method (may be null) + * @param requestURI the request URI (may be null) + * @see #setMethod + * @see #setRequestURI + * @see MockServletContext + */ + public MockHttpServletRequest(ServletContext servletContext, String method, String requestURI) { + this.servletContext = (servletContext != null ? servletContext : new MockServletContext()); + this.method = method; + this.requestURI = requestURI; + this.locales.add(Locale.ENGLISH); + } + + + //--------------------------------------------------------------------- + // Lifecycle methods + //--------------------------------------------------------------------- + + /** + * Return the ServletContext that this request is associated with. + * (Not available in the standard HttpServletRequest interface for some reason.) + */ + public ServletContext getServletContext() { + return this.servletContext; + } + + /** + * Return whether this request is still active (that is, not completed yet). + */ + public boolean isActive() { + return this.active; + } + + /** + * Mark this request as completed, keeping its state. + */ + public void close() { + this.active = false; + } + + /** + * Invalidate this request, clearing its state. + */ + public void invalidate() { + close(); + clearAttributes(); + } + + /** + * Check whether this request is still active (that is, not completed yet), + * throwing an IllegalStateException if not active anymore. + */ + protected void checkActive() throws IllegalStateException { + if (!this.active) { + throw new IllegalStateException("Request is not active anymore"); + } + } + + + //--------------------------------------------------------------------- + // ServletRequest interface + //--------------------------------------------------------------------- + + public Object getAttribute(String name) { + checkActive(); + return this.attributes.get(name); + } + + public Enumeration getAttributeNames() { + checkActive(); + return Collections.enumeration(this.attributes.keySet()); + } + + public String getCharacterEncoding() { + return this.characterEncoding; + } + + public void setCharacterEncoding(String characterEncoding) { + this.characterEncoding = characterEncoding; + updateContentTypeHeader(); + } + + private void updateContentTypeHeader() { + if (this.contentType != null) { + StringBuilder sb = new StringBuilder(this.contentType); + if (this.contentType.toLowerCase().indexOf(CHARSET_PREFIX) == -1 && this.characterEncoding != null) { + sb.append(";").append(CHARSET_PREFIX).append(this.characterEncoding); + } + doAddHeaderValue(CONTENT_TYPE_HEADER, sb.toString(), true); + } + } + + public void setContent(byte[] content) { + this.content = content; + } + + public int getContentLength() { + return (this.content != null ? this.content.length : -1); + } + + public void setContentType(String contentType) { + this.contentType = contentType; + if (contentType != null) { + int charsetIndex = contentType.toLowerCase().indexOf(CHARSET_PREFIX); + if (charsetIndex != -1) { + String encoding = contentType.substring(charsetIndex + CHARSET_PREFIX.length()); + this.characterEncoding = encoding; + } + updateContentTypeHeader(); + } + } + + public String getContentType() { + return this.contentType; + } + + public ServletInputStream getInputStream() { + if (this.content != null) { + return new DelegatingServletInputStream(new ByteArrayInputStream(this.content)); + } + else { + return null; + } + } + + /** + * Set a single value for the specified HTTP parameter. + *

If there are already one or more values registered for the given + * parameter name, they will be replaced. + */ + public void setParameter(String name, String value) { + setParameter(name, new String[] {value}); + } + + /** + * Set an array of values for the specified HTTP parameter. + *

If there are already one or more values registered for the given + * parameter name, they will be replaced. + */ + public void setParameter(String name, String[] values) { + Assert.notNull(name, "Parameter name must not be null"); + this.parameters.put(name, values); + } + + /** + * Sets all provided parameters replacing any + * existing values for the provided parameter names. To add without + * replacing existing values, use {@link #addParameters(java.util.Map)}. + */ + public void setParameters(Map params) { + Assert.notNull(params, "Parameter map must not be null"); + for (Object key : params.keySet()) { + Assert.isInstanceOf(String.class, key, + "Parameter map key must be of type [" + String.class.getName() + "]"); + Object value = params.get(key); + if (value instanceof String) { + this.setParameter((String) key, (String) value); + } + else if (value instanceof String[]) { + this.setParameter((String) key, (String[]) value); + } + else { + throw new IllegalArgumentException( + "Parameter map value must be single value " + " or array of type [" + String.class.getName() + + "]"); + } + } + } + + /** + * Add a single value for the specified HTTP parameter. + *

If there are already one or more values registered for the given + * parameter name, the given value will be added to the end of the list. + */ + public void addParameter(String name, String value) { + addParameter(name, new String[] {value}); + } + + /** + * Add an array of values for the specified HTTP parameter. + *

If there are already one or more values registered for the given + * parameter name, the given values will be added to the end of the list. + */ + public void addParameter(String name, String[] values) { + Assert.notNull(name, "Parameter name must not be null"); + String[] oldArr = this.parameters.get(name); + if (oldArr != null) { + String[] newArr = new String[oldArr.length + values.length]; + System.arraycopy(oldArr, 0, newArr, 0, oldArr.length); + System.arraycopy(values, 0, newArr, oldArr.length, values.length); + this.parameters.put(name, newArr); + } + else { + this.parameters.put(name, values); + } + } + + /** + * Adds all provided parameters without replacing + * any existing values. To replace existing values, use + * {@link #setParameters(java.util.Map)}. + */ + public void addParameters(Map params) { + Assert.notNull(params, "Parameter map must not be null"); + for (Object key : params.keySet()) { + Assert.isInstanceOf(String.class, key, + "Parameter map key must be of type [" + String.class.getName() + "]"); + Object value = params.get(key); + if (value instanceof String) { + this.addParameter((String) key, (String) value); + } + else if (value instanceof String[]) { + this.addParameter((String) key, (String[]) value); + } + else { + throw new IllegalArgumentException("Parameter map value must be single value " + + " or array of type [" + String.class.getName() + "]"); + } + } + } + + /** + * Remove already registered values for the specified HTTP parameter, if any. + */ + public void removeParameter(String name) { + Assert.notNull(name, "Parameter name must not be null"); + this.parameters.remove(name); + } + + /** + * Removes all existing parameters. + */ + public void removeAllParameters() { + this.parameters.clear(); + } + + public String getParameter(String name) { + Assert.notNull(name, "Parameter name must not be null"); + String[] arr = this.parameters.get(name); + return (arr != null && arr.length > 0 ? arr[0] : null); + } + + public Enumeration getParameterNames() { + return Collections.enumeration(this.parameters.keySet()); + } + + public String[] getParameterValues(String name) { + Assert.notNull(name, "Parameter name must not be null"); + return this.parameters.get(name); + } + + public Map getParameterMap() { + return Collections.unmodifiableMap(this.parameters); + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public String getProtocol() { + return this.protocol; + } + + public void setScheme(String scheme) { + this.scheme = scheme; + } + + public String getScheme() { + return this.scheme; + } + + public void setServerName(String serverName) { + this.serverName = serverName; + } + + public String getServerName() { + return this.serverName; + } + + public void setServerPort(int serverPort) { + this.serverPort = serverPort; + } + + public int getServerPort() { + return this.serverPort; + } + + public BufferedReader getReader() throws UnsupportedEncodingException { + if (this.content != null) { + InputStream sourceStream = new ByteArrayInputStream(this.content); + Reader sourceReader = (this.characterEncoding != null) ? + new InputStreamReader(sourceStream, this.characterEncoding) : new InputStreamReader(sourceStream); + return new BufferedReader(sourceReader); + } + else { + return null; + } + } + + public void setRemoteAddr(String remoteAddr) { + this.remoteAddr = remoteAddr; + } + + public String getRemoteAddr() { + return this.remoteAddr; + } + + public void setRemoteHost(String remoteHost) { + this.remoteHost = remoteHost; + } + + public String getRemoteHost() { + return this.remoteHost; + } + + public void setAttribute(String name, Object value) { + checkActive(); + Assert.notNull(name, "Attribute name must not be null"); + if (value != null) { + this.attributes.put(name, value); + } + else { + this.attributes.remove(name); + } + } + + public void removeAttribute(String name) { + checkActive(); + Assert.notNull(name, "Attribute name must not be null"); + this.attributes.remove(name); + } + + /** + * Clear all of this request's attributes. + */ + public void clearAttributes() { + this.attributes.clear(); + } + + /** + * Add a new preferred locale, before any existing locales. + */ + public void addPreferredLocale(Locale locale) { + Assert.notNull(locale, "Locale must not be null"); + this.locales.add(0, locale); + } + + public Locale getLocale() { + return this.locales.get(0); + } + + public Enumeration getLocales() { + return Collections.enumeration(this.locales); + } + + public void setSecure(boolean secure) { + this.secure = secure; + } + + public boolean isSecure() { + return this.secure; + } + + public RequestDispatcher getRequestDispatcher(String path) { + return new MockRequestDispatcher(path); + } + + public String getRealPath(String path) { + return this.servletContext.getRealPath(path); + } + + public void setRemotePort(int remotePort) { + this.remotePort = remotePort; + } + + public int getRemotePort() { + return this.remotePort; + } + + public void setLocalName(String localName) { + this.localName = localName; + } + + public String getLocalName() { + return this.localName; + } + + public void setLocalAddr(String localAddr) { + this.localAddr = localAddr; + } + + public String getLocalAddr() { + return this.localAddr; + } + + public void setLocalPort(int localPort) { + this.localPort = localPort; + } + + public int getLocalPort() { + return this.localPort; + } + + + //--------------------------------------------------------------------- + // HttpServletRequest interface + //--------------------------------------------------------------------- + + public void setAuthType(String authType) { + this.authType = authType; + } + + public String getAuthType() { + return this.authType; + } + + public void setCookies(Cookie... cookies) { + this.cookies = cookies; + } + + public Cookie[] getCookies() { + return this.cookies; + } + + /** + * Add a header entry for the given name. + *

If there was no entry for that header name before, + * the value will be used as-is. In case of an existing entry, + * a String array will be created, adding the given value (more + * specifically, its toString representation) as further element. + *

Multiple values can only be stored as list of Strings, + * following the Servlet spec (see getHeaders accessor). + * As alternative to repeated addHeader calls for + * individual elements, you can use a single call with an entire + * array or Collection of values as parameter. + * @see #getHeaderNames + * @see #getHeader + * @see #getHeaders + * @see #getDateHeader + * @see #getIntHeader + */ + public void addHeader(String name, Object value) { + if (CONTENT_TYPE_HEADER.equalsIgnoreCase(name)) { + setContentType((String) value); + return; + } + doAddHeaderValue(name, value, false); + } + + @SuppressWarnings("rawtypes") + private void doAddHeaderValue(String name, Object value, boolean replace) { + HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); + Assert.notNull(value, "Header value must not be null"); + if (header == null || replace) { + header = new HeaderValueHolder(); + this.headers.put(name, header); + } + if (value instanceof Collection) { + header.addValues((Collection) value); + } + else if (value.getClass().isArray()) { + header.addValueArray(value); + } + else { + header.addValue(value); + } + } + + public long getDateHeader(String name) { + HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); + Object value = (header != null ? header.getValue() : null); + if (value instanceof Date) { + return ((Date) value).getTime(); + } + else if (value instanceof Number) { + return ((Number) value).longValue(); + } + else if (value != null) { + throw new IllegalArgumentException( + "Value for header '" + name + "' is neither a Date nor a Number: " + value); + } + else { + return -1L; + } + } + + public String getHeader(String name) { + HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); + return (header != null ? header.getValue().toString() : null); + } + + public Enumeration getHeaders(String name) { + HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); + return Collections.enumeration(header != null ? header.getStringValues() : new LinkedList()); + } + + public Enumeration getHeaderNames() { + return Collections.enumeration(this.headers.keySet()); + } + + public int getIntHeader(String name) { + HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name); + Object value = (header != null ? header.getValue() : null); + if (value instanceof Number) { + return ((Number) value).intValue(); + } + else if (value instanceof String) { + return Integer.parseInt((String) value); + } + else if (value != null) { + throw new NumberFormatException("Value for header '" + name + "' is not a Number: " + value); + } + else { + return -1; + } + } + + public void setMethod(String method) { + this.method = method; + } + + public String getMethod() { + return this.method; + } + + public void setPathInfo(String pathInfo) { + this.pathInfo = pathInfo; + } + + public String getPathInfo() { + return this.pathInfo; + } + + public String getPathTranslated() { + return (this.pathInfo != null ? getRealPath(this.pathInfo) : null); + } + + public void setContextPath(String contextPath) { + this.contextPath = contextPath; + } + + public String getContextPath() { + return this.contextPath; + } + + public void setQueryString(String queryString) { + this.queryString = queryString; + } + + public String getQueryString() { + return this.queryString; + } + + public void setRemoteUser(String remoteUser) { + this.remoteUser = remoteUser; + } + + public String getRemoteUser() { + return this.remoteUser; + } + + public void addUserRole(String role) { + this.userRoles.add(role); + } + + public boolean isUserInRole(String role) { + return this.userRoles.contains(role); + } + + public void setUserPrincipal(Principal userPrincipal) { + this.userPrincipal = userPrincipal; + } + + public Principal getUserPrincipal() { + return this.userPrincipal; + } + + public void setRequestedSessionId(String requestedSessionId) { + this.requestedSessionId = requestedSessionId; + } + + public String getRequestedSessionId() { + return this.requestedSessionId; + } + + public void setRequestURI(String requestURI) { + this.requestURI = requestURI; + } + + public String getRequestURI() { + return this.requestURI; + } + + public StringBuffer getRequestURL() { + StringBuffer url = new StringBuffer(this.scheme); + url.append("://").append(this.serverName).append(':').append(this.serverPort); + url.append(getRequestURI()); + return url; + } + + public void setServletPath(String servletPath) { + this.servletPath = servletPath; + } + + public String getServletPath() { + return this.servletPath; + } + + public void setSession(HttpSession session) { + this.session = session; + if (session instanceof MockHttpSession) { + MockHttpSession mockSession = ((MockHttpSession) session); + mockSession.access(); + } + } + + public HttpSession getSession(boolean create) { + checkActive(); + // Reset session if invalidated. + if (this.session instanceof MockHttpSession && ((MockHttpSession) this.session).isInvalid()) { + this.session = null; + } + // Create new session if necessary. + if (this.session == null && create) { + this.session = new MockHttpSession(this.servletContext); + } + return this.session; + } + + public HttpSession getSession() { + return getSession(true); + } + + public void setRequestedSessionIdValid(boolean requestedSessionIdValid) { + this.requestedSessionIdValid = requestedSessionIdValid; + } + + public boolean isRequestedSessionIdValid() { + return this.requestedSessionIdValid; + } + + public void setRequestedSessionIdFromCookie(boolean requestedSessionIdFromCookie) { + this.requestedSessionIdFromCookie = requestedSessionIdFromCookie; + } + + public boolean isRequestedSessionIdFromCookie() { + return this.requestedSessionIdFromCookie; + } + + public void setRequestedSessionIdFromURL(boolean requestedSessionIdFromURL) { + this.requestedSessionIdFromURL = requestedSessionIdFromURL; + } + + public boolean isRequestedSessionIdFromURL() { + return this.requestedSessionIdFromURL; + } + + public boolean isRequestedSessionIdFromUrl() { + return isRequestedSessionIdFromURL(); + } + + + //--------------------------------------------------------------------- + // Methods introduced in Servlet 3.0 + //--------------------------------------------------------------------- + + public AsyncContext getAsyncContext() { + throw new UnsupportedOperationException(); + } + + public DispatcherType getDispatcherType() { + throw new UnsupportedOperationException(); + } + + public boolean isAsyncSupported() { + throw new UnsupportedOperationException(); + } + + public AsyncContext startAsync() { + throw new UnsupportedOperationException(); + } + + public AsyncContext startAsync(ServletRequest arg0, ServletResponse arg1) { + throw new UnsupportedOperationException(); + } + + public boolean isAsyncStarted() { + throw new UnsupportedOperationException(); + } + + public boolean authenticate(HttpServletResponse arg0) throws IOException, ServletException { + throw new UnsupportedOperationException(); + } + + public void addPart(Part part) { + parts.put(part.getName(), part); + } + + public Part getPart(String key) throws IOException, IllegalStateException, ServletException { + return parts.get(key); + } + + public Collection getParts() throws IOException, IllegalStateException, ServletException { + return parts.values(); + } + + public void login(String arg0, String arg1) throws ServletException { + throw new UnsupportedOperationException(); + } + + public void logout() throws ServletException { + throw new UnsupportedOperationException(); + } + +} diff --git a/org.springframework.web/src/test/java/org/springframework/mock/web/MockHttpSession.java b/org.springframework.web/src/test/java/org/springframework/mock/web/MockHttpSession.java index 3803e93712..757414dbbc 100644 --- a/org.springframework.web/src/test/java/org/springframework/mock/web/MockHttpSession.java +++ b/org.springframework.web/src/test/java/org/springframework/mock/web/MockHttpSession.java @@ -1,246 +1,246 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import java.io.Serializable; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; -import javax.servlet.ServletContext; -import javax.servlet.http.HttpSession; -import javax.servlet.http.HttpSessionBindingEvent; -import javax.servlet.http.HttpSessionBindingListener; -import javax.servlet.http.HttpSessionContext; - -import org.springframework.util.Assert; - -/** - * Mock implementation of the {@link javax.servlet.http.HttpSession} interface. - * Supports the Servlet 2.4 API level. - * - *

Used for testing the web framework; also useful for testing - * application controllers. - * - * @author Juergen Hoeller - * @author Rod Johnson - * @author Mark Fisher - * @since 1.0.2 - */ -public class MockHttpSession implements HttpSession { - - public static final String SESSION_COOKIE_NAME = "JSESSION"; - - private static int nextId = 1; - - - private final String id; - - private final long creationTime = System.currentTimeMillis(); - - private int maxInactiveInterval; - - private long lastAccessedTime = System.currentTimeMillis(); - - private final ServletContext servletContext; - - private final Map attributes = new LinkedHashMap(); - - private boolean invalid = false; - - private boolean isNew = true; - - - /** - * Create a new MockHttpSession with a default {@link MockServletContext}. - * @see MockServletContext - */ - public MockHttpSession() { - this(null); - } - - /** - * Create a new MockHttpSession. - * @param servletContext the ServletContext that the session runs in - */ - public MockHttpSession(ServletContext servletContext) { - this(servletContext, null); - } - - /** - * Create a new MockHttpSession. - * @param servletContext the ServletContext that the session runs in - * @param id a unique identifier for this session - */ - public MockHttpSession(ServletContext servletContext, String id) { - this.servletContext = (servletContext != null ? servletContext : new MockServletContext()); - this.id = (id != null ? id : Integer.toString(nextId++)); - } - - - public long getCreationTime() { - return this.creationTime; - } - - public String getId() { - return this.id; - } - - public void access() { - this.lastAccessedTime = System.currentTimeMillis(); - this.isNew = false; - } - - public long getLastAccessedTime() { - return this.lastAccessedTime; - } - - public ServletContext getServletContext() { - return this.servletContext; - } - - public void setMaxInactiveInterval(int interval) { - this.maxInactiveInterval = interval; - } - - public int getMaxInactiveInterval() { - return this.maxInactiveInterval; - } - - public HttpSessionContext getSessionContext() { - throw new UnsupportedOperationException("getSessionContext"); - } - - public Object getAttribute(String name) { - Assert.notNull(name, "Attribute name must not be null"); - return this.attributes.get(name); - } - - public Object getValue(String name) { - return getAttribute(name); - } - - public Enumeration getAttributeNames() { - return Collections.enumeration(this.attributes.keySet()); - } - - public String[] getValueNames() { - return this.attributes.keySet().toArray(new String[this.attributes.size()]); - } - - public void setAttribute(String name, Object value) { - Assert.notNull(name, "Attribute name must not be null"); - if (value != null) { - this.attributes.put(name, value); - if (value instanceof HttpSessionBindingListener) { - ((HttpSessionBindingListener) value).valueBound(new HttpSessionBindingEvent(this, name, value)); - } - } - else { - removeAttribute(name); - } - } - - public void putValue(String name, Object value) { - setAttribute(name, value); - } - - public void removeAttribute(String name) { - Assert.notNull(name, "Attribute name must not be null"); - Object value = this.attributes.remove(name); - if (value instanceof HttpSessionBindingListener) { - ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value)); - } - } - - public void removeValue(String name) { - removeAttribute(name); - } - - /** - * Clear all of this session's attributes. - */ - public void clearAttributes() { - for (Iterator> it = this.attributes.entrySet().iterator(); it.hasNext();) { - Map.Entry entry = it.next(); - String name = entry.getKey(); - Object value = entry.getValue(); - it.remove(); - if (value instanceof HttpSessionBindingListener) { - ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value)); - } - } - } - - public void invalidate() { - this.invalid = true; - clearAttributes(); - } - - public boolean isInvalid() { - return this.invalid; - } - - public void setNew(boolean value) { - this.isNew = value; - } - - public boolean isNew() { - return this.isNew; - } - - - /** - * Serialize the attributes of this session into an object that can - * be turned into a byte array with standard Java serialization. - * @return a representation of this session's serialized state - */ - public Serializable serializeState() { - HashMap state = new HashMap(); - for (Iterator> it = this.attributes.entrySet().iterator(); it.hasNext();) { - Map.Entry entry = it.next(); - String name = entry.getKey(); - Object value = entry.getValue(); - it.remove(); - if (value instanceof Serializable) { - state.put(name, (Serializable) value); - } - else { - // Not serializable... Servlet containers usually automatically - // unbind the attribute in this case. - if (value instanceof HttpSessionBindingListener) { - ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value)); - } - } - } - return state; - } - - /** - * Deserialize the attributes of this session from a state object - * created by {@link #serializeState()}. - * @param state a representation of this session's serialized state - */ - @SuppressWarnings("unchecked") - public void deserializeState(Serializable state) { - Assert.isTrue(state instanceof Map, "Serialized state needs to be of type [java.util.Map]"); - this.attributes.putAll((Map) state); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.io.Serializable; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpSessionBindingEvent; +import javax.servlet.http.HttpSessionBindingListener; +import javax.servlet.http.HttpSessionContext; + +import org.springframework.util.Assert; + +/** + * Mock implementation of the {@link javax.servlet.http.HttpSession} interface. + * Supports the Servlet 2.4 API level. + * + *

Used for testing the web framework; also useful for testing + * application controllers. + * + * @author Juergen Hoeller + * @author Rod Johnson + * @author Mark Fisher + * @since 1.0.2 + */ +public class MockHttpSession implements HttpSession { + + public static final String SESSION_COOKIE_NAME = "JSESSION"; + + private static int nextId = 1; + + + private final String id; + + private final long creationTime = System.currentTimeMillis(); + + private int maxInactiveInterval; + + private long lastAccessedTime = System.currentTimeMillis(); + + private final ServletContext servletContext; + + private final Map attributes = new LinkedHashMap(); + + private boolean invalid = false; + + private boolean isNew = true; + + + /** + * Create a new MockHttpSession with a default {@link MockServletContext}. + * @see MockServletContext + */ + public MockHttpSession() { + this(null); + } + + /** + * Create a new MockHttpSession. + * @param servletContext the ServletContext that the session runs in + */ + public MockHttpSession(ServletContext servletContext) { + this(servletContext, null); + } + + /** + * Create a new MockHttpSession. + * @param servletContext the ServletContext that the session runs in + * @param id a unique identifier for this session + */ + public MockHttpSession(ServletContext servletContext, String id) { + this.servletContext = (servletContext != null ? servletContext : new MockServletContext()); + this.id = (id != null ? id : Integer.toString(nextId++)); + } + + + public long getCreationTime() { + return this.creationTime; + } + + public String getId() { + return this.id; + } + + public void access() { + this.lastAccessedTime = System.currentTimeMillis(); + this.isNew = false; + } + + public long getLastAccessedTime() { + return this.lastAccessedTime; + } + + public ServletContext getServletContext() { + return this.servletContext; + } + + public void setMaxInactiveInterval(int interval) { + this.maxInactiveInterval = interval; + } + + public int getMaxInactiveInterval() { + return this.maxInactiveInterval; + } + + public HttpSessionContext getSessionContext() { + throw new UnsupportedOperationException("getSessionContext"); + } + + public Object getAttribute(String name) { + Assert.notNull(name, "Attribute name must not be null"); + return this.attributes.get(name); + } + + public Object getValue(String name) { + return getAttribute(name); + } + + public Enumeration getAttributeNames() { + return Collections.enumeration(this.attributes.keySet()); + } + + public String[] getValueNames() { + return this.attributes.keySet().toArray(new String[this.attributes.size()]); + } + + public void setAttribute(String name, Object value) { + Assert.notNull(name, "Attribute name must not be null"); + if (value != null) { + this.attributes.put(name, value); + if (value instanceof HttpSessionBindingListener) { + ((HttpSessionBindingListener) value).valueBound(new HttpSessionBindingEvent(this, name, value)); + } + } + else { + removeAttribute(name); + } + } + + public void putValue(String name, Object value) { + setAttribute(name, value); + } + + public void removeAttribute(String name) { + Assert.notNull(name, "Attribute name must not be null"); + Object value = this.attributes.remove(name); + if (value instanceof HttpSessionBindingListener) { + ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value)); + } + } + + public void removeValue(String name) { + removeAttribute(name); + } + + /** + * Clear all of this session's attributes. + */ + public void clearAttributes() { + for (Iterator> it = this.attributes.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = it.next(); + String name = entry.getKey(); + Object value = entry.getValue(); + it.remove(); + if (value instanceof HttpSessionBindingListener) { + ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value)); + } + } + } + + public void invalidate() { + this.invalid = true; + clearAttributes(); + } + + public boolean isInvalid() { + return this.invalid; + } + + public void setNew(boolean value) { + this.isNew = value; + } + + public boolean isNew() { + return this.isNew; + } + + + /** + * Serialize the attributes of this session into an object that can + * be turned into a byte array with standard Java serialization. + * @return a representation of this session's serialized state + */ + public Serializable serializeState() { + HashMap state = new HashMap(); + for (Iterator> it = this.attributes.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = it.next(); + String name = entry.getKey(); + Object value = entry.getValue(); + it.remove(); + if (value instanceof Serializable) { + state.put(name, (Serializable) value); + } + else { + // Not serializable... Servlet containers usually automatically + // unbind the attribute in this case. + if (value instanceof HttpSessionBindingListener) { + ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value)); + } + } + } + return state; + } + + /** + * Deserialize the attributes of this session from a state object + * created by {@link #serializeState()}. + * @param state a representation of this session's serialized state + */ + @SuppressWarnings("unchecked") + public void deserializeState(Serializable state) { + Assert.isTrue(state instanceof Map, "Serialized state needs to be of type [java.util.Map]"); + this.attributes.putAll((Map) state); + } + +} diff --git a/org.springframework.web/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java b/org.springframework.web/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java index 396f0e7fd5..a87bea43c9 100644 --- a/org.springframework.web/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java +++ b/org.springframework.web/src/test/java/org/springframework/mock/web/MockRequestDispatcher.java @@ -1,91 +1,91 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.util.Assert; - -/** - * Mock implementation of the {@link javax.servlet.RequestDispatcher} interface. - * - *

Used for testing the web framework; typically not necessary for - * testing application controllers. - * - * @author Rod Johnson - * @author Juergen Hoeller - * @since 1.0.2 - */ -public class MockRequestDispatcher implements RequestDispatcher { - - private final Log logger = LogFactory.getLog(getClass()); - - private final String url; - - - /** - * Create a new MockRequestDispatcher for the given URL. - * @param url the URL to dispatch to. - */ - public MockRequestDispatcher(String url) { - Assert.notNull(url, "URL must not be null"); - this.url = url; - } - - - public void forward(ServletRequest request, ServletResponse response) { - Assert.notNull(request, "Request must not be null"); - Assert.notNull(response, "Response must not be null"); - if (response.isCommitted()) { - throw new IllegalStateException("Cannot perform forward - response is already committed"); - } - getMockHttpServletResponse(response).setForwardedUrl(this.url); - if (logger.isDebugEnabled()) { - logger.debug("MockRequestDispatcher: forwarding to URL [" + this.url + "]"); - } - } - - public void include(ServletRequest request, ServletResponse response) { - Assert.notNull(request, "Request must not be null"); - Assert.notNull(response, "Response must not be null"); - getMockHttpServletResponse(response).addIncludedUrl(this.url); - if (logger.isDebugEnabled()) { - logger.debug("MockRequestDispatcher: including URL [" + this.url + "]"); - } - } - - /** - * Obtain the underlying MockHttpServletResponse, - * unwrapping {@link HttpServletResponseWrapper} decorators if necessary. - */ - protected MockHttpServletResponse getMockHttpServletResponse(ServletResponse response) { - if (response instanceof MockHttpServletResponse) { - return (MockHttpServletResponse) response; - } - if (response instanceof HttpServletResponseWrapper) { - return getMockHttpServletResponse(((HttpServletResponseWrapper) response).getResponse()); - } - throw new IllegalArgumentException("MockRequestDispatcher requires MockHttpServletResponse"); - } - -} +/* + * Copyright 2002-2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.util.Assert; + +/** + * Mock implementation of the {@link javax.servlet.RequestDispatcher} interface. + * + *

Used for testing the web framework; typically not necessary for + * testing application controllers. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @since 1.0.2 + */ +public class MockRequestDispatcher implements RequestDispatcher { + + private final Log logger = LogFactory.getLog(getClass()); + + private final String url; + + + /** + * Create a new MockRequestDispatcher for the given URL. + * @param url the URL to dispatch to. + */ + public MockRequestDispatcher(String url) { + Assert.notNull(url, "URL must not be null"); + this.url = url; + } + + + public void forward(ServletRequest request, ServletResponse response) { + Assert.notNull(request, "Request must not be null"); + Assert.notNull(response, "Response must not be null"); + if (response.isCommitted()) { + throw new IllegalStateException("Cannot perform forward - response is already committed"); + } + getMockHttpServletResponse(response).setForwardedUrl(this.url); + if (logger.isDebugEnabled()) { + logger.debug("MockRequestDispatcher: forwarding to URL [" + this.url + "]"); + } + } + + public void include(ServletRequest request, ServletResponse response) { + Assert.notNull(request, "Request must not be null"); + Assert.notNull(response, "Response must not be null"); + getMockHttpServletResponse(response).addIncludedUrl(this.url); + if (logger.isDebugEnabled()) { + logger.debug("MockRequestDispatcher: including URL [" + this.url + "]"); + } + } + + /** + * Obtain the underlying MockHttpServletResponse, + * unwrapping {@link HttpServletResponseWrapper} decorators if necessary. + */ + protected MockHttpServletResponse getMockHttpServletResponse(ServletResponse response) { + if (response instanceof MockHttpServletResponse) { + return (MockHttpServletResponse) response; + } + if (response instanceof HttpServletResponseWrapper) { + return getMockHttpServletResponse(((HttpServletResponseWrapper) response).getResponse()); + } + throw new IllegalArgumentException("MockRequestDispatcher requires MockHttpServletResponse"); + } + +} diff --git a/org.springframework.web/src/test/java/org/springframework/mock/web/MockServletContext.java b/org.springframework.web/src/test/java/org/springframework/mock/web/MockServletContext.java index 828af03d2e..cd9d391735 100644 --- a/org.springframework.web/src/test/java/org/springframework/mock/web/MockServletContext.java +++ b/org.springframework.web/src/test/java/org/springframework/mock/web/MockServletContext.java @@ -1,507 +1,507 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.mock.web; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Collections; -import java.util.Enumeration; -import java.util.EventListener; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; -import javax.activation.FileTypeMap; -import javax.servlet.Filter; -import javax.servlet.FilterRegistration; -import javax.servlet.FilterRegistration.Dynamic; -import javax.servlet.RequestDispatcher; -import javax.servlet.Servlet; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRegistration; -import javax.servlet.SessionCookieConfig; -import javax.servlet.SessionTrackingMode; -import javax.servlet.descriptor.JspConfigDescriptor; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.core.io.DefaultResourceLoader; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; -import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; -import org.springframework.web.util.WebUtils; - -/** - * Mock implementation of the {@link javax.servlet.ServletContext} interface. - * - *

Used for testing the Spring web framework; only rarely necessary for testing - * application controllers. As long as application components don't explicitly - * access the ServletContext, ClassPathXmlApplicationContext or - * FileSystemXmlApplicationContext can be used to load the context files for testing, - * even for DispatcherServlet context definitions. - * - *

For setting up a full WebApplicationContext in a test environment, you can - * use XmlWebApplicationContext (or GenericWebApplicationContext), passing in an - * appropriate MockServletContext instance. You might want to configure your - * MockServletContext with a FileSystemResourceLoader in that case, to make your - * resource paths interpreted as relative file system locations. - * - *

A common setup is to point your JVM working directory to the root of your - * web application directory, in combination with filesystem-based resource loading. - * This allows to load the context files as used in the web application, with - * relative paths getting interpreted correctly. Such a setup will work with both - * FileSystemXmlApplicationContext (which will load straight from the file system) - * and XmlWebApplicationContext with an underlying MockServletContext (as long as - * the MockServletContext has been configured with a FileSystemResourceLoader). - * - *

Supports Servlet 3.0 API level, but throws {@link UnsupportedOperationException} - * for most methods introduced in Servlet 3.0. - * - * @author Rod Johnson - * @author Juergen Hoeller - * @author Chris Beams - * @since 1.0.2 - * @see #MockServletContext(org.springframework.core.io.ResourceLoader) - * @see org.springframework.web.context.support.XmlWebApplicationContext - * @see org.springframework.web.context.support.GenericWebApplicationContext - * @see org.springframework.context.support.ClassPathXmlApplicationContext - * @see org.springframework.context.support.FileSystemXmlApplicationContext - */ -public class MockServletContext implements ServletContext { - - private static final String TEMP_DIR_SYSTEM_PROPERTY = "java.io.tmpdir"; - - - private final Log logger = LogFactory.getLog(getClass()); - - private final ResourceLoader resourceLoader; - - private final String resourceBasePath; - - private String contextPath = ""; - - private int majorVersion = 2; - - private int minorVersion = 5; - - private int effectiveMajorVersion = 2; - - private int effectiveMinorVersion = 5; - - private final Map contexts = new HashMap(); - - private final Map initParameters = new LinkedHashMap(); - - private final Map attributes = new LinkedHashMap(); - - private String servletContextName = "MockServletContext"; - - - /** - * Create a new MockServletContext, using no base path and a - * DefaultResourceLoader (i.e. the classpath root as WAR root). - * @see org.springframework.core.io.DefaultResourceLoader - */ - public MockServletContext() { - this("", null); - } - - /** - * Create a new MockServletContext, using a DefaultResourceLoader. - * @param resourceBasePath the WAR root directory (should not end with a slash) - * @see org.springframework.core.io.DefaultResourceLoader - */ - public MockServletContext(String resourceBasePath) { - this(resourceBasePath, null); - } - - /** - * Create a new MockServletContext, using the specified ResourceLoader - * and no base path. - * @param resourceLoader the ResourceLoader to use (or null for the default) - */ - public MockServletContext(ResourceLoader resourceLoader) { - this("", resourceLoader); - } - - /** - * Create a new MockServletContext. - * @param resourceBasePath the WAR root directory (should not end with a slash) - * @param resourceLoader the ResourceLoader to use (or null for the default) - */ - public MockServletContext(String resourceBasePath, ResourceLoader resourceLoader) { - this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader()); - this.resourceBasePath = (resourceBasePath != null ? resourceBasePath : ""); - - // Use JVM temp dir as ServletContext temp dir. - String tempDir = System.getProperty(TEMP_DIR_SYSTEM_PROPERTY); - if (tempDir != null) { - this.attributes.put(WebUtils.TEMP_DIR_CONTEXT_ATTRIBUTE, new File(tempDir)); - } - } - - - /** - * Build a full resource location for the given path, - * prepending the resource base path of this MockServletContext. - * @param path the path as specified - * @return the full resource path - */ - protected String getResourceLocation(String path) { - if (!path.startsWith("/")) { - path = "/" + path; - } - return this.resourceBasePath + path; - } - - - public void setContextPath(String contextPath) { - this.contextPath = (contextPath != null ? contextPath : ""); - } - - /* This is a Servlet API 2.5 method. */ - public String getContextPath() { - return this.contextPath; - } - - public void registerContext(String contextPath, ServletContext context) { - this.contexts.put(contextPath, context); - } - - public ServletContext getContext(String contextPath) { - if (this.contextPath.equals(contextPath)) { - return this; - } - return this.contexts.get(contextPath); - } - - public void setMajorVersion(int majorVersion) { - this.majorVersion = majorVersion; - } - - public int getMajorVersion() { - return this.majorVersion; - } - - public void setMinorVersion(int minorVersion) { - this.minorVersion = minorVersion; - } - - public int getMinorVersion() { - return this.minorVersion; - } - - public void setEffectiveMajorVersion(int effectiveMajorVersion) { - this.effectiveMajorVersion = effectiveMajorVersion; - } - - public int getEffectiveMajorVersion() { - return this.effectiveMajorVersion; - } - - public void setEffectiveMinorVersion(int effectiveMinorVersion) { - this.effectiveMinorVersion = effectiveMinorVersion; - } - - public int getEffectiveMinorVersion() { - return this.effectiveMinorVersion; - } - - public String getMimeType(String filePath) { - return MimeTypeResolver.getMimeType(filePath); - } - - public Set getResourcePaths(String path) { - String actualPath = (path.endsWith("/") ? path : path + "/"); - Resource resource = this.resourceLoader.getResource(getResourceLocation(actualPath)); - try { - File file = resource.getFile(); - String[] fileList = file.list(); - if (ObjectUtils.isEmpty(fileList)) { - return null; - } - Set resourcePaths = new LinkedHashSet(fileList.length); - for (String fileEntry : fileList) { - String resultPath = actualPath + fileEntry; - if (resource.createRelative(fileEntry).getFile().isDirectory()) { - resultPath += "/"; - } - resourcePaths.add(resultPath); - } - return resourcePaths; - } - catch (IOException ex) { - logger.warn("Couldn't get resource paths for " + resource, ex); - return null; - } - } - - public URL getResource(String path) throws MalformedURLException { - Resource resource = this.resourceLoader.getResource(getResourceLocation(path)); - if (!resource.exists()) { - return null; - } - try { - return resource.getURL(); - } - catch (MalformedURLException ex) { - throw ex; - } - catch (IOException ex) { - logger.warn("Couldn't get URL for " + resource, ex); - return null; - } - } - - public InputStream getResourceAsStream(String path) { - Resource resource = this.resourceLoader.getResource(getResourceLocation(path)); - if (!resource.exists()) { - return null; - } - try { - return resource.getInputStream(); - } - catch (IOException ex) { - logger.warn("Couldn't open InputStream for " + resource, ex); - return null; - } - } - - public RequestDispatcher getRequestDispatcher(String path) { - if (!path.startsWith("/")) { - throw new IllegalArgumentException("RequestDispatcher path at ServletContext level must start with '/'"); - } - return new MockRequestDispatcher(path); - } - - public RequestDispatcher getNamedDispatcher(String path) { - return null; - } - - public Servlet getServlet(String name) { - return null; - } - - public Enumeration getServlets() { - return Collections.enumeration(new HashSet()); - } - - public Enumeration getServletNames() { - return Collections.enumeration(new HashSet()); - } - - public void log(String message) { - logger.info(message); - } - - public void log(Exception ex, String message) { - logger.info(message, ex); - } - - public void log(String message, Throwable ex) { - logger.info(message, ex); - } - - public String getRealPath(String path) { - Resource resource = this.resourceLoader.getResource(getResourceLocation(path)); - try { - return resource.getFile().getAbsolutePath(); - } - catch (IOException ex) { - logger.warn("Couldn't determine real path of resource " + resource, ex); - return null; - } - } - - public String getServerInfo() { - return "MockServletContext"; - } - - public String getInitParameter(String name) { - Assert.notNull(name, "Parameter name must not be null"); - return this.initParameters.get(name); - } - - public void addInitParameter(String name, String value) { - Assert.notNull(name, "Parameter name must not be null"); - this.initParameters.put(name, value); - } - - public Enumeration getInitParameterNames() { - return Collections.enumeration(this.initParameters.keySet()); - } - - public Object getAttribute(String name) { - Assert.notNull(name, "Attribute name must not be null"); - return this.attributes.get(name); - } - - public Enumeration getAttributeNames() { - return Collections.enumeration(this.attributes.keySet()); - } - - public void setAttribute(String name, Object value) { - Assert.notNull(name, "Attribute name must not be null"); - if (value != null) { - this.attributes.put(name, value); - } - else { - this.attributes.remove(name); - } - } - - public void removeAttribute(String name) { - Assert.notNull(name, "Attribute name must not be null"); - this.attributes.remove(name); - } - - public void setServletContextName(String servletContextName) { - this.servletContextName = servletContextName; - } - - public String getServletContextName() { - return this.servletContextName; - } - - - /** - * Inner factory class used to just introduce a Java Activation Framework - * dependency when actually asked to resolve a MIME type. - */ - private static class MimeTypeResolver { - - public static String getMimeType(String filePath) { - return FileTypeMap.getDefaultFileTypeMap().getContentType(filePath); - } - } - - - //--------------------------------------------------------------------- - // Methods introduced in Servlet 3.0 - //--------------------------------------------------------------------- - - public Dynamic addFilter(String arg0, String arg1) { - throw new UnsupportedOperationException(); - } - - public Dynamic addFilter(String arg0, Filter arg1) { - throw new UnsupportedOperationException(); - } - - public Dynamic addFilter(String arg0, Class arg1) { - throw new UnsupportedOperationException(); - } - - public void addListener(Class arg0) { - throw new UnsupportedOperationException(); - } - - public void addListener(String arg0) { - throw new UnsupportedOperationException(); - } - - public void addListener(T arg0) { - throw new UnsupportedOperationException(); - } - - public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, String arg1) { - throw new UnsupportedOperationException(); - } - - public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, - Servlet arg1) { - throw new UnsupportedOperationException(); - } - - public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, - Class arg1) { - throw new UnsupportedOperationException(); - } - - public T createFilter(Class arg0) - throws ServletException { - throw new UnsupportedOperationException(); - } - - public T createListener(Class arg0) - throws ServletException { - throw new UnsupportedOperationException(); - } - - public T createServlet(Class arg0) - throws ServletException { - throw new UnsupportedOperationException(); - } - - public void declareRoles(String... arg0) { - throw new UnsupportedOperationException(); - } - - public ClassLoader getClassLoader() { - throw new UnsupportedOperationException(); - } - - public Set getDefaultSessionTrackingModes() { - throw new UnsupportedOperationException(); - } - - public Set getEffectiveSessionTrackingModes() { - throw new UnsupportedOperationException(); - } - - public FilterRegistration getFilterRegistration(String arg0) { - throw new UnsupportedOperationException(); - } - - public Map getFilterRegistrations() { - throw new UnsupportedOperationException(); - } - - public JspConfigDescriptor getJspConfigDescriptor() { - throw new UnsupportedOperationException(); - } - - public ServletRegistration getServletRegistration(String arg0) { - throw new UnsupportedOperationException(); - } - - public Map getServletRegistrations() { - throw new UnsupportedOperationException(); - } - - public SessionCookieConfig getSessionCookieConfig() { - throw new UnsupportedOperationException(); - } - - public boolean setInitParameter(String arg0, String arg1) { - throw new UnsupportedOperationException(); - } - - public void setSessionTrackingModes(Set arg0) - throws IllegalStateException, IllegalArgumentException { - throw new UnsupportedOperationException(); - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.mock.web; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import java.util.EventListener; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import javax.activation.FileTypeMap; +import javax.servlet.Filter; +import javax.servlet.FilterRegistration; +import javax.servlet.FilterRegistration.Dynamic; +import javax.servlet.RequestDispatcher; +import javax.servlet.Servlet; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; +import javax.servlet.SessionCookieConfig; +import javax.servlet.SessionTrackingMode; +import javax.servlet.descriptor.JspConfigDescriptor; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; +import org.springframework.web.util.WebUtils; + +/** + * Mock implementation of the {@link javax.servlet.ServletContext} interface. + * + *

Used for testing the Spring web framework; only rarely necessary for testing + * application controllers. As long as application components don't explicitly + * access the ServletContext, ClassPathXmlApplicationContext or + * FileSystemXmlApplicationContext can be used to load the context files for testing, + * even for DispatcherServlet context definitions. + * + *

For setting up a full WebApplicationContext in a test environment, you can + * use XmlWebApplicationContext (or GenericWebApplicationContext), passing in an + * appropriate MockServletContext instance. You might want to configure your + * MockServletContext with a FileSystemResourceLoader in that case, to make your + * resource paths interpreted as relative file system locations. + * + *

A common setup is to point your JVM working directory to the root of your + * web application directory, in combination with filesystem-based resource loading. + * This allows to load the context files as used in the web application, with + * relative paths getting interpreted correctly. Such a setup will work with both + * FileSystemXmlApplicationContext (which will load straight from the file system) + * and XmlWebApplicationContext with an underlying MockServletContext (as long as + * the MockServletContext has been configured with a FileSystemResourceLoader). + * + *

Supports Servlet 3.0 API level, but throws {@link UnsupportedOperationException} + * for most methods introduced in Servlet 3.0. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @author Chris Beams + * @since 1.0.2 + * @see #MockServletContext(org.springframework.core.io.ResourceLoader) + * @see org.springframework.web.context.support.XmlWebApplicationContext + * @see org.springframework.web.context.support.GenericWebApplicationContext + * @see org.springframework.context.support.ClassPathXmlApplicationContext + * @see org.springframework.context.support.FileSystemXmlApplicationContext + */ +public class MockServletContext implements ServletContext { + + private static final String TEMP_DIR_SYSTEM_PROPERTY = "java.io.tmpdir"; + + + private final Log logger = LogFactory.getLog(getClass()); + + private final ResourceLoader resourceLoader; + + private final String resourceBasePath; + + private String contextPath = ""; + + private int majorVersion = 2; + + private int minorVersion = 5; + + private int effectiveMajorVersion = 2; + + private int effectiveMinorVersion = 5; + + private final Map contexts = new HashMap(); + + private final Map initParameters = new LinkedHashMap(); + + private final Map attributes = new LinkedHashMap(); + + private String servletContextName = "MockServletContext"; + + + /** + * Create a new MockServletContext, using no base path and a + * DefaultResourceLoader (i.e. the classpath root as WAR root). + * @see org.springframework.core.io.DefaultResourceLoader + */ + public MockServletContext() { + this("", null); + } + + /** + * Create a new MockServletContext, using a DefaultResourceLoader. + * @param resourceBasePath the WAR root directory (should not end with a slash) + * @see org.springframework.core.io.DefaultResourceLoader + */ + public MockServletContext(String resourceBasePath) { + this(resourceBasePath, null); + } + + /** + * Create a new MockServletContext, using the specified ResourceLoader + * and no base path. + * @param resourceLoader the ResourceLoader to use (or null for the default) + */ + public MockServletContext(ResourceLoader resourceLoader) { + this("", resourceLoader); + } + + /** + * Create a new MockServletContext. + * @param resourceBasePath the WAR root directory (should not end with a slash) + * @param resourceLoader the ResourceLoader to use (or null for the default) + */ + public MockServletContext(String resourceBasePath, ResourceLoader resourceLoader) { + this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader()); + this.resourceBasePath = (resourceBasePath != null ? resourceBasePath : ""); + + // Use JVM temp dir as ServletContext temp dir. + String tempDir = System.getProperty(TEMP_DIR_SYSTEM_PROPERTY); + if (tempDir != null) { + this.attributes.put(WebUtils.TEMP_DIR_CONTEXT_ATTRIBUTE, new File(tempDir)); + } + } + + + /** + * Build a full resource location for the given path, + * prepending the resource base path of this MockServletContext. + * @param path the path as specified + * @return the full resource path + */ + protected String getResourceLocation(String path) { + if (!path.startsWith("/")) { + path = "/" + path; + } + return this.resourceBasePath + path; + } + + + public void setContextPath(String contextPath) { + this.contextPath = (contextPath != null ? contextPath : ""); + } + + /* This is a Servlet API 2.5 method. */ + public String getContextPath() { + return this.contextPath; + } + + public void registerContext(String contextPath, ServletContext context) { + this.contexts.put(contextPath, context); + } + + public ServletContext getContext(String contextPath) { + if (this.contextPath.equals(contextPath)) { + return this; + } + return this.contexts.get(contextPath); + } + + public void setMajorVersion(int majorVersion) { + this.majorVersion = majorVersion; + } + + public int getMajorVersion() { + return this.majorVersion; + } + + public void setMinorVersion(int minorVersion) { + this.minorVersion = minorVersion; + } + + public int getMinorVersion() { + return this.minorVersion; + } + + public void setEffectiveMajorVersion(int effectiveMajorVersion) { + this.effectiveMajorVersion = effectiveMajorVersion; + } + + public int getEffectiveMajorVersion() { + return this.effectiveMajorVersion; + } + + public void setEffectiveMinorVersion(int effectiveMinorVersion) { + this.effectiveMinorVersion = effectiveMinorVersion; + } + + public int getEffectiveMinorVersion() { + return this.effectiveMinorVersion; + } + + public String getMimeType(String filePath) { + return MimeTypeResolver.getMimeType(filePath); + } + + public Set getResourcePaths(String path) { + String actualPath = (path.endsWith("/") ? path : path + "/"); + Resource resource = this.resourceLoader.getResource(getResourceLocation(actualPath)); + try { + File file = resource.getFile(); + String[] fileList = file.list(); + if (ObjectUtils.isEmpty(fileList)) { + return null; + } + Set resourcePaths = new LinkedHashSet(fileList.length); + for (String fileEntry : fileList) { + String resultPath = actualPath + fileEntry; + if (resource.createRelative(fileEntry).getFile().isDirectory()) { + resultPath += "/"; + } + resourcePaths.add(resultPath); + } + return resourcePaths; + } + catch (IOException ex) { + logger.warn("Couldn't get resource paths for " + resource, ex); + return null; + } + } + + public URL getResource(String path) throws MalformedURLException { + Resource resource = this.resourceLoader.getResource(getResourceLocation(path)); + if (!resource.exists()) { + return null; + } + try { + return resource.getURL(); + } + catch (MalformedURLException ex) { + throw ex; + } + catch (IOException ex) { + logger.warn("Couldn't get URL for " + resource, ex); + return null; + } + } + + public InputStream getResourceAsStream(String path) { + Resource resource = this.resourceLoader.getResource(getResourceLocation(path)); + if (!resource.exists()) { + return null; + } + try { + return resource.getInputStream(); + } + catch (IOException ex) { + logger.warn("Couldn't open InputStream for " + resource, ex); + return null; + } + } + + public RequestDispatcher getRequestDispatcher(String path) { + if (!path.startsWith("/")) { + throw new IllegalArgumentException("RequestDispatcher path at ServletContext level must start with '/'"); + } + return new MockRequestDispatcher(path); + } + + public RequestDispatcher getNamedDispatcher(String path) { + return null; + } + + public Servlet getServlet(String name) { + return null; + } + + public Enumeration getServlets() { + return Collections.enumeration(new HashSet()); + } + + public Enumeration getServletNames() { + return Collections.enumeration(new HashSet()); + } + + public void log(String message) { + logger.info(message); + } + + public void log(Exception ex, String message) { + logger.info(message, ex); + } + + public void log(String message, Throwable ex) { + logger.info(message, ex); + } + + public String getRealPath(String path) { + Resource resource = this.resourceLoader.getResource(getResourceLocation(path)); + try { + return resource.getFile().getAbsolutePath(); + } + catch (IOException ex) { + logger.warn("Couldn't determine real path of resource " + resource, ex); + return null; + } + } + + public String getServerInfo() { + return "MockServletContext"; + } + + public String getInitParameter(String name) { + Assert.notNull(name, "Parameter name must not be null"); + return this.initParameters.get(name); + } + + public void addInitParameter(String name, String value) { + Assert.notNull(name, "Parameter name must not be null"); + this.initParameters.put(name, value); + } + + public Enumeration getInitParameterNames() { + return Collections.enumeration(this.initParameters.keySet()); + } + + public Object getAttribute(String name) { + Assert.notNull(name, "Attribute name must not be null"); + return this.attributes.get(name); + } + + public Enumeration getAttributeNames() { + return Collections.enumeration(this.attributes.keySet()); + } + + public void setAttribute(String name, Object value) { + Assert.notNull(name, "Attribute name must not be null"); + if (value != null) { + this.attributes.put(name, value); + } + else { + this.attributes.remove(name); + } + } + + public void removeAttribute(String name) { + Assert.notNull(name, "Attribute name must not be null"); + this.attributes.remove(name); + } + + public void setServletContextName(String servletContextName) { + this.servletContextName = servletContextName; + } + + public String getServletContextName() { + return this.servletContextName; + } + + + /** + * Inner factory class used to just introduce a Java Activation Framework + * dependency when actually asked to resolve a MIME type. + */ + private static class MimeTypeResolver { + + public static String getMimeType(String filePath) { + return FileTypeMap.getDefaultFileTypeMap().getContentType(filePath); + } + } + + + //--------------------------------------------------------------------- + // Methods introduced in Servlet 3.0 + //--------------------------------------------------------------------- + + public Dynamic addFilter(String arg0, String arg1) { + throw new UnsupportedOperationException(); + } + + public Dynamic addFilter(String arg0, Filter arg1) { + throw new UnsupportedOperationException(); + } + + public Dynamic addFilter(String arg0, Class arg1) { + throw new UnsupportedOperationException(); + } + + public void addListener(Class arg0) { + throw new UnsupportedOperationException(); + } + + public void addListener(String arg0) { + throw new UnsupportedOperationException(); + } + + public void addListener(T arg0) { + throw new UnsupportedOperationException(); + } + + public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, String arg1) { + throw new UnsupportedOperationException(); + } + + public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, + Servlet arg1) { + throw new UnsupportedOperationException(); + } + + public javax.servlet.ServletRegistration.Dynamic addServlet(String arg0, + Class arg1) { + throw new UnsupportedOperationException(); + } + + public T createFilter(Class arg0) + throws ServletException { + throw new UnsupportedOperationException(); + } + + public T createListener(Class arg0) + throws ServletException { + throw new UnsupportedOperationException(); + } + + public T createServlet(Class arg0) + throws ServletException { + throw new UnsupportedOperationException(); + } + + public void declareRoles(String... arg0) { + throw new UnsupportedOperationException(); + } + + public ClassLoader getClassLoader() { + throw new UnsupportedOperationException(); + } + + public Set getDefaultSessionTrackingModes() { + throw new UnsupportedOperationException(); + } + + public Set getEffectiveSessionTrackingModes() { + throw new UnsupportedOperationException(); + } + + public FilterRegistration getFilterRegistration(String arg0) { + throw new UnsupportedOperationException(); + } + + public Map getFilterRegistrations() { + throw new UnsupportedOperationException(); + } + + public JspConfigDescriptor getJspConfigDescriptor() { + throw new UnsupportedOperationException(); + } + + public ServletRegistration getServletRegistration(String arg0) { + throw new UnsupportedOperationException(); + } + + public Map getServletRegistrations() { + throw new UnsupportedOperationException(); + } + + public SessionCookieConfig getSessionCookieConfig() { + throw new UnsupportedOperationException(); + } + + public boolean setInitParameter(String arg0, String arg1) { + throw new UnsupportedOperationException(); + } + + public void setSessionTrackingModes(Set arg0) + throws IllegalStateException, IllegalArgumentException { + throw new UnsupportedOperationException(); + } + +} diff --git a/org.springframework.web/src/test/java/org/springframework/web/context/request/WebApplicationContextScopeTests.java b/org.springframework.web/src/test/java/org/springframework/web/context/request/WebApplicationContextScopeTests.java index 26ef5cd60e..7366c555b6 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/context/request/WebApplicationContextScopeTests.java +++ b/org.springframework.web/src/test/java/org/springframework/web/context/request/WebApplicationContextScopeTests.java @@ -1,100 +1,100 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.web.context.request; - -import javax.servlet.ServletContextEvent; - -import static org.junit.Assert.*; -import org.junit.Test; - -import org.springframework.beans.DerivedTestBean; -import org.springframework.beans.factory.support.GenericBeanDefinition; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockServletContext; -import org.springframework.web.context.ContextCleanupListener; -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.context.support.GenericWebApplicationContext; - -/** - * @author Juergen Hoeller - */ -public class WebApplicationContextScopeTests { - - private static final String NAME = "scoped"; - - - private WebApplicationContext initApplicationContext(String scope) { - MockServletContext sc = new MockServletContext(); - GenericWebApplicationContext ac = new GenericWebApplicationContext(sc); - GenericBeanDefinition bd = new GenericBeanDefinition(); - bd.setBeanClass(DerivedTestBean.class); - bd.setScope(scope); - ac.registerBeanDefinition(NAME, bd); - ac.refresh(); - return ac; - } - - @Test - public void testRequestScope() { - WebApplicationContext ac = initApplicationContext(WebApplicationContext.SCOPE_REQUEST); - MockHttpServletRequest request = new MockHttpServletRequest(); - ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request); - RequestContextHolder.setRequestAttributes(requestAttributes); - try { - assertNull(request.getAttribute(NAME)); - DerivedTestBean bean = ac.getBean(NAME, DerivedTestBean.class); - assertSame(bean, request.getAttribute(NAME)); - assertSame(bean, ac.getBean(NAME)); - requestAttributes.requestCompleted(); - assertTrue(bean.wasDestroyed()); - } - finally { - RequestContextHolder.setRequestAttributes(null); - } - } - - @Test - public void testSessionScope() { - WebApplicationContext ac = initApplicationContext(WebApplicationContext.SCOPE_SESSION); - MockHttpServletRequest request = new MockHttpServletRequest(); - ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request); - RequestContextHolder.setRequestAttributes(requestAttributes); - try { - assertNull(request.getSession().getAttribute(NAME)); - DerivedTestBean bean = ac.getBean(NAME, DerivedTestBean.class); - assertSame(bean, request.getSession().getAttribute(NAME)); - assertSame(bean, ac.getBean(NAME)); - request.getSession().invalidate(); - assertTrue(bean.wasDestroyed()); - } - finally { - RequestContextHolder.setRequestAttributes(null); - } - } - - @Test - public void testApplicationScope() { - WebApplicationContext ac = initApplicationContext(WebApplicationContext.SCOPE_APPLICATION); - assertNull(ac.getServletContext().getAttribute(NAME)); - DerivedTestBean bean = ac.getBean(NAME, DerivedTestBean.class); - assertSame(bean, ac.getServletContext().getAttribute(NAME)); - assertSame(bean, ac.getBean(NAME)); - new ContextCleanupListener().contextDestroyed(new ServletContextEvent(ac.getServletContext())); - assertTrue(bean.wasDestroyed()); - } - -} +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context.request; + +import javax.servlet.ServletContextEvent; + +import static org.junit.Assert.*; +import org.junit.Test; + +import org.springframework.beans.DerivedTestBean; +import org.springframework.beans.factory.support.GenericBeanDefinition; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.ContextCleanupListener; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.GenericWebApplicationContext; + +/** + * @author Juergen Hoeller + */ +public class WebApplicationContextScopeTests { + + private static final String NAME = "scoped"; + + + private WebApplicationContext initApplicationContext(String scope) { + MockServletContext sc = new MockServletContext(); + GenericWebApplicationContext ac = new GenericWebApplicationContext(sc); + GenericBeanDefinition bd = new GenericBeanDefinition(); + bd.setBeanClass(DerivedTestBean.class); + bd.setScope(scope); + ac.registerBeanDefinition(NAME, bd); + ac.refresh(); + return ac; + } + + @Test + public void testRequestScope() { + WebApplicationContext ac = initApplicationContext(WebApplicationContext.SCOPE_REQUEST); + MockHttpServletRequest request = new MockHttpServletRequest(); + ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request); + RequestContextHolder.setRequestAttributes(requestAttributes); + try { + assertNull(request.getAttribute(NAME)); + DerivedTestBean bean = ac.getBean(NAME, DerivedTestBean.class); + assertSame(bean, request.getAttribute(NAME)); + assertSame(bean, ac.getBean(NAME)); + requestAttributes.requestCompleted(); + assertTrue(bean.wasDestroyed()); + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + } + + @Test + public void testSessionScope() { + WebApplicationContext ac = initApplicationContext(WebApplicationContext.SCOPE_SESSION); + MockHttpServletRequest request = new MockHttpServletRequest(); + ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request); + RequestContextHolder.setRequestAttributes(requestAttributes); + try { + assertNull(request.getSession().getAttribute(NAME)); + DerivedTestBean bean = ac.getBean(NAME, DerivedTestBean.class); + assertSame(bean, request.getSession().getAttribute(NAME)); + assertSame(bean, ac.getBean(NAME)); + request.getSession().invalidate(); + assertTrue(bean.wasDestroyed()); + } + finally { + RequestContextHolder.setRequestAttributes(null); + } + } + + @Test + public void testApplicationScope() { + WebApplicationContext ac = initApplicationContext(WebApplicationContext.SCOPE_APPLICATION); + assertNull(ac.getServletContext().getAttribute(NAME)); + DerivedTestBean bean = ac.getBean(NAME, DerivedTestBean.class); + assertSame(bean, ac.getServletContext().getAttribute(NAME)); + assertSame(bean, ac.getBean(NAME)); + new ContextCleanupListener().contextDestroyed(new ServletContextEvent(ac.getServletContext())); + assertTrue(bean.wasDestroyed()); + } + +} diff --git a/org.springframework.web/src/test/java/org/springframework/web/context/support/SpringBeanAutowiringSupportTests.java b/org.springframework.web/src/test/java/org/springframework/web/context/support/SpringBeanAutowiringSupportTests.java index dfa22e3a5c..72ac783005 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/context/support/SpringBeanAutowiringSupportTests.java +++ b/org.springframework.web/src/test/java/org/springframework/web/context/support/SpringBeanAutowiringSupportTests.java @@ -1,62 +1,62 @@ -/* - * Copyright 2002-2011 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.context.support; - -import org.junit.Test; - -import org.springframework.beans.ITestBean; -import org.springframework.beans.MutablePropertyValues; -import org.springframework.beans.TestBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.mock.web.MockServletContext; -import org.springframework.web.context.WebApplicationContext; - -import static org.junit.Assert.*; - -/** - * @author Juergen Hoeller - */ -public class SpringBeanAutowiringSupportTests { - - @Test - public void testProcessInjectionBasedOnServletContext() { - MockServletContext sc = new MockServletContext(); - StaticWebApplicationContext wac = new StaticWebApplicationContext(); - MutablePropertyValues pvs = new MutablePropertyValues(); - pvs.add("name", "tb"); - wac.registerSingleton("testBean", TestBean.class, pvs); - wac.setServletContext(sc); - wac.refresh(); - sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); - InjectionTarget target = new InjectionTarget(); - SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(target, sc); - assertTrue(target.testBean instanceof TestBean); - assertEquals("tb", target.name); - } - - - public static class InjectionTarget { - - @Autowired - public ITestBean testBean; - - @Value("#{testBean.name}") - public String name; - } - -} +/* + * Copyright 2002-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.context.support; + +import org.junit.Test; + +import org.springframework.beans.ITestBean; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.TestBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.WebApplicationContext; + +import static org.junit.Assert.*; + +/** + * @author Juergen Hoeller + */ +public class SpringBeanAutowiringSupportTests { + + @Test + public void testProcessInjectionBasedOnServletContext() { + MockServletContext sc = new MockServletContext(); + StaticWebApplicationContext wac = new StaticWebApplicationContext(); + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.add("name", "tb"); + wac.registerSingleton("testBean", TestBean.class, pvs); + wac.setServletContext(sc); + wac.refresh(); + sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); + InjectionTarget target = new InjectionTarget(); + SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(target, sc); + assertTrue(target.testBean instanceof TestBean); + assertEquals("tb", target.name); + } + + + public static class InjectionTarget { + + @Autowired + public ITestBean testBean; + + @Value("#{testBean.name}") + public String name; + } + +}