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/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; + } + +}