diff options
Diffstat (limited to 'spring-context/src/test/java')
87 files changed, 3038 insertions, 795 deletions
diff --git a/spring-context/src/test/java/org/springframework/aop/aspectj/AspectAndAdvicePrecedenceTests.java b/spring-context/src/test/java/org/springframework/aop/aspectj/AspectAndAdvicePrecedenceTests.java index 2e4cfe2f..99bde98e 100644 --- a/spring-context/src/test/java/org/springframework/aop/aspectj/AspectAndAdvicePrecedenceTests.java +++ b/spring-context/src/test/java/org/springframework/aop/aspectj/AspectAndAdvicePrecedenceTests.java @@ -186,7 +186,9 @@ class PrecedenceTestAspect implements BeanNameAware, Ordered { try { ret = ((Integer)pjp.proceed()).intValue(); } - catch(Throwable t) { throw new RuntimeException(t); } + catch (Throwable t) { + throw new RuntimeException(t); + } this.collaborator.aroundAdviceOne(this.name); return ret; } @@ -197,7 +199,9 @@ class PrecedenceTestAspect implements BeanNameAware, Ordered { try { ret = ((Integer)pjp.proceed()).intValue(); } - catch(Throwable t) {throw new RuntimeException(t);} + catch (Throwable t) { + throw new RuntimeException(t); + } this.collaborator.aroundAdviceTwo(this.name); return ret; } diff --git a/spring-context/src/test/java/org/springframework/aop/aspectj/_TestTypes.java b/spring-context/src/test/java/org/springframework/aop/aspectj/_TestTypes.java index 1490cf35..e4ebeb13 100644 --- a/spring-context/src/test/java/org/springframework/aop/aspectj/_TestTypes.java +++ b/spring-context/src/test/java/org/springframework/aop/aspectj/_TestTypes.java @@ -36,7 +36,7 @@ final class _TestTypes { } /** - * Aspect used as part of before before advice binding tests and + * Aspect used as part of before advice binding tests and * serves as base class for a number of more specialized test aspects. * * @author Adrian Colyer diff --git a/spring-context/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotationBindingTests.java b/spring-context/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotationBindingTests.java index 82b20d96..a7f24b51 100644 --- a/spring-context/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotationBindingTests.java +++ b/spring-context/src/test/java/org/springframework/aop/aspectj/autoproxy/AnnotationBindingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,18 +27,19 @@ import static org.junit.Assert.*; * @author Adrian Colyer * @author Chris Beams */ -public final class AnnotationBindingTests { +public class AnnotationBindingTests { private AnnotatedTestBean testBean; + @Before public void setUp() { ClassPathXmlApplicationContext ctx = - new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass()); - + new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass()); testBean = (AnnotatedTestBean) ctx.getBean("testBean"); } + @Test public void testAnnotationBindingInAroundAdvice() { assertEquals("this value", testBean.doThis()); diff --git a/spring-context/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJAutoProxyCreatorTests.java b/spring-context/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJAutoProxyCreatorTests.java index d1c2e3f0..c753fd9f 100644 --- a/spring-context/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJAutoProxyCreatorTests.java +++ b/spring-context/src/test/java/org/springframework/aop/aspectj/autoproxy/AspectJAutoProxyCreatorTests.java @@ -513,11 +513,13 @@ class RetryAspect { try { o = jp.proceed(); this.commitCalls++; - } catch (RetryableException e) { + } + catch (RetryableException re) { this.rollbackCalls++; - throw e; + throw re; } - } catch (RetryableException re) { + } + catch (RetryableException re) { retry = true; } } diff --git a/spring-context/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/SPR3064Tests.java b/spring-context/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/SPR3064Tests.java index e2cf0114..b4229d15 100644 --- a/spring-context/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/SPR3064Tests.java +++ b/spring-context/src/test/java/org/springframework/aop/aspectj/autoproxy/spr3064/SPR3064Tests.java @@ -1,5 +1,5 @@ /** - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.aop.aspectj.autoproxy.spr3064; import java.lang.annotation.Retention; @@ -35,6 +36,7 @@ public final class SPR3064Tests { private Service service; + @Test public void testServiceIsAdvised() { ClassPathXmlApplicationContext ctx = @@ -46,7 +48,7 @@ public final class SPR3064Tests { this.service.serveMe(); fail("service operation has not been advised by transaction interceptor"); } - catch(RuntimeException ex) { + catch (RuntimeException ex) { assertEquals("advice invoked",ex.getMessage()); } } @@ -56,7 +58,6 @@ public final class SPR3064Tests { @Retention(RetentionPolicy.RUNTIME) @interface Transaction { - } @@ -68,14 +69,12 @@ class TransactionInterceptor { throw new RuntimeException("advice invoked"); //return pjp.proceed(); } - } interface Service { void serveMe(); - } @@ -85,5 +84,4 @@ class ServiceImpl implements Service { @Transaction public void serveMe() { } - } diff --git a/spring-context/src/test/java/org/springframework/aop/framework/AbstractAopProxyTests.java b/spring-context/src/test/java/org/springframework/aop/framework/AbstractAopProxyTests.java index 3114bf62..09b73f1c 100644 --- a/spring-context/src/test/java/org/springframework/aop/framework/AbstractAopProxyTests.java +++ b/spring-context/src/test/java/org/springframework/aop/framework/AbstractAopProxyTests.java @@ -400,7 +400,8 @@ public abstract class AbstractAopProxyTests { public Object invoke(MethodInvocation invocation) throws Throwable { if (!context) { assertNoInvocationContext(); - } else { + } + else { assertNotNull("have context", ExposeInvocationInterceptor.currentInvocation()); } return s; diff --git a/spring-context/src/test/java/org/springframework/aop/framework/ClassWithComplexConstructor.java b/spring-context/src/test/java/org/springframework/aop/framework/ClassWithComplexConstructor.java index 92118c0c..19bb244b 100644 --- a/spring-context/src/test/java/org/springframework/aop/framework/ClassWithComplexConstructor.java +++ b/spring-context/src/test/java/org/springframework/aop/framework/ClassWithComplexConstructor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.aop.framework; +import org.springframework.aop.support.AopUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.Assert; @@ -28,6 +29,8 @@ public class ClassWithComplexConstructor { private final Dependency dependency; + @Autowired ClassWithComplexConstructor selfReference; + @Autowired public ClassWithComplexConstructor(Dependency dependency) { Assert.notNull(dependency); @@ -39,6 +42,7 @@ public class ClassWithComplexConstructor { } public void method() { + Assert.isTrue(this.selfReference != this && AopUtils.isCglibProxy(this.selfReference)); this.dependency.method(); } diff --git a/spring-context/src/test/java/org/springframework/aop/framework/JdkDynamicProxyTests.java b/spring-context/src/test/java/org/springframework/aop/framework/JdkDynamicProxyTests.java index dd8d1f3a..384be563 100644 --- a/spring-context/src/test/java/org/springframework/aop/framework/JdkDynamicProxyTests.java +++ b/spring-context/src/test/java/org/springframework/aop/framework/JdkDynamicProxyTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,10 +32,10 @@ import org.springframework.tests.sample.beans.TestBean; import static org.junit.Assert.*; /** - * @since 13.03.2003 * @author Rod Johnson * @author Juergen Hoeller * @author Chris Beams + * @since 13.03.2003 */ @SuppressWarnings("serial") public class JdkDynamicProxyTests extends AbstractAopProxyTests implements Serializable { diff --git a/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/AdvisorAutoProxyCreatorTests.java b/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/AdvisorAutoProxyCreatorTests.java index 5c7dfce7..0170cfd7 100644 --- a/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/AdvisorAutoProxyCreatorTests.java +++ b/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/AdvisorAutoProxyCreatorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import java.io.IOException; import org.junit.Test; import test.mixin.Lockable; +import org.springframework.aop.Advisor; import org.springframework.aop.framework.Advised; import org.springframework.aop.framework.autoproxy.target.AbstractBeanFactoryBasedTargetSourceCreator; import org.springframework.aop.support.AopUtils; @@ -48,7 +49,7 @@ import static org.junit.Assert.*; * @author Chris Beams */ @SuppressWarnings("resource") -public final class AdvisorAutoProxyCreatorTests { +public class AdvisorAutoProxyCreatorTests { private static final Class<?> CLASS = AdvisorAutoProxyCreatorTests.class; private static final String CLASSNAME = CLASS.getSimpleName(); @@ -59,6 +60,7 @@ public final class AdvisorAutoProxyCreatorTests { private static final String QUICK_TARGETSOURCE_CONTEXT = CLASSNAME + "-quick-targetsource.xml"; private static final String OPTIMIZED_CONTEXT = CLASSNAME + "-optimized.xml"; + /** * Return a bean factory with attributes and EnterpriseServices configured. */ @@ -66,6 +68,7 @@ public final class AdvisorAutoProxyCreatorTests { return new ClassPathXmlApplicationContext(DEFAULT_CONTEXT, CLASS); } + /** * Check that we can provide a common interceptor that will * appear in the chain before "specific" interceptors, @@ -78,8 +81,8 @@ public final class AdvisorAutoProxyCreatorTests { assertTrue(AopUtils.isAopProxy(test1)); Lockable lockable1 = (Lockable) test1; - NopInterceptor nop = (NopInterceptor) bf.getBean("nopInterceptor"); - assertEquals(0, nop.getCount()); + NopInterceptor nop1 = (NopInterceptor) bf.getBean("nopInterceptor"); + NopInterceptor nop2 = (NopInterceptor) bf.getBean("pointcutAdvisor", Advisor.class).getAdvice(); ITestBean test2 = (ITestBean) bf.getBean("test2"); Lockable lockable2 = (Lockable) test2; @@ -87,14 +90,28 @@ public final class AdvisorAutoProxyCreatorTests { // Locking should be independent; nop is shared assertFalse(lockable1.locked()); assertFalse(lockable2.locked()); - // equals 2 calls on shared nop, because it's first - // and sees calls against the Lockable interface introduced - // by the specific advisor - assertEquals(2, nop.getCount()); + // equals 2 calls on shared nop, because it's first and sees calls + // against the Lockable interface introduced by the specific advisor + assertEquals(2, nop1.getCount()); + assertEquals(0, nop2.getCount()); lockable1.lock(); assertTrue(lockable1.locked()); assertFalse(lockable2.locked()); - assertEquals(5, nop.getCount()); + assertEquals(5, nop1.getCount()); + assertEquals(0, nop2.getCount()); + + PackageVisibleMethod packageVisibleMethod = (PackageVisibleMethod) bf.getBean("packageVisibleMethod"); + assertEquals(5, nop1.getCount()); + assertEquals(0, nop2.getCount()); + packageVisibleMethod.doSomething(); + assertEquals(6, nop1.getCount()); + assertEquals(1, nop2.getCount()); + assertTrue(packageVisibleMethod instanceof Lockable); + Lockable lockable3 = (Lockable) packageVisibleMethod; + lockable3.lock(); + assertTrue(lockable3.locked()); + lockable3.unlock(); + assertFalse(lockable3.locked()); } /** @@ -202,6 +219,7 @@ public final class AdvisorAutoProxyCreatorTests { } + class SelectivePrototypeTargetSourceCreator extends AbstractBeanFactoryBasedTargetSourceCreator { @Override diff --git a/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/AutoProxyCreatorTests.java b/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/AutoProxyCreatorTests.java index acaa8b72..5ed2091c 100644 --- a/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/AutoProxyCreatorTests.java +++ b/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/AutoProxyCreatorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,7 +56,7 @@ import static org.junit.Assert.*; * @since 09.12.2003 */ @SuppressWarnings("resource") -public final class AutoProxyCreatorTests { +public class AutoProxyCreatorTests { @Test public void testBeanNameAutoProxyCreator() { @@ -253,6 +253,23 @@ public final class AutoProxyCreatorTests { } @Test + public void testAutoProxyCreatorWithPackageVisibleMethod() { + StaticApplicationContext sac = new StaticApplicationContext(); + sac.registerSingleton("testAutoProxyCreator", TestAutoProxyCreator.class); + sac.registerSingleton("packageVisibleMethodToBeProxied", PackageVisibleMethod.class); + sac.refresh(); + + TestAutoProxyCreator tapc = (TestAutoProxyCreator) sac.getBean("testAutoProxyCreator"); + tapc.testInterceptor.nrOfInvocations = 0; + + PackageVisibleMethod tb = (PackageVisibleMethod) sac.getBean("packageVisibleMethodToBeProxied"); + assertTrue(AopUtils.isCglibProxy(tb)); + assertEquals(0, tapc.testInterceptor.nrOfInvocations); + tb.doSomething(); + assertEquals(1, tapc.testInterceptor.nrOfInvocations); + } + + @Test public void testAutoProxyCreatorWithFactoryBean() { StaticApplicationContext sac = new StaticApplicationContext(); sac.registerSingleton("testAutoProxyCreator", TestAutoProxyCreator.class); diff --git a/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/PackageVisibleMethod.java b/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/PackageVisibleMethod.java new file mode 100644 index 00000000..cf5e5a39 --- /dev/null +++ b/spring-context/src/test/java/org/springframework/aop/framework/autoproxy/PackageVisibleMethod.java @@ -0,0 +1,24 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.framework.autoproxy; + +public class PackageVisibleMethod { + + void doSomething() { + } + +} diff --git a/spring-context/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireContextTests.java b/spring-context/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireContextTests.java index b86f1480..e6e7f023 100644 --- a/spring-context/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireContextTests.java +++ b/spring-context/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireContextTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,6 +42,7 @@ import static org.junit.Assert.*; * @author Mark Fisher * @author Juergen Hoeller * @author Chris Beams + * @author Sam Brannen */ public class QualifierAnnotationAutowireContextTests { @@ -51,7 +52,7 @@ public class QualifierAnnotationAutowireContextTests { @Test - public void testAutowiredFieldWithSingleNonQualifiedCandidate() { + public void autowiredFieldWithSingleNonQualifiedCandidate() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs = new ConstructorArgumentValues(); cavs.addGenericArgumentValue(JUERGEN); @@ -71,7 +72,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredMethodParameterWithSingleNonQualifiedCandidate() { + public void autowiredMethodParameterWithSingleNonQualifiedCandidate() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs = new ConstructorArgumentValues(); cavs.addGenericArgumentValue(JUERGEN); @@ -91,7 +92,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredConstructorArgumentWithSingleNonQualifiedCandidate() { + public void autowiredConstructorArgumentWithSingleNonQualifiedCandidate() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs = new ConstructorArgumentValues(); cavs.addGenericArgumentValue(JUERGEN); @@ -111,7 +112,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredFieldWithSingleQualifiedCandidate() { + public void autowiredFieldWithSingleQualifiedCandidate() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs = new ConstructorArgumentValues(); cavs.addGenericArgumentValue(JUERGEN); @@ -126,7 +127,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredMethodParameterWithSingleQualifiedCandidate() { + public void autowiredMethodParameterWithSingleQualifiedCandidate() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs = new ConstructorArgumentValues(); cavs.addGenericArgumentValue(JUERGEN); @@ -143,7 +144,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredMethodParameterWithStaticallyQualifiedCandidate() { + public void autowiredMethodParameterWithStaticallyQualifiedCandidate() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs = new ConstructorArgumentValues(); cavs.addGenericArgumentValue(JUERGEN); @@ -160,7 +161,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredMethodParameterWithStaticallyQualifiedCandidateAmongOthers() { + public void autowiredMethodParameterWithStaticallyQualifiedCandidateAmongOthers() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs = new ConstructorArgumentValues(); cavs.addGenericArgumentValue(JUERGEN); @@ -180,7 +181,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredConstructorArgumentWithSingleQualifiedCandidate() { + public void autowiredConstructorArgumentWithSingleQualifiedCandidate() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs = new ConstructorArgumentValues(); cavs.addGenericArgumentValue(JUERGEN); @@ -197,7 +198,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredFieldWithMultipleNonQualifiedCandidates() { + public void autowiredFieldWithMultipleNonQualifiedCandidates() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); @@ -221,7 +222,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredMethodParameterWithMultipleNonQualifiedCandidates() { + public void autowiredMethodParameterWithMultipleNonQualifiedCandidates() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); @@ -245,7 +246,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredConstructorArgumentWithMultipleNonQualifiedCandidates() { + public void autowiredConstructorArgumentWithMultipleNonQualifiedCandidates() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); @@ -269,7 +270,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredFieldResolvesQualifiedCandidate() { + public void autowiredFieldResolvesQualifiedCandidate() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); @@ -289,7 +290,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredFieldResolvesMetaQualifiedCandidate() { + public void autowiredFieldResolvesMetaQualifiedCandidate() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); @@ -309,7 +310,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredMethodParameterResolvesQualifiedCandidate() { + public void autowiredMethodParameterResolvesQualifiedCandidate() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); @@ -330,7 +331,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredConstructorArgumentResolvesQualifiedCandidate() { + public void autowiredConstructorArgumentResolvesQualifiedCandidate() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); @@ -351,7 +352,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredFieldResolvesQualifiedCandidateWithDefaultValueAndNoValueOnBeanDefinition() { + public void autowiredFieldResolvesQualifiedCandidateWithDefaultValueAndNoValueOnBeanDefinition() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); @@ -373,7 +374,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredFieldDoesNotResolveCandidateWithDefaultValueAndConflictingValueOnBeanDefinition() { + public void autowiredFieldDoesNotResolveCandidateWithDefaultValueAndConflictingValueOnBeanDefinition() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); @@ -399,7 +400,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredFieldResolvesWithDefaultValueAndExplicitDefaultValueOnBeanDefinition() { + public void autowiredFieldResolvesWithDefaultValueAndExplicitDefaultValueOnBeanDefinition() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); @@ -421,7 +422,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredFieldResolvesWithMultipleQualifierValues() { + public void autowiredFieldResolvesWithMultipleQualifierValues() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); @@ -447,7 +448,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredFieldDoesNotResolveWithMultipleQualifierValuesAndConflictingDefaultValue() { + public void autowiredFieldDoesNotResolveWithMultipleQualifierValuesAndConflictingDefaultValue() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); @@ -478,7 +479,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredFieldResolvesWithMultipleQualifierValuesAndExplicitDefaultValue() { + public void autowiredFieldResolvesWithMultipleQualifierValuesAndExplicitDefaultValue() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); @@ -505,7 +506,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredFieldDoesNotResolveWithMultipleQualifierValuesAndMultipleMatchingCandidates() { + public void autowiredFieldDoesNotResolveWithMultipleQualifierValuesAndMultipleMatchingCandidates() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); @@ -536,7 +537,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredFieldResolvesWithBaseQualifierAndDefaultValue() { + public void autowiredFieldResolvesWithBaseQualifierAndDefaultValue() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue(JUERGEN); @@ -557,7 +558,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredFieldResolvesWithBaseQualifierAndNonDefaultValue() { + public void autowiredFieldResolvesWithBaseQualifierAndNonDefaultValue() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue("the real juergen"); @@ -579,7 +580,7 @@ public class QualifierAnnotationAutowireContextTests { } @Test - public void testAutowiredFieldDoesNotResolveWithBaseQualifierAndNonDefaultValueAndMultipleMatchingCandidates() { + public void autowiredFieldDoesNotResolveWithBaseQualifierAndNonDefaultValueAndMultipleMatchingCandidates() { GenericApplicationContext context = new GenericApplicationContext(); ConstructorArgumentValues cavs1 = new ConstructorArgumentValues(); cavs1.addGenericArgumentValue("the real juergen"); @@ -631,7 +632,7 @@ public class QualifierAnnotationAutowireContextTests { @Autowired @TestQualifier @Retention(RetentionPolicy.RUNTIME) - public static @interface MyAutowired { + @interface MyAutowired { } @@ -666,7 +667,7 @@ public class QualifierAnnotationAutowireContextTests { } - public static class QualifiedFieldWithDefaultValueTestBean { + private static class QualifiedFieldWithDefaultValueTestBean { @Autowired @TestQualifierWithDefaultValue @@ -678,7 +679,7 @@ public class QualifierAnnotationAutowireContextTests { } - public static class QualifiedFieldWithMultipleAttributesTestBean { + private static class QualifiedFieldWithMultipleAttributesTestBean { @Autowired @TestQualifierWithMultipleAttributes(number=123) @@ -702,7 +703,7 @@ public class QualifierAnnotationAutowireContextTests { } - public static class QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean { + private static class QualifiedConstructorArgumentWithBaseQualifierNonDefaultValueTestBean { private Person person; @@ -760,13 +761,13 @@ public class QualifierAnnotationAutowireContextTests { @Retention(RetentionPolicy.RUNTIME) @Qualifier - public static @interface TestQualifier { + @interface TestQualifier { } @Retention(RetentionPolicy.RUNTIME) @Qualifier - public static @interface TestQualifierWithDefaultValue { + @interface TestQualifierWithDefaultValue { String value() default "default"; } @@ -775,7 +776,7 @@ public class QualifierAnnotationAutowireContextTests { @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Qualifier - public static @interface TestQualifierWithMultipleAttributes { + @interface TestQualifierWithMultipleAttributes { String value() default "default"; diff --git a/spring-context/src/test/java/org/springframework/beans/factory/xml/XmlBeanFactoryTests.java b/spring-context/src/test/java/org/springframework/beans/factory/xml/XmlBeanFactoryTests.java index 94ec9db8..35f76782 100644 --- a/spring-context/src/test/java/org/springframework/beans/factory/xml/XmlBeanFactoryTests.java +++ b/spring-context/src/test/java/org/springframework/beans/factory/xml/XmlBeanFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import java.lang.reflect.Method; import java.net.URISyntaxException; import java.net.URL; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.logging.LogFactory; import org.junit.Test; @@ -78,7 +79,7 @@ import static org.junit.Assert.*; * @author Chris Beams * @author Sam Brannen */ -public final class XmlBeanFactoryTests { +public class XmlBeanFactoryTests { private static final Class<?> CLASS = XmlBeanFactoryTests.class; private static final String CLASSNAME = CLASS.getSimpleName(); @@ -1611,6 +1612,16 @@ public final class XmlBeanFactoryTests { } @Test + public void testConstructorWithUnresolvableParameterName() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONSTRUCTOR_ARG_CONTEXT); + AtomicInteger bean = (AtomicInteger) xbf.getBean("constructorUnresolvableName"); + assertEquals(1, bean.get()); + bean = (AtomicInteger) xbf.getBean("constructorUnresolvableNameWithIndex"); + assertEquals(1, bean.get()); + } + + @Test public void testWithDuplicateName() throws Exception { DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); try { diff --git a/spring-context/src/test/java/org/springframework/cache/AbstractCacheTests.java b/spring-context/src/test/java/org/springframework/cache/AbstractCacheTests.java new file mode 100644 index 00000000..c71f133d --- /dev/null +++ b/spring-context/src/test/java/org/springframework/cache/AbstractCacheTests.java @@ -0,0 +1,218 @@ +/* + * Copyright 2002-2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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 java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.UUID; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import static org.hamcrest.core.Is.*; +import static org.junit.Assert.*; + +/** + * @author Stephane Nicoll + */ +public abstract class AbstractCacheTests<T extends Cache> { + + @Rule + public final ExpectedException thrown = ExpectedException.none(); + + protected final static String CACHE_NAME = "testCache"; + + protected abstract T getCache(); + + protected abstract Object getNativeCache(); + + + @Test + public void testCacheName() throws Exception { + assertEquals(CACHE_NAME, getCache().getName()); + } + + @Test + public void testNativeCache() throws Exception { + assertSame(getNativeCache(), getCache().getNativeCache()); + } + + @Test + public void testCachePut() throws Exception { + T cache = getCache(); + + String key = createRandomKey(); + Object value = "george"; + + assertNull(cache.get(key)); + assertNull(cache.get(key, String.class)); + assertNull(cache.get(key, Object.class)); + + cache.put(key, value); + assertEquals(value, cache.get(key).get()); + assertEquals(value, cache.get(key, String.class)); + assertEquals(value, cache.get(key, Object.class)); + assertEquals(value, cache.get(key, (Class<?>) null)); + + cache.put(key, null); + assertNotNull(cache.get(key)); + assertNull(cache.get(key).get()); + assertNull(cache.get(key, String.class)); + assertNull(cache.get(key, Object.class)); + } + + @Test + public void testCachePutIfAbsent() throws Exception { + T cache = getCache(); + + String key = createRandomKey(); + Object value = "initialValue"; + + assertNull(cache.get(key)); + assertNull(cache.putIfAbsent(key, value)); + assertEquals(value, cache.get(key).get()); + assertEquals("initialValue", cache.putIfAbsent(key, "anotherValue").get()); + assertEquals(value, cache.get(key).get()); // not changed + } + + @Test + public void testCacheRemove() throws Exception { + T cache = getCache(); + + String key = createRandomKey(); + Object value = "george"; + + assertNull(cache.get(key)); + cache.put(key, value); + } + + @Test + public void testCacheClear() throws Exception { + T cache = getCache(); + + 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")); + } + + @Test + public void testCacheGetCallable() { + doTestCacheGetCallable("test"); + } + + @Test + public void testCacheGetCallableWithNull() { + doTestCacheGetCallable(null); + } + + private void doTestCacheGetCallable(Object returnValue) { + T cache = getCache(); + + String key = createRandomKey(); + + assertNull(cache.get(key)); + Object value = cache.get(key, () -> returnValue ); + assertEquals(returnValue, value); + assertEquals(value, cache.get(key).get()); + } + + @Test + public void testCacheGetCallableNotInvokedWithHit() { + doTestCacheGetCallableNotInvokedWithHit("existing"); + } + + @Test + public void testCacheGetCallableNotInvokedWithHitNull() { + doTestCacheGetCallableNotInvokedWithHit(null); + } + + private void doTestCacheGetCallableNotInvokedWithHit(Object initialValue) { + T cache = getCache(); + + String key = createRandomKey(); + cache.put(key, initialValue); + + Object value = cache.get(key, () -> { + throw new IllegalStateException("Should not have been invoked"); + }); + assertEquals(initialValue, value); + } + + @Test + public void testCacheGetCallableFail() { + T cache = getCache(); + + String key = createRandomKey(); + assertNull(cache.get(key)); + + try { + cache.get(key, () -> { + throw new UnsupportedOperationException("Expected exception"); + }); + } + catch (Cache.ValueRetrievalException ex) { + assertNotNull(ex.getCause()); + assertEquals(UnsupportedOperationException.class, ex.getCause().getClass()); + } + } + + /** + * Test that a call to get with a Callable concurrently properly synchronize the + * invocations. + */ + @Test + public void testCacheGetSynchronized() throws InterruptedException { + T cache = getCache(); + final AtomicInteger counter = new AtomicInteger(); + final List<Object> results = new CopyOnWriteArrayList<>(); + final CountDownLatch latch = new CountDownLatch(10); + + String key = createRandomKey(); + Runnable run = () -> { + try { + Integer value = cache.get(key, () -> { + Thread.sleep(50); // make sure the thread will overlap + return counter.incrementAndGet(); + }); + results.add(value); + } + finally { + latch.countDown(); + } + }; + + for (int i = 0; i < 10; i++) { + new Thread(run).start(); + } + latch.await(); + + assertEquals(10, results.size()); + results.forEach(r -> assertThat(r, is(1))); // Only one method got invoked + } + + protected String createRandomKey() { + return UUID.randomUUID().toString(); + } + +} diff --git a/spring-context/src/test/java/org/springframework/cache/CacheReproTests.java b/spring-context/src/test/java/org/springframework/cache/CacheReproTests.java index 8781e82a..729bb61d 100644 --- a/spring-context/src/test/java/org/springframework/cache/CacheReproTests.java +++ b/spring-context/src/test/java/org/springframework/cache/CacheReproTests.java @@ -20,12 +20,14 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Optional; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.mockito.Mockito; +import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Caching; import org.springframework.cache.annotation.CachingConfigurerSupport; @@ -39,6 +41,7 @@ import org.springframework.cache.support.SimpleCacheManager; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.tests.sample.beans.TestBean; import static org.junit.Assert.*; import static org.mockito.Mockito.*; @@ -130,6 +133,23 @@ public class CacheReproTests { bean.getSimple(null); } + @Test + public void spr14230AdaptsToOptional() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr14230Config.class); + Spr14230Service bean = context.getBean(Spr14230Service.class); + Cache cache = context.getBean(CacheManager.class).getCache("itemCache"); + + TestBean tb = new TestBean("tb1"); + bean.insertItem(tb); + assertSame(tb, bean.findById("tb1").get()); + assertSame(tb, cache.get("tb1").get()); + + cache.clear(); + TestBean tb2 = bean.findById("tb1").get(); + assertNotSame(tb, tb2); + assertSame(tb2, cache.get("tb1").get()); + } + @Configuration @EnableCaching @@ -292,4 +312,34 @@ public class CacheReproTests { } } + + public static class Spr14230Service { + + @Cacheable("itemCache") + public Optional<TestBean> findById(String id) { + return Optional.of(new TestBean(id)); + } + + @CachePut(cacheNames = "itemCache", key = "#item.name") + public TestBean insertItem(TestBean item) { + return item; + } + } + + + @Configuration + @EnableCaching + public static class Spr14230Config { + + @Bean + public CacheManager cacheManager() { + return new ConcurrentMapCacheManager(); + } + + @Bean + public Spr14230Service service() { + return new Spr14230Service(); + } + } + } diff --git a/spring-context/src/test/java/org/springframework/cache/NoOpCacheManagerTests.java b/spring-context/src/test/java/org/springframework/cache/NoOpCacheManagerTests.java index dc65b678..9489b847 100644 --- a/spring-context/src/test/java/org/springframework/cache/NoOpCacheManagerTests.java +++ b/spring-context/src/test/java/org/springframework/cache/NoOpCacheManagerTests.java @@ -18,33 +18,33 @@ package org.springframework.cache; import java.util.UUID; -import org.junit.Before; import org.junit.Test; import org.springframework.cache.support.NoOpCacheManager; import static org.junit.Assert.*; +/** + * Tests for {@link NoOpCacheManager}. + * + * @author Costin Leau + * @author Stephane Nicoll + */ public class NoOpCacheManagerTests { - private CacheManager manager; - - @Before - public void setup() { - manager = new NoOpCacheManager(); - } + private final CacheManager manager = new NoOpCacheManager(); @Test public void testGetCache() throws Exception { - Cache cache = manager.getCache("bucket"); + Cache cache = this.manager.getCache("bucket"); assertNotNull(cache); - assertSame(cache, manager.getCache("bucket")); + assertSame(cache, this.manager.getCache("bucket")); } @Test public void testNoOpCache() throws Exception { - String name = UUID.randomUUID().toString(); - Cache cache = manager.getCache(name); + String name = createRandomKey(); + Cache cache = this.manager.getCache(name); assertEquals(name, cache.getName()); Object key = new Object(); cache.put(key, new Object()); @@ -56,8 +56,37 @@ public class NoOpCacheManagerTests { @Test public void testCacheName() throws Exception { String name = "bucket"; - assertFalse(manager.getCacheNames().contains(name)); - manager.getCache(name); - assertTrue(manager.getCacheNames().contains(name)); + assertFalse(this.manager.getCacheNames().contains(name)); + this.manager.getCache(name); + assertTrue(this.manager.getCacheNames().contains(name)); + } + + @Test + public void testCacheCallable() throws Exception { + String name = createRandomKey(); + Cache cache = this.manager.getCache(name); + Object returnValue = new Object(); + Object value = cache.get(new Object(), () -> returnValue); + assertEquals(returnValue, value); } + + @Test + public void testCacheGetCallableFail() { + Cache cache = this.manager.getCache(createRandomKey()); + String key = createRandomKey(); + try { + cache.get(key, () -> { + throw new UnsupportedOperationException("Expected exception"); + }); + } + catch (Cache.ValueRetrievalException ex) { + assertNotNull(ex.getCause()); + assertEquals(UnsupportedOperationException.class, ex.getCause().getClass()); + } + } + + private String createRandomKey() { + return UUID.randomUUID().toString(); + } + } diff --git a/spring-context/src/test/java/org/springframework/cache/annotation/AnnotationCacheOperationSourceTests.java b/spring-context/src/test/java/org/springframework/cache/annotation/AnnotationCacheOperationSourceTests.java index bfafce1d..409d9692 100644 --- a/spring-context/src/test/java/org/springframework/cache/annotation/AnnotationCacheOperationSourceTests.java +++ b/spring-context/src/test/java/org/springframework/cache/annotation/AnnotationCacheOperationSourceTests.java @@ -23,6 +23,7 @@ import java.lang.annotation.Target; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import org.junit.Rule; @@ -34,6 +35,7 @@ import org.springframework.cache.interceptor.CacheOperation; import org.springframework.cache.interceptor.CacheableOperation; import org.springframework.core.annotation.AliasFor; +import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; /** @@ -96,6 +98,48 @@ public class AnnotationCacheOperationSourceTests { } @Test + public void singleComposedAnnotation() throws Exception { + Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "singleComposed", 2); + Iterator<CacheOperation> it = ops.iterator(); + + CacheOperation cacheOperation = it.next(); + assertThat(cacheOperation, instanceOf(CacheableOperation.class)); + assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("directly declared"))); + assertThat(cacheOperation.getKey(), equalTo("")); + + cacheOperation = it.next(); + assertThat(cacheOperation, instanceOf(CacheableOperation.class)); + assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("composedCache"))); + assertThat(cacheOperation.getKey(), equalTo("composedKey")); + } + + @Test + public void multipleComposedAnnotations() throws Exception { + Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "multipleComposed", 4); + Iterator<CacheOperation> it = ops.iterator(); + + CacheOperation cacheOperation = it.next(); + assertThat(cacheOperation, instanceOf(CacheableOperation.class)); + assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("directly declared"))); + assertThat(cacheOperation.getKey(), equalTo("")); + + cacheOperation = it.next(); + assertThat(cacheOperation, instanceOf(CacheableOperation.class)); + assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("composedCache"))); + assertThat(cacheOperation.getKey(), equalTo("composedKey")); + + cacheOperation = it.next(); + assertThat(cacheOperation, instanceOf(CacheableOperation.class)); + assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("foo"))); + assertThat(cacheOperation.getKey(), equalTo("")); + + cacheOperation = it.next(); + assertThat(cacheOperation, instanceOf(CacheEvictOperation.class)); + assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("composedCacheEvict"))); + assertThat(cacheOperation.getKey(), equalTo("composedEvictionKey")); + } + + @Test public void customKeyGenerator() { Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "customKeyGenerator", 1); CacheOperation cacheOperation = ops.iterator().next(); diff --git a/spring-context/src/test/java/org/springframework/cache/concurrent/ConcurrentCacheTests.java b/spring-context/src/test/java/org/springframework/cache/concurrent/ConcurrentCacheTests.java deleted file mode 100644 index cba7db7d..00000000 --- a/spring-context/src/test/java/org/springframework/cache/concurrent/ConcurrentCacheTests.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2002-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS 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.junit.Before; -import org.junit.Test; - -import org.springframework.cache.Cache; - -import static org.junit.Assert.*; - -/** - * @author Costin Leau - * @author Juergen Hoeller - * @author Stephane Nicoll - */ -public class ConcurrentCacheTests { - - protected final static String CACHE_NAME = "testCache"; - - protected ConcurrentMap<Object, Object> nativeCache; - - protected Cache cache; - - - @Before - public void setUp() throws Exception { - nativeCache = new ConcurrentHashMap<Object, Object>(); - cache = new ConcurrentMapCache(CACHE_NAME, nativeCache, true); - cache.clear(); - } - - - @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)); - assertNull(cache.get(key, String.class)); - assertNull(cache.get(key, Object.class)); - - cache.put(key, value); - assertEquals(value, cache.get(key).get()); - assertEquals(value, cache.get(key, String.class)); - assertEquals(value, cache.get(key, Object.class)); - assertEquals(value, cache.get(key, null)); - - cache.put(key, null); - assertNotNull(cache.get(key)); - assertNull(cache.get(key).get()); - assertNull(cache.get(key, String.class)); - assertNull(cache.get(key, Object.class)); - } - - @Test - public void testCachePutIfAbsent() throws Exception { - Object key = new Object(); - Object value = "initialValue"; - - assertNull(cache.get(key)); - assertNull(cache.putIfAbsent(key, value)); - assertEquals(value, cache.get(key).get()); - assertEquals("initialValue", cache.putIfAbsent(key, "anotherValue").get()); - assertEquals(value, cache.get(key).get()); // not changed - } - - @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")); - } - -} diff --git a/spring-context/src/test/java/org/springframework/cache/concurrent/ConcurrentMapCacheManagerTests.java b/spring-context/src/test/java/org/springframework/cache/concurrent/ConcurrentMapCacheManagerTests.java index 14fdb547..1598b0fa 100644 --- a/spring-context/src/test/java/org/springframework/cache/concurrent/ConcurrentMapCacheManagerTests.java +++ b/spring-context/src/test/java/org/springframework/cache/concurrent/ConcurrentMapCacheManagerTests.java @@ -25,6 +25,7 @@ import static org.junit.Assert.*; /** * @author Juergen Hoeller + * @author Stephane Nicoll */ public class ConcurrentMapCacheManagerTests { @@ -120,4 +121,21 @@ public class ConcurrentMapCacheManagerTests { assertNull(cache1y.get("key3")); } + @Test + public void testChangeStoreByValue() { + ConcurrentMapCacheManager cm = new ConcurrentMapCacheManager("c1", "c2"); + assertFalse(cm.isStoreByValue()); + Cache cache1 = cm.getCache("c1"); + assertTrue(cache1 instanceof ConcurrentMapCache); + assertFalse(((ConcurrentMapCache)cache1).isStoreByValue()); + cache1.put("key", "value"); + + cm.setStoreByValue(true); + assertTrue(cm.isStoreByValue()); + Cache cache1x = cm.getCache("c1"); + assertTrue(cache1x instanceof ConcurrentMapCache); + assertTrue(cache1x != cache1); + assertNull(cache1x.get("key")); + } + } diff --git a/spring-context/src/test/java/org/springframework/cache/concurrent/ConcurrentMapCacheTests.java b/spring-context/src/test/java/org/springframework/cache/concurrent/ConcurrentMapCacheTests.java new file mode 100644 index 00000000..6836ba70 --- /dev/null +++ b/spring-context/src/test/java/org/springframework/cache/concurrent/ConcurrentMapCacheTests.java @@ -0,0 +1,111 @@ +/* + * Copyright 2002-2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.junit.Before; +import org.junit.Test; + +import org.springframework.cache.AbstractCacheTests; +import org.springframework.core.serializer.support.SerializationDelegate; + +import static org.junit.Assert.*; + +/** + * @author Costin Leau + * @author Juergen Hoeller + * @author Stephane Nicoll + */ +public class ConcurrentMapCacheTests extends AbstractCacheTests<ConcurrentMapCache> { + + protected ConcurrentMap<Object, Object> nativeCache; + + protected ConcurrentMapCache cache; + + + @Before + public void setUp() throws Exception { + nativeCache = new ConcurrentHashMap<Object, Object>(); + cache = new ConcurrentMapCache(CACHE_NAME, nativeCache, true); + cache.clear(); + } + + @Override + protected ConcurrentMapCache getCache() { + return this.cache; + } + + @Override + protected ConcurrentMap<Object, Object> getNativeCache() { + return this.nativeCache; + } + + @Test + public void testIsStoreByReferenceByDefault() { + assertFalse(this.cache.isStoreByValue()); + } + + @SuppressWarnings("unchecked") + @Test + public void testSerializer() { + ConcurrentMapCache serializeCache = createCacheWithStoreByValue(); + assertTrue(serializeCache.isStoreByValue()); + + Object key = createRandomKey(); + List<String> content = new ArrayList<>(); + content.addAll(Arrays.asList("one", "two", "three")); + serializeCache.put(key, content); + content.remove(0); + List<String> entry = (List<String>) serializeCache.get(key).get(); + assertEquals(3, entry.size()); + assertEquals("one", entry.get(0)); + } + + @Test + public void testNonSerializableContent() { + ConcurrentMapCache serializeCache = createCacheWithStoreByValue(); + + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("Failed to serialize"); + thrown.expectMessage(this.cache.getClass().getName()); + serializeCache.put(createRandomKey(), this.cache); + } + + @Test + public void testInvalidSerializedContent() { + ConcurrentMapCache serializeCache = createCacheWithStoreByValue(); + + String key = createRandomKey(); + this.nativeCache.put(key, "Some garbage"); + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("Failed to deserialize"); + thrown.expectMessage("Some garbage"); + serializeCache.get(key); + } + + + private ConcurrentMapCache createCacheWithStoreByValue() { + return new ConcurrentMapCache(CACHE_NAME, nativeCache, true, + new SerializationDelegate(ConcurrentMapCacheTests.class.getClassLoader())); + } + +} diff --git a/spring-context/src/test/java/org/springframework/cache/config/AbstractCacheAnnotationTests.java b/spring-context/src/test/java/org/springframework/cache/config/AbstractCacheAnnotationTests.java index 73b9d4d6..8a00e735 100644 --- a/spring-context/src/test/java/org/springframework/cache/config/AbstractCacheAnnotationTests.java +++ b/spring-context/src/test/java/org/springframework/cache/config/AbstractCacheAnnotationTests.java @@ -105,6 +105,32 @@ public abstract class AbstractCacheAnnotationTests { assertNull("Cached value should be null", r3); } + public void testCacheableSync(CacheableService<?> service) throws Exception { + Object o1 = new Object(); + + Object r1 = service.cacheSync(o1); + Object r2 = service.cacheSync(o1); + Object r3 = service.cacheSync(o1); + + assertSame(r1, r2); + assertSame(r1, r3); + } + + public void testCacheableSyncNull(CacheableService<?> service) throws Exception { + Object o1 = new Object(); + assertNull(cm.getCache("testCache").get(o1)); + + Object r1 = service.cacheSyncNull(o1); + Object r2 = service.cacheSyncNull(o1); + Object r3 = service.cacheSyncNull(o1); + + assertSame(r1, r2); + assertSame(r1, r3); + + assertEquals(r3, cm.getCache("testCache").get(o1).get()); + assertNull("Cached value should be null", r3); + } + public void testEvict(CacheableService<?> service) throws Exception { Object o1 = new Object(); @@ -225,6 +251,18 @@ public abstract class AbstractCacheAnnotationTests { assertSame(r3, r4); } + public void testConditionalExpressionSync(CacheableService<?> service) throws Exception { + Object r1 = service.conditionalSync(4); + Object r2 = service.conditionalSync(4); + + assertNotSame(r1, r2); + + Object r3 = service.conditionalSync(3); + Object r4 = service.conditionalSync(3); + + assertSame(r3, r4); + } + public void testUnlessExpression(CacheableService<?> service) throws Exception { Cache cache = cm.getCache("testCache"); cache.clear(); @@ -311,6 +349,30 @@ public abstract class AbstractCacheAnnotationTests { } } + public void testCheckedThrowableSync(CacheableService<?> service) throws Exception { + String arg = UUID.randomUUID().toString(); + try { + service.throwCheckedSync(arg); + fail("Excepted exception"); + } + catch (Exception ex) { + ex.printStackTrace(); + assertEquals("Wrong exception type", IOException.class, ex.getClass()); + assertEquals(arg, ex.getMessage()); + } + } + + public void testUncheckedThrowableSync(CacheableService<?> service) throws Exception { + try { + service.throwUncheckedSync(Long.valueOf(1)); + fail("Excepted exception"); + } + catch (RuntimeException ex) { + assertEquals("Wrong exception type", UnsupportedOperationException.class, ex.getClass()); + assertEquals("1", ex.getMessage()); + } + } + public void testNullArg(CacheableService<?> service) { Object r1 = service.cache(null); assertSame(r1, service.cache(null)); @@ -484,6 +546,16 @@ public abstract class AbstractCacheAnnotationTests { } @Test + public void testCacheableSync() throws Exception { + testCacheableSync(cs); + } + + @Test + public void testCacheableSyncNull() throws Exception { + testCacheableSyncNull(cs); + } + + @Test public void testInvalidate() throws Exception { testEvict(cs); } @@ -519,6 +591,11 @@ public abstract class AbstractCacheAnnotationTests { } @Test + public void testConditionalExpressionSync() throws Exception { + testConditionalExpressionSync(cs); + } + + @Test public void testUnlessExpression() throws Exception { testUnlessExpression(cs); } @@ -678,6 +755,16 @@ public abstract class AbstractCacheAnnotationTests { } @Test + public void testCheckedExceptionSync() throws Exception { + testCheckedThrowableSync(cs); + } + + @Test + public void testClassCheckedExceptionSync() throws Exception { + testCheckedThrowableSync(ccs); + } + + @Test public void testUncheckedException() throws Exception { testUncheckedThrowable(cs); } @@ -688,6 +775,16 @@ public abstract class AbstractCacheAnnotationTests { } @Test + public void testUncheckedExceptionSync() throws Exception { + testUncheckedThrowableSync(cs); + } + + @Test + public void testClassUncheckedExceptionSync() throws Exception { + testUncheckedThrowableSync(ccs); + } + + @Test public void testUpdate() { testCacheUpdate(cs); } diff --git a/spring-context/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java b/spring-context/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java index 450a01fb..88886b6a 100644 --- a/spring-context/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java +++ b/spring-context/src/test/java/org/springframework/cache/config/AnnotatedClassCacheableService.java @@ -47,11 +47,28 @@ public class AnnotatedClassCacheableService implements CacheableService<Object> } @Override + @Cacheable(cacheNames = "testCache", sync = true) + public Object cacheSync(Object arg1) { + return counter.getAndIncrement(); + } + + @Override + @Cacheable(cacheNames = "testCache", sync = true) + public Object cacheSyncNull(Object arg1) { + return null; + } + + @Override public Object conditional(int field) { return null; } @Override + public Object conditionalSync(int field) { + return null; + } + + @Override @Cacheable(cacheNames = "testCache", unless = "#result > 10") public Object unless(int arg) { return arg; @@ -171,6 +188,18 @@ public class AnnotatedClassCacheableService implements CacheableService<Object> throw new UnsupportedOperationException(arg1.toString()); } + @Override + @Cacheable(cacheNames = "testCache", sync = true) + public Object throwCheckedSync(Object arg1) throws Exception { + throw new IOException(arg1.toString()); + } + + @Override + @Cacheable(cacheNames = "testCache", sync = true) + public Object throwUncheckedSync(Object arg1) { + throw new UnsupportedOperationException(arg1.toString()); + } + // multi annotations @Override diff --git a/spring-context/src/test/java/org/springframework/cache/config/CacheAdviceParserTests.java b/spring-context/src/test/java/org/springframework/cache/config/CacheAdviceParserTests.java index 5e624bda..3d461ce3 100644 --- a/spring-context/src/test/java/org/springframework/cache/config/CacheAdviceParserTests.java +++ b/spring-context/src/test/java/org/springframework/cache/config/CacheAdviceParserTests.java @@ -35,7 +35,10 @@ public class CacheAdviceParserTests { try { new GenericXmlApplicationContext("/org/springframework/cache/config/cache-advice-invalid.xml"); fail("Should have failed to load context, one advise define both a key and a key generator"); - } catch (BeanDefinitionStoreException e) { // TODO better exception handling + } + catch (BeanDefinitionStoreException ex) { + // TODO better exception handling } } + } diff --git a/spring-context/src/test/java/org/springframework/cache/config/CacheableService.java b/spring-context/src/test/java/org/springframework/cache/config/CacheableService.java index a129f617..f7030351 100644 --- a/spring-context/src/test/java/org/springframework/cache/config/CacheableService.java +++ b/spring-context/src/test/java/org/springframework/cache/config/CacheableService.java @@ -29,6 +29,10 @@ public interface CacheableService<T> { T cacheNull(Object arg1); + T cacheSync(Object arg1); + + T cacheSyncNull(Object arg1); + void invalidate(Object arg1); void evictEarly(Object arg1); @@ -43,6 +47,8 @@ public interface CacheableService<T> { T conditional(int field); + T conditionalSync(int field); + T unless(int arg); T key(Object arg1, Object arg2); @@ -73,6 +79,10 @@ public interface CacheableService<T> { T throwUnchecked(Object arg1); + T throwCheckedSync(Object arg1) throws Exception; + + T throwUncheckedSync(Object arg1); + // multi annotations T multiCache(Object arg1); diff --git a/spring-context/src/test/java/org/springframework/cache/config/DefaultCacheableService.java b/spring-context/src/test/java/org/springframework/cache/config/DefaultCacheableService.java index f5564df5..93b7a239 100644 --- a/spring-context/src/test/java/org/springframework/cache/config/DefaultCacheableService.java +++ b/spring-context/src/test/java/org/springframework/cache/config/DefaultCacheableService.java @@ -49,6 +49,18 @@ public class DefaultCacheableService implements CacheableService<Long> { } @Override + @Cacheable(cacheNames = "testCache", sync = true) + public Long cacheSync(Object arg1) { + return counter.getAndIncrement(); + } + + @Override + @Cacheable(cacheNames = "testCache", sync = true) + public Long cacheSyncNull(Object arg1) { + return null; + } + + @Override @CacheEvict("testCache") public void invalidate(Object arg1) { } @@ -82,12 +94,18 @@ public class DefaultCacheableService implements CacheableService<Long> { } @Override - @Cacheable(cacheNames = "testCache", condition = "#classField == 3") + @Cacheable(cacheNames = "testCache", condition = "#p0 == 3") public Long conditional(int classField) { return counter.getAndIncrement(); } @Override + @Cacheable(cacheNames = "testCache", sync = true, condition = "#p0 == 3") + public Long conditionalSync(int classField) { + return counter.getAndIncrement(); + } + + @Override @Cacheable(cacheNames = "testCache", unless = "#result > 10") public Long unless(int arg) { return (long) arg; @@ -177,6 +195,18 @@ public class DefaultCacheableService implements CacheableService<Long> { throw new UnsupportedOperationException(arg1.toString()); } + @Override + @Cacheable(cacheNames = "testCache", sync = true) + public Long throwCheckedSync(Object arg1) throws Exception { + throw new IOException(arg1.toString()); + } + + @Override + @Cacheable(cacheNames = "testCache", sync = true) + public Long throwUncheckedSync(Object arg1) { + throw new UnsupportedOperationException(arg1.toString()); + } + // multi annotations @Override diff --git a/spring-context/src/test/java/org/springframework/cache/config/EnableCachingIntegrationTests.java b/spring-context/src/test/java/org/springframework/cache/config/EnableCachingIntegrationTests.java index d51cc524..4ab2d706 100644 --- a/spring-context/src/test/java/org/springframework/cache/config/EnableCachingIntegrationTests.java +++ b/spring-context/src/test/java/org/springframework/cache/config/EnableCachingIntegrationTests.java @@ -1,7 +1,24 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.junit.After; import org.junit.Test; import org.springframework.cache.Cache; @@ -11,7 +28,6 @@ import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; -import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; @@ -21,29 +37,37 @@ import org.springframework.context.annotation.Import; import static org.springframework.cache.CacheTestUtils.*; /** - * Tests that represent real use cases with advanced configuration + * Tests that represent real use cases with advanced configuration. + * * @author Stephane Nicoll */ public class EnableCachingIntegrationTests { + private ConfigurableApplicationContext context; + + @After + public void closeContext() { + if (this.context != null) { + this.context.close(); + } + } + @Test public void fooServiceWithInterface() { - ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(FooConfig.class); - FooService service = context.getBean(FooService.class); - fooGetSimple(context, service); + this.context = new AnnotationConfigApplicationContext(FooConfig.class); + FooService service = this.context.getBean(FooService.class); + fooGetSimple(service); } @Test public void fooServiceWithInterfaceCglib() { - ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(FooConfigCglib.class); - FooService service = context.getBean(FooService.class); - fooGetSimple(context, service); + this.context = new AnnotationConfigApplicationContext(FooConfigCglib.class); + FooService service = this.context.getBean(FooService.class); + fooGetSimple(service); } - private void fooGetSimple(ApplicationContext context, FooService service) { - CacheManager cacheManager = context.getBean(CacheManager.class); - - Cache cache = cacheManager.getCache("testCache"); + private void fooGetSimple(FooService service) { + Cache cache = getCache(); Object key = new Object(); assertCacheMiss(key, cache); @@ -52,6 +76,21 @@ public class EnableCachingIntegrationTests { assertCacheHit(key, value, cache); } + @Test + public void beanCondition() { + this.context = new AnnotationConfigApplicationContext(BeanConditionConfig.class); + Cache cache = getCache(); + FooService service = context.getBean(FooService.class); + + Object key = new Object(); + service.getWithCondition(key); + assertCacheMiss(key, cache); + } + + private Cache getCache() { + return this.context.getBean(CacheManager.class).getCache("testCache"); + } + @Configuration static class SharedConfig extends CachingConfigurerSupport { @Override @@ -81,8 +120,10 @@ public class EnableCachingIntegrationTests { } } - private static interface FooService { - public Object getSimple(Object key); + private interface FooService { + Object getSimple(Object key); + + Object getWithCondition(Object key); } @CacheConfig(cacheNames = "testCache") @@ -94,6 +135,35 @@ public class EnableCachingIntegrationTests { public Object getSimple(Object key) { return counter.getAndIncrement(); } + + @Override + @Cacheable(condition = "@bar.enabled") + public Object getWithCondition(Object key) { + return counter.getAndIncrement(); + } + } + + @Configuration + @Import(FooConfig.class) + @EnableCaching + static class BeanConditionConfig { + + @Bean + public Bar bar() { + return new Bar(false); + } + + static class Bar { + private final boolean enabled; + + public Bar(boolean enabled) { + this.enabled = enabled; + } + + public boolean isEnabled() { + return enabled; + } + } } } diff --git a/spring-context/src/test/java/org/springframework/cache/config/ExpressionCachingIntegrationTests.java b/spring-context/src/test/java/org/springframework/cache/config/ExpressionCachingIntegrationTests.java index 3f1f5a9b..f00ddde3 100644 --- a/spring-context/src/test/java/org/springframework/cache/config/ExpressionCachingIntegrationTests.java +++ b/spring-context/src/test/java/org/springframework/cache/config/ExpressionCachingIntegrationTests.java @@ -92,6 +92,7 @@ public class ExpressionCachingIntegrationTests { this.id = id; } + @SuppressWarnings("unused") public String getId() { return id; } @@ -104,6 +105,7 @@ public class ExpressionCachingIntegrationTests { this.id = id; } + @SuppressWarnings("unused") public String getId() { return id; } diff --git a/spring-context/src/test/java/org/springframework/cache/interceptor/CacheSyncFailureTests.java b/spring-context/src/test/java/org/springframework/cache/interceptor/CacheSyncFailureTests.java new file mode 100644 index 00000000..531bc01a --- /dev/null +++ b/spring-context/src/test/java/org/springframework/cache/interceptor/CacheSyncFailureTests.java @@ -0,0 +1,158 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.interceptor; + +import java.util.concurrent.atomic.AtomicLong; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import org.springframework.cache.CacheManager; +import org.springframework.cache.CacheTestUtils; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; +import org.springframework.cache.annotation.CachingConfigurerSupport; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Provides various failure scenario linked to the use of {@link Cacheable#sync()}. + * + * @author Stephane Nicoll + * @since 4.3 + */ +public class CacheSyncFailureTests { + + @Rule + public final ExpectedException thrown = ExpectedException.none(); + + private ConfigurableApplicationContext context; + + private SimpleService simpleService; + + @Before + public void setUp() { + this.context = new AnnotationConfigApplicationContext(Config.class); + this.simpleService = context.getBean(SimpleService.class); + } + + @After + public void closeContext() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void unlessSync() { + thrown.expect(IllegalStateException.class); + thrown.expectMessage("@Cacheable(sync=true) does not support unless attribute"); + this.simpleService.unlessSync("key"); + } + + @Test + public void severalCachesSync() { + thrown.expect(IllegalStateException.class); + thrown.expectMessage("@Cacheable(sync=true) only allows a single cache"); + this.simpleService.severalCachesSync("key"); + } + + @Test + public void severalCachesWithResolvedSync() { + thrown.expect(IllegalStateException.class); + thrown.expectMessage("@Cacheable(sync=true) only allows a single cache"); + this.simpleService.severalCachesWithResolvedSync("key"); + } + + @Test + public void syncWithAnotherOperation() { + thrown.expect(IllegalStateException.class); + thrown.expectMessage("@Cacheable(sync=true) cannot be combined with other cache operations"); + this.simpleService.syncWithAnotherOperation("key"); + } + + @Test + public void syncWithTwoGetOperations() { + thrown.expect(IllegalStateException.class); + thrown.expectMessage("Only one @Cacheable(sync=true) entry is allowed"); + this.simpleService.syncWithTwoGetOperations("key"); + } + + + static class SimpleService { + + private final AtomicLong counter = new AtomicLong(); + + @Cacheable(cacheNames = "testCache", sync = true, unless = "#result > 10") + public Object unlessSync(Object arg1) { + return this.counter.getAndIncrement(); + } + + @Cacheable(cacheNames = {"testCache", "anotherTestCache"}, sync = true) + public Object severalCachesSync(Object arg1) { + return this.counter.getAndIncrement(); + } + + @Cacheable(cacheResolver = "testCacheResolver", sync = true) + public Object severalCachesWithResolvedSync(Object arg1) { + return this.counter.getAndIncrement(); + } + + @Cacheable(cacheNames = "testCache", sync = true) + @CacheEvict(cacheNames = "anotherTestCache", key = "#arg1") + public Object syncWithAnotherOperation(Object arg1) { + return this.counter.getAndIncrement(); + } + + @Caching(cacheable = { + @Cacheable(cacheNames = "testCache", sync = true), + @Cacheable(cacheNames = "anotherTestCache", sync = true) + }) + public Object syncWithTwoGetOperations(Object arg1) { + return this.counter.getAndIncrement(); + } + } + + @Configuration + @EnableCaching + static class Config extends CachingConfigurerSupport { + + @Override + @Bean + public CacheManager cacheManager() { + return CacheTestUtils.createSimpleCacheManager("testCache", "anotherTestCache"); + } + + @Bean + public CacheResolver testCacheResolver() { + return new NamedCacheResolver(cacheManager(), "testCache", "anotherTestCache"); + } + + @Bean + public SimpleService simpleService() { + return new SimpleService(); + } + } + +} diff --git a/spring-context/src/test/java/org/springframework/cache/interceptor/ExpressionEvaluatorTests.java b/spring-context/src/test/java/org/springframework/cache/interceptor/ExpressionEvaluatorTests.java index 508a21fd..6e3b5633 100644 --- a/spring-context/src/test/java/org/springframework/cache/interceptor/ExpressionEvaluatorTests.java +++ b/spring-context/src/test/java/org/springframework/cache/interceptor/ExpressionEvaluatorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,11 +23,15 @@ import java.util.Iterator; import org.junit.Test; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.cache.annotation.AnnotationCacheOperationSource; import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Caching; import org.springframework.cache.concurrent.ConcurrentMapCache; import org.springframework.context.expression.AnnotatedElementKey; +import org.springframework.context.support.StaticApplicationContext; import org.springframework.expression.EvaluationContext; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.util.ReflectionUtils; @@ -43,15 +47,17 @@ import static org.junit.Assert.*; */ public class ExpressionEvaluatorTests { - private ExpressionEvaluator eval = new ExpressionEvaluator(); + private final CacheOperationExpressionEvaluator eval = new CacheOperationExpressionEvaluator(); + + private final AnnotationCacheOperationSource source = new AnnotationCacheOperationSource(); - private AnnotationCacheOperationSource source = new AnnotationCacheOperationSource(); private Collection<CacheOperation> getOps(String name) { Method method = ReflectionUtils.findMethod(AnnotatedClass.class, name, Object.class, Object.class); - return source.getCacheOperations(method, AnnotatedClass.class); + return this.source.getCacheOperations(method, AnnotatedClass.class); } + @Test public void testMultipleCachingSource() throws Exception { Collection<CacheOperation> ops = getOps("multipleCaching"); @@ -75,7 +81,8 @@ public class ExpressionEvaluatorTests { Object[] args = new Object[] { new Object(), new Object() }; Collection<ConcurrentMapCache> caches = Collections.singleton(new ConcurrentMapCache("test")); - EvaluationContext evalCtx = eval.createEvaluationContext(caches, method, args, target, target.getClass()); + EvaluationContext evalCtx = eval.createEvaluationContext(caches, method, args, + target, target.getClass(), null); Collection<CacheOperation> ops = getOps("multipleCaching"); Iterator<CacheOperation> it = ops.iterator(); @@ -105,14 +112,14 @@ public class ExpressionEvaluatorTests { @Test public void withoutReturnValue() throws Exception { - EvaluationContext context = createEvaluationContext(ExpressionEvaluator.NO_RESULT); + EvaluationContext context = createEvaluationContext(CacheOperationExpressionEvaluator.NO_RESULT); Object value = new SpelExpressionParser().parseExpression("#result").getValue(context); assertThat(value, nullValue()); } @Test public void unavailableReturnValue() throws Exception { - EvaluationContext context = createEvaluationContext(ExpressionEvaluator.RESULT_UNAVAILABLE); + EvaluationContext context = createEvaluationContext(CacheOperationExpressionEvaluator.RESULT_UNAVAILABLE); try { new SpelExpressionParser().parseExpression("#result").getValue(context); fail("Should have failed to parse expression, result not available"); @@ -122,14 +129,29 @@ public class ExpressionEvaluatorTests { } } + @Test + public void resolveBeanReference() throws Exception { + StaticApplicationContext applicationContext = new StaticApplicationContext(); + BeanDefinition beanDefinition = new RootBeanDefinition(String.class); + applicationContext.registerBeanDefinition("myBean", beanDefinition); + applicationContext.refresh(); + + EvaluationContext context = createEvaluationContext(CacheOperationExpressionEvaluator.NO_RESULT, applicationContext); + Object value = new SpelExpressionParser().parseExpression("@myBean.class.getName()").getValue(context); + assertThat(value, is(String.class.getName())); + } + private EvaluationContext createEvaluationContext(Object result) { + return createEvaluationContext(result, null); + } + + private EvaluationContext createEvaluationContext(Object result, BeanFactory beanFactory) { AnnotatedClass target = new AnnotatedClass(); Method method = ReflectionUtils.findMethod(AnnotatedClass.class, "multipleCaching", Object.class, Object.class); Object[] args = new Object[] { new Object(), new Object() }; Collection<ConcurrentMapCache> caches = Collections.singleton(new ConcurrentMapCache("test")); - EvaluationContext context = eval.createEvaluationContext(caches, method, args, target, target.getClass(), result); - return context; + return eval.createEvaluationContext(caches, method, args, target, target.getClass(), result, beanFactory); } diff --git a/spring-context/src/test/java/org/springframework/context/annotation/AbstractCircularImportDetectionTests.java b/spring-context/src/test/java/org/springframework/context/annotation/AbstractCircularImportDetectionTests.java index 10aa8ee9..d73412eb 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/AbstractCircularImportDetectionTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/AbstractCircularImportDetectionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -72,58 +72,71 @@ public abstract class AbstractCircularImportDetectionTests { @Configuration @Import(B.class) static class A { + @Bean TestBean b1() { return new TestBean(); } } + @Configuration @Import(A.class) static class B { + @Bean TestBean b2() { return new TestBean(); } } + @Configuration - @Import( { Y.class, Z.class }) + @Import({Y.class, Z.class}) class X { + @Bean TestBean x() { return new TestBean(); } } + @Configuration class Y { + @Bean TestBean y() { return new TestBean(); } } + @Configuration - @Import( { Z1.class, Z2.class }) + @Import({Z1.class, Z2.class}) class Z { + @Bean TestBean z() { return new TestBean(); } } + @Configuration class Z1 { + @Bean TestBean z1() { return new TestBean(); } } + @Configuration @Import(Z.class) class Z2 { + @Bean TestBean z2() { return new TestBean(); diff --git a/spring-context/src/test/java/org/springframework/context/annotation/AsmCircularImportDetectionTests.java b/spring-context/src/test/java/org/springframework/context/annotation/AsmCircularImportDetectionTests.java index 8cb5152e..c0c32c38 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/AsmCircularImportDetectionTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/AsmCircularImportDetectionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,12 +23,8 @@ import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; /** - * Unit test proving that ASM-based {@link ConfigurationClassParser} correctly detects circular - * use of the {@link Import @Import} annotation. - * - * <p>While this test is the only subclass of {@link AbstractCircularImportDetectionTests}, - * the hierarchy remains in place in case a JDT-based ConfigurationParser implementation - * needs to be developed. + * Unit test proving that ASM-based {@link ConfigurationClassParser} correctly detects + * circular use of the {@link Import @Import} annotation. * * @author Chris Beams */ diff --git a/spring-context/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java b/spring-context/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java index d4f47fb0..2dfd1ef0 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java @@ -560,6 +560,11 @@ public class CommonAnnotationBeanPostProcessorTests { assertFalse(((AnnotatedInitDestroyBean) bean).destroyCalled); } } + + @Override + public boolean requiresDestruction(Object bean) { + return true; + } } diff --git a/spring-context/src/test/java/org/springframework/context/annotation/ComponentScanAndImportAnnotationInteractionTests.java b/spring-context/src/test/java/org/springframework/context/annotation/ComponentScanAndImportAnnotationInteractionTests.java index 177e153e..96b18066 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/ComponentScanAndImportAnnotationInteractionTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/ComponentScanAndImportAnnotationInteractionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ package org.springframework.context.annotation; import org.junit.Test; import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.annotation.componentscan.importing.ImportingConfig; import org.springframework.context.annotation.componentscan.simple.SimpleComponent; /** @@ -58,7 +59,7 @@ public class ComponentScanAndImportAnnotationInteractionTests { @Test public void componentScanViaImportUsingAsm() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.registerBeanDefinition("config4", new RootBeanDefinition(Config3.class.getName())); + ctx.registerBeanDefinition("config", new RootBeanDefinition(Config3.class.getName())); ctx.refresh(); ctx.getBean(SimpleComponent.class); } @@ -71,6 +72,14 @@ public class ComponentScanAndImportAnnotationInteractionTests { ctx.getBean(SimpleComponent.class); } + @Test + public void circularImportViaComponentScan() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.registerBeanDefinition("config", new RootBeanDefinition(ImportingConfig.class.getName())); + ctx.refresh(); + ctx.getBean(SimpleComponent.class); + } + @ComponentScan("org.springframework.context.annotation.componentscan.simple") static final class Config1 { @@ -88,6 +97,7 @@ public class ComponentScanAndImportAnnotationInteractionTests { @ComponentScan("org.springframework.context.annotation.componentscan.simple") + @ComponentScan("org.springframework.context.annotation.componentscan.importing") public static final class ImportedConfig { } diff --git a/spring-context/src/test/java/org/springframework/context/annotation/ComponentScanAnnotationIntegrationTests.java b/spring-context/src/test/java/org/springframework/context/annotation/ComponentScanAnnotationIntegrationTests.java index f579aa32..2c51a7c8 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/ComponentScanAnnotationIntegrationTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/ComponentScanAnnotationIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,18 +33,31 @@ import example.scannable_implicitbasepackage.ComponentScanAnnotatedConfigWithImp import example.scannable_implicitbasepackage.ConfigurableComponent; import example.scannable_scoped.CustomScopeAnnotationBean; import example.scannable_scoped.MyScope; + import org.junit.Test; import org.springframework.aop.support.AopUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.annotation.CustomAutowireConfigurer; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.context.EnvironmentAware; +import org.springframework.context.ResourceLoaderAware; import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.ComponentScanParserTests.KustomAnnotationAutowiredBean; import org.springframework.context.annotation.componentscan.simple.ClassWithNestedComponents; import org.springframework.context.annotation.componentscan.simple.SimpleComponent; import org.springframework.context.support.GenericApplicationContext; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.filter.TypeFilter; import org.springframework.tests.context.SimpleMapScope; import org.springframework.util.SerializationTestUtils; @@ -159,6 +172,14 @@ public class ComponentScanAnnotationIntegrationTests { // custom scope annotation makes the bean prototype scoped. subsequent calls // to getBean should return distinct instances. assertThat(ctx.getBean(CustomScopeAnnotationBean.class), not(sameInstance(ctx.getBean(CustomScopeAnnotationBean.class)))); + assertThat(ctx.containsBean("scannedComponent"), is(false)); + } + + @Test + public void multiComponentScan() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MultiComponentScan.class); + assertThat(ctx.getBean(CustomScopeAnnotationBean.class), not(sameInstance(ctx.getBean(CustomScopeAnnotationBean.class)))); + assertThat(ctx.containsBean("scannedComponent"), is(true)); } @Test @@ -170,6 +191,12 @@ public class ComponentScanAnnotationIntegrationTests { } @Test + public void withAwareTypeFilter() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ComponentScanWithAwareTypeFilter.class); + assertTrue(ctx.getEnvironment().acceptsProfiles("the-filter-ran")); + } + + @Test public void withScopedProxy() throws IOException, ClassNotFoundException { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(ComponentScanWithScopedProxy.class); @@ -250,6 +277,47 @@ public class ComponentScanAnnotationIntegrationTests { public static class ComposedAnnotationConfig { } + public static class AwareTypeFilter implements TypeFilter, EnvironmentAware, + ResourceLoaderAware, BeanClassLoaderAware, BeanFactoryAware { + + private BeanFactory beanFactory; + private ClassLoader classLoader; + private ResourceLoader resourceLoader; + private Environment environment; + + @Override + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + this.beanFactory = beanFactory; + } + + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + @Override + public void setResourceLoader(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + } + + @Override + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + @Override + public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) { + ((ConfigurableEnvironment) this.environment).addActiveProfile("the-filter-ran"); + assertNotNull(this.beanFactory); + assertNotNull(this.classLoader); + assertNotNull(this.resourceLoader); + assertNotNull(this.environment); + return false; + } + + } + + } @@ -296,6 +364,12 @@ class MyBeanNameGenerator extends AnnotationBeanNameGenerator { class ComponentScanWithScopeResolver { } +@Configuration +@ComponentScan(basePackages = "example.scannable_scoped", scopeResolver = MyScopeMetadataResolver.class) +@ComponentScan(basePackages = "example.scannable_implicitbasepackage") +class MultiComponentScan { +} + class MyScopeMetadataResolver extends AnnotationScopeMetadataResolver { MyScopeMetadataResolver() { @@ -327,6 +401,14 @@ class ComponentScanWithCustomTypeFilter { } @Configuration +@ComponentScan( + basePackages = "org.springframework.context.annotation", + useDefaultFilters = false, + includeFilters = @Filter(type = FilterType.CUSTOM, classes = ComponentScanAnnotationIntegrationTests.AwareTypeFilter.class), + lazyInit = true) +class ComponentScanWithAwareTypeFilter {} + +@Configuration @ComponentScan(basePackages = "example.scannable", scopedProxy = ScopedProxyMode.INTERFACES, useDefaultFilters = false, @@ -370,3 +452,5 @@ class ComponentScanWithMultipleAnnotationIncludeFilters2 {} basePackages = "example.scannable", basePackageClasses = example.scannable._package.class) class ComponentScanWithBasePackagesAndValueAlias {} + + diff --git a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java index 5bebb953..8c96aacd 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java @@ -955,7 +955,7 @@ public class ConfigurationClassPostProcessorTests { @ComponentScan(basePackages = "org.springframework.context.annotation.componentscan.simple") @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) - public static @interface ComposedConfiguration { + public @interface ComposedConfiguration { } @ComposedConfiguration @@ -966,7 +966,7 @@ public class ConfigurationClassPostProcessorTests { @ComponentScan @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) - public static @interface ComposedConfigurationWithAttributeOverrides { + public @interface ComposedConfigurationWithAttributeOverrides { String[] basePackages() default {}; @@ -985,7 +985,7 @@ public class ConfigurationClassPostProcessorTests { @ComposedConfigurationWithAttributeOverrides @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) - public static @interface ComposedComposedConfigurationWithAttributeOverrides { + public @interface ComposedComposedConfigurationWithAttributeOverrides { String[] basePackages() default {}; } @@ -997,14 +997,14 @@ public class ConfigurationClassPostProcessorTests { @ComponentScan @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) - public static @interface MetaComponentScan { + public @interface MetaComponentScan { } @MetaComponentScan @Configuration @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) - public static @interface MetaComponentScanConfigurationWithAttributeOverrides { + public @interface MetaComponentScanConfigurationWithAttributeOverrides { String[] basePackages() default {}; } diff --git a/spring-context/src/test/java/org/springframework/context/annotation/EnableAspectJAutoProxyTests.java b/spring-context/src/test/java/org/springframework/context/annotation/EnableAspectJAutoProxyTests.java index 9995fc5a..feeee8a8 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/EnableAspectJAutoProxyTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/EnableAspectJAutoProxyTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,11 +20,13 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import example.scannable.FooService; +import example.scannable.FooServiceImpl; import example.scannable.ServiceInvocationCounter; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.junit.Test; +import org.springframework.aop.framework.AopContext; import org.springframework.aop.support.AopUtils; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; @@ -54,6 +56,14 @@ public class EnableAspectJAutoProxyTests { assertThat(AopUtils.isCglibProxy(ctx.getBean(FooService.class)), is(true)); } + @Test + public void withExposedProxy() { + ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigWithExposedProxy.class); + + aspectIsApplied(ctx); + assertThat(AopUtils.isJdkDynamicProxy(ctx.getBean(FooService.class)), is(true)); + } + private void aspectIsApplied(ApplicationContext ctx) { FooService fooService = ctx.getBean(FooService.class); ServiceInvocationCounter counter = ctx.getBean(ServiceInvocationCounter.class); @@ -96,30 +106,49 @@ public class EnableAspectJAutoProxyTests { } - @Configuration @ComponentScan("example.scannable") @EnableAspectJAutoProxy static class ConfigWithJdkProxy { } - @Configuration + @ComponentScan("example.scannable") @EnableAspectJAutoProxy(proxyTargetClass = true) static class ConfigWithCglibProxy { } + @ComponentScan("example.scannable") + @EnableAspectJAutoProxy(exposeProxy = true) + static class ConfigWithExposedProxy { + + @Bean + public FooService fooServiceImpl() { + return new FooServiceImpl() { + @Override + public String foo(int id) { + assertNotNull(AopContext.currentProxy()); + return super.foo(id); + } + }; + } + } + + @Retention(RetentionPolicy.RUNTIME) public @interface Loggable { } + @Loggable public static class SampleDto { } + public static class SampleInputBean { } + public static class SampleService { // Not matched method on {@link LoggingAspect}. @@ -131,6 +160,7 @@ public class EnableAspectJAutoProxyTests { } } + @Aspect public static class LoggingAspect { diff --git a/spring-context/src/test/java/org/springframework/context/annotation/PropertySourceAnnotationTests.java b/spring-context/src/test/java/org/springframework/context/annotation/PropertySourceAnnotationTests.java index 7150c4b0..b20afea1 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/PropertySourceAnnotationTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/PropertySourceAnnotationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,8 +17,12 @@ package org.springframework.context.annotation; import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Collections; import java.util.Iterator; +import java.util.Properties; import javax.inject.Inject; import org.junit.Rule; @@ -27,9 +31,13 @@ import org.junit.rules.ExpectedException; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.FactoryBean; +import org.springframework.core.annotation.AliasFor; import org.springframework.core.env.Environment; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.MutablePropertySources; +import org.springframework.core.io.support.EncodedResource; +import org.springframework.core.io.support.PropertiesLoaderUtils; +import org.springframework.core.io.support.PropertySourceFactory; import org.springframework.tests.sample.beans.TestBean; import static org.hamcrest.CoreMatchers.*; @@ -64,7 +72,7 @@ public class PropertySourceAnnotationTests { do { name = iterator.next().getName(); } - while(iterator.hasNext()); + while (iterator.hasNext()); assertThat(name, is("p1")); } @@ -112,6 +120,22 @@ public class PropertySourceAnnotationTests { } @Test + public void withCustomFactory() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(ConfigWithImplicitName.class, WithCustomFactory.class); + ctx.refresh(); + assertThat(ctx.getBean(TestBean.class).getName(), equalTo("P2TESTBEAN")); + } + + @Test + public void withCustomFactoryAsMeta() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(ConfigWithImplicitName.class, WithCustomFactoryAsMeta.class); + ctx.refresh(); + assertThat(ctx.getBean(TestBean.class).getName(), equalTo("P2TESTBEAN")); + } + + @Test public void withUnresolvablePlaceholder() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(ConfigWithUnresolvablePlaceholder.class); @@ -355,6 +379,43 @@ public class PropertySourceAnnotationTests { @Configuration + @PropertySource(value = "classpath:org/springframework/context/annotation/p2.properties", factory = MyCustomFactory.class) + static class WithCustomFactory { + } + + + @Configuration + @MyPropertySource(value = "classpath:org/springframework/context/annotation/p2.properties") + static class WithCustomFactoryAsMeta { + } + + + @Retention(RetentionPolicy.RUNTIME) + @PropertySource(value = {}, factory = MyCustomFactory.class) + public @interface MyPropertySource { + + @AliasFor(annotation = PropertySource.class) + String value(); + } + + + public static class MyCustomFactory implements PropertySourceFactory { + + @Override + public org.springframework.core.env.PropertySource createPropertySource(String name, EncodedResource resource) throws IOException { + Properties props = PropertiesLoaderUtils.loadProperties(resource); + return new org.springframework.core.env.PropertySource<Properties>("my" + name, props) { + @Override + public Object getProperty(String name) { + String value = props.getProperty(name); + return (value != null ? value.toUpperCase() : null); + } + }; + } + } + + + @Configuration @PropertySource( name = "psName", value = { diff --git a/spring-context/src/test/java/org/springframework/context/annotation/Spr12278Tests.java b/spring-context/src/test/java/org/springframework/context/annotation/Spr12278Tests.java new file mode 100644 index 00000000..13dcbccc --- /dev/null +++ b/spring-context/src/test/java/org/springframework/context/annotation/Spr12278Tests.java @@ -0,0 +1,115 @@ +/* + * Copyright 2002-2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.junit.After; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import org.springframework.beans.factory.BeanCreationException; + +import static org.hamcrest.core.Is.*; +import static org.junit.Assert.*; + +/** + * @author Stephane Nicoll + */ +public class Spr12278Tests { + + @Rule + public final ExpectedException thrown = ExpectedException.none(); + + private AnnotationConfigApplicationContext context; + + @After + public void close() { + if (context != null) { + context.close(); + } + } + + @Test + public void componentSingleConstructor() { + this.context = new AnnotationConfigApplicationContext(BaseConfiguration.class, + SingleConstructorComponent.class); + assertThat(this.context.getBean(SingleConstructorComponent.class).autowiredName, is("foo")); + } + + @Test + public void componentTwoConstructorsNoHint() { + this.context = new AnnotationConfigApplicationContext(BaseConfiguration.class, + TwoConstructorsComponent.class); + assertThat(this.context.getBean(TwoConstructorsComponent.class).name, is("fallback")); + } + + @Test + public void componentTwoSpecificConstructorsNoHint() { + thrown.expect(BeanCreationException.class); + thrown.expectMessage(NoSuchMethodException.class.getName()); + new AnnotationConfigApplicationContext(BaseConfiguration.class, + TwoSpecificConstructorsComponent.class); + } + + + @Configuration + static class BaseConfiguration { + + @Bean + public String autowiredName() { + return "foo"; + } + } + + private static class SingleConstructorComponent { + + private final String autowiredName; + + // No @Autowired - implicit wiring + public SingleConstructorComponent(String autowiredName) { + this.autowiredName = autowiredName; + } + + } + + private static class TwoConstructorsComponent { + + private final String name; + + public TwoConstructorsComponent(String name) { + this.name = name; + } + + public TwoConstructorsComponent() { + this("fallback"); + } + } + + private static class TwoSpecificConstructorsComponent { + + private final Integer counter; + + public TwoSpecificConstructorsComponent(Integer counter) { + this.counter = counter; + } + + public TwoSpecificConstructorsComponent(String name) { + this(Integer.valueOf(name)); + } + } + +} diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/AutowiredConfigurationTests.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/AutowiredConfigurationTests.java index 651bff79..cedd45bd 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/configuration/AutowiredConfigurationTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/configuration/AutowiredConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,14 +17,16 @@ package org.springframework.context.annotation.configuration; import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.List; import java.util.Optional; import javax.inject.Provider; import org.junit.Test; -import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.support.DefaultListableBeanFactory; @@ -36,6 +38,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.GenericApplicationContext; +import org.springframework.core.annotation.AliasFor; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.tests.sample.beans.Colour; @@ -89,19 +92,40 @@ public class AutowiredConfigurationTests { assertThat(context.getBean(TestBean.class).getName(), equalTo("")); } - /** - * {@link Autowired} constructors are not supported on {@link Configuration} classes - * due to CGLIB constraints - */ - @Test(expected = BeanCreationException.class) - public void testAutowiredConfigurationConstructorsAreNotSupported() { - DefaultListableBeanFactory context = new DefaultListableBeanFactory(); - new XmlBeanDefinitionReader(context).loadBeanDefinitions( + @Test + public void testAutowiredSingleConstructorSupported() { + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + new XmlBeanDefinitionReader(factory).loadBeanDefinitions( new ClassPathResource("annotation-config.xml", AutowiredConstructorConfig.class)); - GenericApplicationContext ctx = new GenericApplicationContext(context); + GenericApplicationContext ctx = new GenericApplicationContext(factory); ctx.registerBeanDefinition("config1", new RootBeanDefinition(AutowiredConstructorConfig.class)); ctx.registerBeanDefinition("config2", new RootBeanDefinition(ColorConfig.class)); - ctx.refresh(); // should throw + ctx.refresh(); + assertSame(ctx.getBean(AutowiredConstructorConfig.class).colour, ctx.getBean(Colour.class)); + } + + @Test + public void testObjectFactoryConstructorWithTypeVariable() { + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + new XmlBeanDefinitionReader(factory).loadBeanDefinitions( + new ClassPathResource("annotation-config.xml", ObjectFactoryConstructorConfig.class)); + GenericApplicationContext ctx = new GenericApplicationContext(factory); + ctx.registerBeanDefinition("config1", new RootBeanDefinition(ObjectFactoryConstructorConfig.class)); + ctx.registerBeanDefinition("config2", new RootBeanDefinition(ColorConfig.class)); + ctx.refresh(); + assertSame(ctx.getBean(ObjectFactoryConstructorConfig.class).colour, ctx.getBean(Colour.class)); + } + + @Test + public void testAutowiredAnnotatedConstructorSupported() { + DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); + new XmlBeanDefinitionReader(factory).loadBeanDefinitions( + new ClassPathResource("annotation-config.xml", MultipleConstructorConfig.class)); + GenericApplicationContext ctx = new GenericApplicationContext(factory); + ctx.registerBeanDefinition("config1", new RootBeanDefinition(MultipleConstructorConfig.class)); + ctx.registerBeanDefinition("config2", new RootBeanDefinition(ColorConfig.class)); + ctx.refresh(); + assertSame(ctx.getBean(MultipleConstructorConfig.class).colour, ctx.getBean(Colour.class)); } @Test @@ -112,6 +136,20 @@ public class AutowiredConfigurationTests { } @Test + public void testValueInjectionWithMetaAnnotation() { + AnnotationConfigApplicationContext context = + new AnnotationConfigApplicationContext(ValueConfigWithMetaAnnotation.class); + doTestValueInjection(context); + } + + @Test + public void testValueInjectionWithAliasedMetaAnnotation() { + AnnotationConfigApplicationContext context = + new AnnotationConfigApplicationContext(ValueConfigWithAliasedMetaAnnotation.class); + doTestValueInjection(context); + } + + @Test public void testValueInjectionWithProviderFields() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ValueConfigWithProviderFields.class); @@ -225,7 +263,7 @@ public class AutowiredConfigurationTests { Colour colour; - @Autowired + // @Autowired AutowiredConstructorConfig(Colour colour) { this.colour = colour; } @@ -233,6 +271,34 @@ public class AutowiredConfigurationTests { @Configuration + static class ObjectFactoryConstructorConfig { + + Colour colour; + + // @Autowired + ObjectFactoryConstructorConfig(ObjectFactory<Colour> colourFactory) { + this.colour = colourFactory.getObject(); + } + } + + + @Configuration + static class MultipleConstructorConfig { + + Colour colour; + + @Autowired + MultipleConstructorConfig(Colour colour) { + this.colour = colour; + } + + MultipleConstructorConfig(String test) { + this.colour = new Colour(test); + } + } + + + @Configuration static class ColorConfig { @Bean @@ -267,6 +333,73 @@ public class AutowiredConfigurationTests { } + @Value("#{systemProperties[myProp]}") + @Retention(RetentionPolicy.RUNTIME) + public @interface MyProp { + } + + + @Configuration + @Scope("prototype") + static class ValueConfigWithMetaAnnotation { + + @MyProp + private String name; + + private String name2; + + @MyProp + public void setName2(String name) { + this.name2 = name; + } + + @Bean @Scope("prototype") + public TestBean testBean() { + return new TestBean(name); + } + + @Bean @Scope("prototype") + public TestBean testBean2() { + return new TestBean(name2); + } + } + + + @Value("") + @Retention(RetentionPolicy.RUNTIME) + public @interface AliasedProp { + + @AliasFor(annotation = Value.class) + String value(); + } + + + @Configuration + @Scope("prototype") + static class ValueConfigWithAliasedMetaAnnotation { + + @AliasedProp("#{systemProperties[myProp]}") + private String name; + + private String name2; + + @AliasedProp("#{systemProperties[myProp]}") + public void setName2(String name) { + this.name2 = name; + } + + @Bean @Scope("prototype") + public TestBean testBean() { + return new TestBean(name); + } + + @Bean @Scope("prototype") + public TestBean testBean2() { + return new TestBean(name2); + } + } + + @Configuration static class ValueConfigWithProviderFields { diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassAspectIntegrationTests.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassAspectIntegrationTests.java index 2e56b557..77f2df5e 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassAspectIntegrationTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassAspectIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -82,7 +82,9 @@ public class ConfigurationClassAspectIntegrationTests { public void withInnerClassAndLambdaExpression() { ApplicationContext ctx = new AnnotationConfigApplicationContext(Application.class, CountingAspect.class); ctx.getBeansOfType(Runnable.class).forEach((k, v) -> v.run()); - assertEquals(2, ctx.getBean(CountingAspect.class).count); + + // TODO: returns just 1 as of AspectJ 1.9 beta 3, not detecting the applicable lambda expression anymore + // assertEquals(2, ctx.getBean(CountingAspect.class).count); } diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java index 78b990b1..bf4c9e6a 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,8 +27,11 @@ import org.junit.Test; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InjectionPoint; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Required; import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor; import org.springframework.beans.factory.annotation.Value; @@ -36,6 +39,7 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.DependencyDescriptor; import org.springframework.beans.factory.config.ListFactoryBean; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; @@ -71,7 +75,7 @@ public class ConfigurationClassProcessingTests { * When complete, the factory is ready to service requests for any {@link Bean} methods * declared by <var>configClasses</var>. */ - private ListableBeanFactory initBeanFactory(Class<?>... configClasses) { + private DefaultListableBeanFactory initBeanFactory(Class<?>... configClasses) { DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); for (Class<?> configClass : configClasses) { String configBeanName = configClass.getName(); @@ -111,7 +115,7 @@ public class ConfigurationClassProcessingTests { BeanFactory factory = initBeanFactory(ConfigWithBeanWithAliases.class); assertSame(factory.getBean("name1"), ConfigWithBeanWithAliases.testBean); String[] aliases = factory.getAliases("name1"); - for(String alias : aliases) + for (String alias : aliases) assertSame(factory.getBean(alias), ConfigWithBeanWithAliases.testBean); // method name should not be registered @@ -203,6 +207,21 @@ public class ConfigurationClassProcessingTests { } @Test + public void configurationWithAdaptivePrototypes() { + AnnotationConfigApplicationContext factory = new AnnotationConfigApplicationContext(); + factory.register(ConfigWithPrototypeBean.class, AdaptiveInjectionPoints.class); + factory.refresh(); + + AdaptiveInjectionPoints adaptive = factory.getBean(AdaptiveInjectionPoints.class); + assertEquals("adaptiveInjectionPoint1", adaptive.adaptiveInjectionPoint1.getName()); + assertEquals("setAdaptiveInjectionPoint2", adaptive.adaptiveInjectionPoint2.getName()); + + adaptive = factory.getBean(AdaptiveInjectionPoints.class); + assertEquals("adaptiveInjectionPoint1", adaptive.adaptiveInjectionPoint1.getName()); + assertEquals("setAdaptiveInjectionPoint2", adaptive.adaptiveInjectionPoint2.getName()); + } + + @Test public void configurationWithPostProcessor() { AnnotationConfigApplicationContext factory = new AnnotationConfigApplicationContext(); factory.register(ConfigWithPostProcessor.class); @@ -324,6 +343,31 @@ public class ConfigurationClassProcessingTests { public TestBean baz() { return new TestBean("baz"); } + + @Bean @Scope("prototype") + public TestBean adaptive1(InjectionPoint ip) { + return new TestBean(ip.getMember().getName()); + } + + @Bean @Scope("prototype") + public TestBean adaptive2(DependencyDescriptor dd) { + return new TestBean(dd.getMember().getName()); + } + } + + + @Scope("prototype") + static class AdaptiveInjectionPoints { + + @Autowired @Qualifier("adaptive1") + public TestBean adaptiveInjectionPoint1; + + public TestBean adaptiveInjectionPoint2; + + @Autowired @Qualifier("adaptive2") + public void setAdaptiveInjectionPoint2(TestBean adaptiveInjectionPoint2) { + this.adaptiveInjectionPoint2 = adaptiveInjectionPoint2; + } } diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassWithPlaceholderConfigurerBeanTests.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassWithPlaceholderConfigurerBeanTests.java index 43c3397b..3c8d933d 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassWithPlaceholderConfigurerBeanTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassWithPlaceholderConfigurerBeanTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,15 +41,16 @@ import static org.junit.Assert.*; * and @Value fields in the same configuration class are mutually exclusive. * * @author Chris Beams + * @author Juergen Hoeller */ public class ConfigurationClassWithPlaceholderConfigurerBeanTests { /** * Intentionally ignored test proving that a property placeholder bean * cannot be declared in the same configuration class that has a @Value - * field in need of placeholder replacement. It's an obvious chicken-and-egg issue. + * field in need of placeholder replacement. It's an obvious chicken-and-egg issue. * The solution is to do as {@link #valueFieldsAreProcessedWhenPlaceholderConfigurerIsSegregated()} - * does and segragate the two bean definitions across configuration classes. + * does and segregate the two bean definitions across configuration classes. */ @Ignore @Test public void valueFieldsAreNotProcessedWhenPlaceholderConfigurerIsIntegrated() { @@ -75,44 +76,57 @@ public class ConfigurationClassWithPlaceholderConfigurerBeanTests { TestBean testBean = ctx.getBean(TestBean.class); assertThat(testBean.getName(), equalTo("foo")); } -} -@Configuration -class ConfigWithValueField { + @Test + public void valueFieldsResolveToPlaceholderSpecifiedDefaultValue() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(ConfigWithValueField.class); + ctx.register(ConfigWithPlaceholderConfigurer.class); + ctx.refresh(); + + TestBean testBean = ctx.getBean(TestBean.class); + assertThat(testBean.getName(), equalTo("bar")); + } + - @Value("${test.name}") - private String name; + @Configuration + static class ConfigWithValueField { - @Bean - public ITestBean testBean() { - return new TestBean(this.name); + @Value("${test.name:bar}") + private String name; + + @Bean + public ITestBean testBean() { + return new TestBean(this.name); + } } -} -@Configuration -class ConfigWithPlaceholderConfigurer { - @Bean - public PropertySourcesPlaceholderConfigurer ppc() { - return new PropertySourcesPlaceholderConfigurer(); + @Configuration + static class ConfigWithPlaceholderConfigurer { + + @Bean + public PropertySourcesPlaceholderConfigurer ppc() { + return new PropertySourcesPlaceholderConfigurer(); + } } -} -@Configuration -class ConfigWithValueFieldAndPlaceholderConfigurer { + @Configuration + static class ConfigWithValueFieldAndPlaceholderConfigurer { - @Value("${test.name}") - private String name; + @Value("${test.name}") + private String name; - @Bean - public ITestBean testBean() { - return new TestBean(this.name); - } + @Bean + public ITestBean testBean() { + return new TestBean(this.name); + } - @Bean - public PropertySourcesPlaceholderConfigurer ppc() { - return new PropertySourcesPlaceholderConfigurer(); + @Bean + public PropertySourcesPlaceholderConfigurer ppc() { + return new PropertySourcesPlaceholderConfigurer(); + } } -}
\ No newline at end of file +} diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ImportResourceTests.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ImportResourceTests.java index 72ed279f..a0f6a0df 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ImportResourceTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ImportResourceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,15 +20,12 @@ import java.util.Collections; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; - -import org.junit.Ignore; import org.junit.Test; import org.springframework.aop.support.AopUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader; -import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -59,26 +56,6 @@ public class ImportResourceTests { ctx.close(); } - @Ignore // TODO: SPR-6310 - @Test - public void importXmlWithRelativePath() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ImportXmlWithRelativePathConfig.class); - assertTrue("did not contain java-declared bean", ctx.containsBean("javaDeclaredBean")); - assertTrue("did not contain xml-declared bean", ctx.containsBean("xmlDeclaredBean")); - TestBean tb = ctx.getBean("javaDeclaredBean", TestBean.class); - assertEquals("myName", tb.getName()); - ctx.close(); - } - - @Ignore // TODO: SPR-6310 - @Test - public void importXmlByConvention() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext( - ImportXmlByConventionConfig.class); - assertTrue("context does not contain xml-declared bean", ctx.containsBean("xmlDeclaredBean")); - ctx.close(); - } - @Test public void importXmlIsInheritedFromSuperclassDeclarations() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(FirstLevelSubConfig.class); @@ -112,15 +89,6 @@ public class ImportResourceTests { ctx.close(); } - @Ignore // TODO: SPR-6327 - @Test - public void importDifferentResourceTypes() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SubResourceConfig.class); - assertTrue(ctx.containsBean("propertiesDeclaredBean")); - assertTrue(ctx.containsBean("xmlDeclaredBean")); - ctx.close(); - } - @Test public void importWithPlaceholder() throws Exception { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); @@ -160,19 +128,6 @@ public class ImportResourceTests { } @Configuration - @ImportResource("ImportXmlConfig-context.xml") - static class ImportXmlWithRelativePathConfig { - public @Bean TestBean javaDeclaredBean() { - return new TestBean("java.declared"); - } - } - - @Configuration - //@ImportXml - static class ImportXmlByConventionConfig { - } - - @Configuration @ImportResource("classpath:org/springframework/context/annotation/configuration/ImportXmlConfig-context.xml") static class BaseConfig { } @@ -217,9 +172,4 @@ public class ImportResourceTests { static class ImportNonXmlResourceConfig { } - @Configuration - @ImportResource(locations = "classpath:org/springframework/context/annotation/configuration/ImportXmlConfig-context.xml", reader = XmlBeanDefinitionReader.class) - static class SubResourceConfig extends ImportNonXmlResourceConfig { - } - } diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ScopingTests.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ScopingTests.java index f553b215..a9bba8cf 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ScopingTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ScopingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,9 +31,9 @@ import org.springframework.aop.scope.ScopedObject; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ConfigurationClassPostProcessor; import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.ScopedProxyMode; import org.springframework.context.support.GenericApplicationContext; @@ -79,8 +79,7 @@ public class ScopingTests { beanFactory.registerScope(SCOPE, customScope); } beanFactory.registerBeanDefinition("config", new RootBeanDefinition(configClass)); - GenericApplicationContext ctx = new GenericApplicationContext(beanFactory); - ctx.addBeanFactoryPostProcessor(new ConfigurationClassPostProcessor()); + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(beanFactory); ctx.refresh(); return ctx; } @@ -222,13 +221,6 @@ public class ScopingTests { assertSame(spouse.getName(), spouseFromBF.getName()); } - @Test - public void testScopedConfigurationBeanDefinitionCount() throws Exception { - // count the beans - // 6 @Beans + 1 Configuration + 2 scoped proxy + 1 importRegistry + 1 enhanced config post processor - assertEquals(11, ctx.getBeanDefinitionCount()); - } - static class Foo { @@ -365,7 +357,7 @@ public class ScopingTests { @Override public void registerDestructionCallback(String name, Runnable callback) { - // do nothing + throw new IllegalStateException("Not supposed to be called"); } @Override diff --git a/spring-context/src/test/java/org/springframework/context/annotation/spr10546/Spr10546Tests.java b/spring-context/src/test/java/org/springframework/context/annotation/spr10546/Spr10546Tests.java index d02b2ba3..758fa053 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/spr10546/Spr10546Tests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/spr10546/Spr10546Tests.java @@ -37,7 +37,7 @@ public class Spr10546Tests { @After public void closeContext() { - if(context != null) { + if (context != null) { context.close(); } } diff --git a/spring-context/src/test/java/org/springframework/context/config/ContextNamespaceHandlerTests.java b/spring-context/src/test/java/org/springframework/context/config/ContextNamespaceHandlerTests.java index e6a3b304..ba04db49 100644 --- a/spring-context/src/test/java/org/springframework/context/config/ContextNamespaceHandlerTests.java +++ b/spring-context/src/test/java/org/springframework/context/config/ContextNamespaceHandlerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,14 +18,10 @@ package org.springframework.context.config; import java.util.Calendar; import java.util.Date; -import java.util.Map; import org.junit.After; import org.junit.Test; -import org.springframework.beans.factory.config.PlaceholderConfigurerSupport; -import org.springframework.beans.factory.config.PropertyOverrideConfigurer; -import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.GenericXmlApplicationContext; @@ -53,9 +49,6 @@ public class ContextNamespaceHandlerTests { public void propertyPlaceholder() throws Exception { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "contextNamespaceHandlerTests-replace.xml", getClass()); - Map<String, PlaceholderConfigurerSupport> beans = applicationContext - .getBeansOfType(PlaceholderConfigurerSupport.class); - assertFalse("No PropertyPlaceholderConfigurer found", beans.isEmpty()); assertEquals("bar", applicationContext.getBean("string")); assertEquals("null", applicationContext.getBean("nullString")); } @@ -66,9 +59,6 @@ public class ContextNamespaceHandlerTests { try { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "contextNamespaceHandlerTests-system.xml", getClass()); - Map<String, PropertyPlaceholderConfigurer> beans = applicationContext - .getBeansOfType(PropertyPlaceholderConfigurer.class); - assertFalse("No PropertyPlaceholderConfigurer found", beans.isEmpty()); assertEquals("spam", applicationContext.getBean("string")); assertEquals("none", applicationContext.getBean("fallback")); } @@ -86,9 +76,6 @@ public class ContextNamespaceHandlerTests { applicationContext.setEnvironment(env); applicationContext.load(new ClassPathResource("contextNamespaceHandlerTests-simple.xml", getClass())); applicationContext.refresh(); - Map<String, PlaceholderConfigurerSupport> beans = applicationContext - .getBeansOfType(PlaceholderConfigurerSupport.class); - assertFalse("No PropertyPlaceholderConfigurer found", beans.isEmpty()); assertEquals("spam", applicationContext.getBean("string")); assertEquals("none", applicationContext.getBean("fallback")); } @@ -97,9 +84,6 @@ public class ContextNamespaceHandlerTests { public void propertyPlaceholderLocation() throws Exception { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "contextNamespaceHandlerTests-location.xml", getClass()); - Map<String, PropertyPlaceholderConfigurer> beans = applicationContext - .getBeansOfType(PropertyPlaceholderConfigurer.class); - assertFalse("No PropertyPlaceholderConfigurer found", beans.isEmpty()); assertEquals("bar", applicationContext.getBean("foo")); assertEquals("foo", applicationContext.getBean("bar")); assertEquals("maps", applicationContext.getBean("spam")); @@ -109,9 +93,6 @@ public class ContextNamespaceHandlerTests { public void propertyPlaceholderIgnored() throws Exception { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "contextNamespaceHandlerTests-replace-ignore.xml", getClass()); - Map<String, PlaceholderConfigurerSupport> beans = applicationContext - .getBeansOfType(PlaceholderConfigurerSupport.class); - assertFalse("No PropertyPlaceholderConfigurer found", beans.isEmpty()); assertEquals("${bar}", applicationContext.getBean("string")); assertEquals("null", applicationContext.getBean("nullString")); } @@ -120,9 +101,6 @@ public class ContextNamespaceHandlerTests { public void propertyOverride() throws Exception { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "contextNamespaceHandlerTests-override.xml", getClass()); - Map<String, PropertyOverrideConfigurer> beans = applicationContext - .getBeansOfType(PropertyOverrideConfigurer.class); - assertFalse("No PropertyOverrideConfigurer found", beans.isEmpty()); Date date = (Date) applicationContext.getBean("date"); Calendar calendar = Calendar.getInstance(); calendar.setTime(date); diff --git a/spring-context/src/test/java/org/springframework/context/event/AbstractApplicationEventListenerTests.java b/spring-context/src/test/java/org/springframework/context/event/AbstractApplicationEventListenerTests.java index 72a2561b..f7aedb13 100644 --- a/spring-context/src/test/java/org/springframework/context/event/AbstractApplicationEventListenerTests.java +++ b/spring-context/src/test/java/org/springframework/context/event/AbstractApplicationEventListenerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,7 +49,7 @@ public abstract class AbstractApplicationEventListenerTests { } public T getPayload() { - return payload; + return this.payload; } } @@ -117,13 +117,13 @@ public abstract class AbstractApplicationEventListenerTests { } } + @SuppressWarnings("rawtypes") static class RawApplicationListener implements ApplicationListener { @Override public void onApplicationEvent(ApplicationEvent event) { } } - @SuppressWarnings("unused") static class TestEvents { public ApplicationEvent applicationEvent; diff --git a/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java b/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java index 3e52c58b..89738660 100644 --- a/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java +++ b/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java @@ -54,6 +54,7 @@ import org.springframework.context.event.test.GenericEventPojo; import org.springframework.context.event.test.Identifiable; import org.springframework.context.event.test.TestEvent; import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.core.annotation.AliasFor; import org.springframework.core.annotation.Order; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.EnableAsync; @@ -116,7 +117,7 @@ public class AnnotationDrivenEventListenerTests { public void metaAnnotationIsDiscovered() { load(MetaAnnotationListenerTestBean.class); - MetaAnnotationListenerTestBean bean = context.getBean(MetaAnnotationListenerTestBean.class); + MetaAnnotationListenerTestBean bean = this.context.getBean(MetaAnnotationListenerTestBean.class); this.eventCollector.assertNoEventReceived(bean); TestEvent event = new TestEvent(); @@ -148,9 +149,9 @@ public class AnnotationDrivenEventListenerTests { failingContext.register(BasicConfiguration.class, InvalidMethodSignatureEventListener.class); - thrown.expect(BeanInitializationException.class); - thrown.expectMessage(InvalidMethodSignatureEventListener.class.getName()); - thrown.expectMessage("cannotBeCalled"); + this.thrown.expect(BeanInitializationException.class); + this.thrown.expectMessage(InvalidMethodSignatureEventListener.class.getName()); + this.thrown.expectMessage("cannotBeCalled"); failingContext.refresh(); } @@ -286,6 +287,17 @@ public class AnnotationDrivenEventListenerTests { } @Test + public void privateMethodOnCglibProxyFails() throws Exception { + try { + load(CglibProxyWithPrivateMethod.class); + fail("Should have thrown BeanInitializationException"); + } + catch (BeanInitializationException ex) { + assertTrue(ex.getCause() instanceof IllegalStateException); + } + } + + @Test public void eventListenerWorksWithCustomScope() throws Exception { load(CustomScopeTestBean.class); CustomScope customScope = new CustomScope(); @@ -329,7 +341,7 @@ public class AnnotationDrivenEventListenerTests { this.eventCollector.assertNoEventReceived(listener); this.context.publishEvent(event); - countDownLatch.await(2, TimeUnit.SECONDS); + this.countDownLatch.await(2, TimeUnit.SECONDS); this.eventCollector.assertEvent(listener, event); this.eventCollector.assertTotalEventsCount(1); } @@ -344,7 +356,7 @@ public class AnnotationDrivenEventListenerTests { this.eventCollector.assertNoEventReceived(listener); this.context.publishEvent(event); - countDownLatch.await(2, TimeUnit.SECONDS); + this.countDownLatch.await(2, TimeUnit.SECONDS); this.eventCollector.assertEvent(listener, event); this.eventCollector.assertTotalEventsCount(1); } @@ -359,7 +371,7 @@ public class AnnotationDrivenEventListenerTests { this.eventCollector.assertNoEventReceived(listener); this.context.publishEvent(event); - countDownLatch.await(2, TimeUnit.SECONDS); + this.countDownLatch.await(2, TimeUnit.SECONDS); this.eventCollector.assertEvent(listener, event); this.eventCollector.assertTotalEventsCount(1); } @@ -389,7 +401,7 @@ public class AnnotationDrivenEventListenerTests { this.eventCollector.assertNoEventReceived(listener); this.context.publishEvent(event); - countDownLatch.await(2, TimeUnit.SECONDS); + this.countDownLatch.await(2, TimeUnit.SECONDS); this.eventCollector.assertEvent(listener, event); this.eventCollector.assertTotalEventsCount(1); @@ -487,6 +499,10 @@ public class AnnotationDrivenEventListenerTests { this.context.publishEvent(timestamp); this.eventCollector.assertEvent(listener, event, "OK", timestamp); this.eventCollector.assertTotalEventsCount(3); + + this.context.publishEvent(42d); + this.eventCollector.assertEvent(listener, event, "OK", timestamp, 42d); + this.eventCollector.assertTotalEventsCount(4); } @Test @@ -508,6 +524,10 @@ public class AnnotationDrivenEventListenerTests { this.context.publishEvent(maxLong); this.eventCollector.assertNoEventReceived(listener); this.eventCollector.assertTotalEventsCount(0); + + this.context.publishEvent(24d); + this.eventCollector.assertNoEventReceived(listener); + this.eventCollector.assertTotalEventsCount(0); } @Test @@ -559,6 +579,18 @@ public class AnnotationDrivenEventListenerTests { public CountDownLatch testCountDownLatch() { return new CountDownLatch(1); } + + @Bean + public TestConditionEvaluator conditionEvaluator() { + return new TestConditionEvaluator(); + } + + static class TestConditionEvaluator { + + public boolean valid(Double ratio) { + return new Double(42).equals(ratio); + } + } } @@ -667,7 +699,7 @@ public class AnnotationDrivenEventListenerTests { public void handleAsync(AnotherTestEvent event) { collectEvent(event); if ("fail".equals(event.content)) { - countDownLatch.countDown(); + this.countDownLatch.countDown(); throw new IllegalStateException("Test exception"); } } @@ -685,7 +717,7 @@ public class AnnotationDrivenEventListenerTests { public void handleAsync(AnotherTestEvent event) { assertTrue(!Thread.currentThread().getName().equals(event.content)); collectEvent(event); - countDownLatch.countDown(); + this.countDownLatch.countDown(); } } @@ -724,15 +756,15 @@ public class AnnotationDrivenEventListenerTests { @EventListener @Override public void handleIt(TestEvent event) { - eventCollector.addEvent(this, event); + this.eventCollector.addEvent(this, event); } @EventListener @Async public void handleAsync(AnotherTestEvent event) { assertTrue(!Thread.currentThread().getName().equals(event.content)); - eventCollector.addEvent(this, event); - countDownLatch.countDown(); + this.eventCollector.addEvent(this, event); + this.countDownLatch.countDown(); } } @@ -750,15 +782,15 @@ public class AnnotationDrivenEventListenerTests { @EventListener @Override public void handleIt(TestEvent event) { - eventCollector.addEvent(this, event); + this.eventCollector.addEvent(this, event); } @EventListener @Async public void handleAsync(AnotherTestEvent event) { assertTrue(!Thread.currentThread().getName().equals(event.content)); - eventCollector.addEvent(this, event); - countDownLatch.countDown(); + this.eventCollector.addEvent(this, event); + this.countDownLatch.countDown(); } } @@ -779,7 +811,7 @@ public class AnnotationDrivenEventListenerTests { @Override public void handleIt(TestEvent event) { - eventCollector.addEvent(this, event); + this.eventCollector.addEvent(this, event); } } @@ -796,6 +828,17 @@ public class AnnotationDrivenEventListenerTests { @Component + @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) + static class CglibProxyWithPrivateMethod extends AbstractTestEventListener { + + @EventListener + private void handleIt(TestEvent event) { + collectEvent(event); + } + } + + + @Component @Scope(scopeName = "custom", proxyMode = ScopedProxyMode.TARGET_CLASS) static class CustomScopeTestBean extends AbstractTestEventListener { @@ -826,6 +869,16 @@ public class AnnotationDrivenEventListenerTests { } + + @EventListener + @Retention(RetentionPolicy.RUNTIME) + public @interface ConditionalEvent { + + @AliasFor(annotation = EventListener.class, attribute = "condition") + String value(); + } + + @Component static class ConditionalEventListener extends TestEventListener { @@ -841,10 +894,15 @@ public class AnnotationDrivenEventListenerTests { super.handleString(payload); } - @EventListener(condition = "#root.event.timestamp > #p0") + @ConditionalEvent("#root.event.timestamp > #p0") public void handleTimestamp(Long timestamp) { collectEvent(timestamp); } + + @ConditionalEvent("@conditionEvaluator.valid(#p0)") + public void handleRatio(Double ratio) { + collectEvent(ratio); + } } @@ -856,18 +914,18 @@ public class AnnotationDrivenEventListenerTests { @EventListener @Order(50) public void handleThird(String payload) { - order.add("third"); + this.order.add("third"); } @EventListener @Order(-50) public void handleFirst(String payload) { - order.add("first"); + this.order.add("first"); } @EventListener public void handleSecond(String payload) { - order.add("second"); + this.order.add("second"); } } diff --git a/spring-context/src/test/java/org/springframework/context/event/ApplicationContextEventTests.java b/spring-context/src/test/java/org/springframework/context/event/ApplicationContextEventTests.java index a56c77be..c65d60b8 100644 --- a/spring-context/src/test/java/org/springframework/context/event/ApplicationContextEventTests.java +++ b/spring-context/src/test/java/org/springframework/context/event/ApplicationContextEventTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -452,7 +452,7 @@ public class ApplicationContextEventTests extends AbstractApplicationEventListen @Override public void onApplicationEvent(MyEvent event) { - assertTrue(otherListener.seenEvents.contains(event)); + assertTrue(this.otherListener.seenEvents.contains(event)); } } @@ -503,7 +503,7 @@ public class ApplicationContextEventTests extends AbstractApplicationEventListen @Override public void onApplicationEvent(MyEvent event) { - assertTrue(otherListener.seenEvents.contains(event)); + assertTrue(this.otherListener.seenEvents.contains(event)); } } diff --git a/spring-context/src/test/java/org/springframework/context/event/ApplicationListenerMethodAdapterTests.java b/spring-context/src/test/java/org/springframework/context/event/ApplicationListenerMethodAdapterTests.java index b9cc4dd0..77373180 100644 --- a/spring-context/src/test/java/org/springframework/context/event/ApplicationListenerMethodAdapterTests.java +++ b/spring-context/src/test/java/org/springframework/context/event/ApplicationListenerMethodAdapterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -148,7 +148,7 @@ public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEv Method method = ReflectionUtils.findMethod(SampleEvents.class, "tooManyParameters", String.class, String.class); - thrown.expect(IllegalStateException.class); + this.thrown.expect(IllegalStateException.class); createTestInstance(method); } @@ -157,7 +157,7 @@ public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEv Method method = ReflectionUtils.findMethod(SampleEvents.class, "noParameter"); - thrown.expect(IllegalStateException.class); + this.thrown.expect(IllegalStateException.class); createTestInstance(method); } @@ -166,7 +166,7 @@ public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEv Method method = ReflectionUtils.findMethod(SampleEvents.class, "moreThanOneParameter", String.class, Integer.class); - thrown.expect(IllegalStateException.class); + this.thrown.expect(IllegalStateException.class); createTestInstance(method); } @@ -237,9 +237,9 @@ public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEv "generateRuntimeException", GenericTestEvent.class); GenericTestEvent<String> event = createGenericTestEvent("fail"); - thrown.expect(IllegalStateException.class); - thrown.expectMessage("Test exception"); - thrown.expectCause(is(isNull(Throwable.class))); + this.thrown.expect(IllegalStateException.class); + this.thrown.expectMessage("Test exception"); + this.thrown.expectCause(is(isNull(Throwable.class))); invokeListener(method, event); } @@ -249,8 +249,8 @@ public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEv "generateCheckedException", GenericTestEvent.class); GenericTestEvent<String> event = createGenericTestEvent("fail"); - thrown.expect(UndeclaredThrowableException.class); - thrown.expectCause(is(instanceOf(IOException.class))); + this.thrown.expect(UndeclaredThrowableException.class); + this.thrown.expectCause(is(instanceOf(IOException.class))); invokeListener(method, event); } @@ -265,8 +265,8 @@ public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEv Method method = ReflectionUtils.findMethod(InvalidProxyTestBean.class, "handleIt2", ApplicationEvent.class); StaticApplicationListenerMethodAdapter listener = new StaticApplicationListenerMethodAdapter(method, bean); - thrown.expect(IllegalStateException.class); - thrown.expectMessage("handleIt2"); + this.thrown.expect(IllegalStateException.class); + this.thrown.expectMessage("handleIt2"); listener.onApplicationEvent(createGenericTestEvent("test")); } @@ -373,7 +373,7 @@ public class ApplicationListenerMethodAdapterTests extends AbstractApplicationEv @Override public Object getTargetBean() { - return targetBean; + return this.targetBean; } } diff --git a/spring-context/src/test/java/org/springframework/context/event/EventPublicationInterceptorTests.java b/spring-context/src/test/java/org/springframework/context/event/EventPublicationInterceptorTests.java index 0cb677c3..6437ac57 100644 --- a/spring-context/src/test/java/org/springframework/context/event/EventPublicationInterceptorTests.java +++ b/spring-context/src/test/java/org/springframework/context/event/EventPublicationInterceptorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,20 +46,20 @@ public class EventPublicationInterceptorTests { @Before public void setUp() { - publisher = mock(ApplicationEventPublisher.class); + this.publisher = mock(ApplicationEventPublisher.class); } @Test(expected=IllegalArgumentException.class) public void testWithNoApplicationEventClassSupplied() throws Exception { EventPublicationInterceptor interceptor = new EventPublicationInterceptor(); - interceptor.setApplicationEventPublisher(publisher); + interceptor.setApplicationEventPublisher(this.publisher); interceptor.afterPropertiesSet(); } @Test(expected=IllegalArgumentException.class) public void testWithNonApplicationEventClassSupplied() throws Exception { EventPublicationInterceptor interceptor = new EventPublicationInterceptor(); - interceptor.setApplicationEventPublisher(publisher); + interceptor.setApplicationEventPublisher(this.publisher); interceptor.setApplicationEventClass(getClass()); interceptor.afterPropertiesSet(); } @@ -67,7 +67,7 @@ public class EventPublicationInterceptorTests { @Test(expected=IllegalArgumentException.class) public void testWithAbstractStraightApplicationEventClassSupplied() throws Exception { EventPublicationInterceptor interceptor = new EventPublicationInterceptor(); - interceptor.setApplicationEventPublisher(publisher); + interceptor.setApplicationEventPublisher(this.publisher); interceptor.setApplicationEventClass(ApplicationEvent.class); interceptor.afterPropertiesSet(); } @@ -75,7 +75,7 @@ public class EventPublicationInterceptorTests { @Test(expected=IllegalArgumentException.class) public void testWithApplicationEventClassThatDoesntExposeAValidCtor() throws Exception { EventPublicationInterceptor interceptor = new EventPublicationInterceptor(); - interceptor.setApplicationEventPublisher(publisher); + interceptor.setApplicationEventPublisher(this.publisher); interceptor.setApplicationEventClass(TestEventWithNoValidOneArgObjectCtor.class); interceptor.afterPropertiesSet(); } diff --git a/spring-context/src/test/java/org/springframework/context/event/test/AbstractIdentifiable.java b/spring-context/src/test/java/org/springframework/context/event/test/AbstractIdentifiable.java index b960d8aa..3a61bc01 100644 --- a/spring-context/src/test/java/org/springframework/context/event/test/AbstractIdentifiable.java +++ b/spring-context/src/test/java/org/springframework/context/event/test/AbstractIdentifiable.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,7 @@ public abstract class AbstractIdentifiable implements Identifiable { @Override public String getId() { - return id; + return this.id; } @Override @@ -41,12 +41,12 @@ public abstract class AbstractIdentifiable implements Identifiable { AbstractIdentifiable that = (AbstractIdentifiable) o; - return id.equals(that.id); + return this.id.equals(that.id); } @Override public int hashCode() { - return id.hashCode(); + return this.id.hashCode(); } } diff --git a/spring-context/src/test/java/org/springframework/context/event/test/EventCollector.java b/spring-context/src/test/java/org/springframework/context/event/test/EventCollector.java index 78dddb96..9df254c2 100644 --- a/spring-context/src/test/java/org/springframework/context/event/test/EventCollector.java +++ b/spring-context/src/test/java/org/springframework/context/event/test/EventCollector.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,7 +56,7 @@ public class EventCollector { * Assert that the listener identified by the specified id has not received any event. */ public void assertNoEventReceived(String listenerId) { - List<Object> events = content.getOrDefault(listenerId, Collections.emptyList()); + List<Object> events = this.content.getOrDefault(listenerId, Collections.emptyList()); assertEquals("Expected no events but got " + events, 0, events.size()); } @@ -72,7 +72,7 @@ public class EventCollector { * specified events, in that specific order. */ public void assertEvent(String listenerId, Object... events) { - List<Object> actual = content.getOrDefault(listenerId, Collections.emptyList()); + List<Object> actual = this.content.getOrDefault(listenerId, Collections.emptyList()); assertEquals("wrong number of events", events.length, actual.size()); for (int i = 0; i < events.length; i++) { assertEquals("Wrong event at index " + i, events[i], actual.get(i)); diff --git a/spring-context/src/test/java/org/springframework/context/event/test/IdentifiableApplicationEvent.java b/spring-context/src/test/java/org/springframework/context/event/test/IdentifiableApplicationEvent.java index 8694c977..6e2df2dc 100644 --- a/spring-context/src/test/java/org/springframework/context/event/test/IdentifiableApplicationEvent.java +++ b/spring-context/src/test/java/org/springframework/context/event/test/IdentifiableApplicationEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,7 +45,7 @@ public abstract class IdentifiableApplicationEvent extends ApplicationEvent impl @Override public String getId() { - return id; + return this.id; } @Override @@ -55,13 +55,13 @@ public abstract class IdentifiableApplicationEvent extends ApplicationEvent impl IdentifiableApplicationEvent that = (IdentifiableApplicationEvent) o; - return id.equals(that.id); + return this.id.equals(that.id); } @Override public int hashCode() { - return id.hashCode(); + return this.id.hashCode(); } } diff --git a/spring-context/src/test/java/org/springframework/context/expression/FactoryBeanAccessTests.java b/spring-context/src/test/java/org/springframework/context/expression/FactoryBeanAccessTests.java new file mode 100644 index 00000000..e1e1ca3e --- /dev/null +++ b/spring-context/src/test/java/org/springframework/context/expression/FactoryBeanAccessTests.java @@ -0,0 +1,130 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.junit.Test; +import org.springframework.beans.factory.BeanIsNotAFactoryException; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.context.expression.FactoryBeanAccessTests.SimpleBeanResolver.Boat; +import org.springframework.context.expression.FactoryBeanAccessTests.SimpleBeanResolver.CarFactoryBean; +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.Expression; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; + +import static org.junit.Assert.*; + +/** + * Unit tests for expressions accessing beans and factory beans. + * + * @author Andy Clement + */ +public class FactoryBeanAccessTests { + + @Test + public void factoryBeanAccess() { // SPR9511 + StandardEvaluationContext context = new StandardEvaluationContext(); + context.setBeanResolver(new SimpleBeanResolver()); + Expression expr = new SpelExpressionParser().parseRaw("@car.colour"); + assertEquals("red", expr.getValue(context)); + expr = new SpelExpressionParser().parseRaw("&car.class.name"); + assertEquals(CarFactoryBean.class.getName(), expr.getValue(context)); + + expr = new SpelExpressionParser().parseRaw("@boat.colour"); + assertEquals("blue",expr.getValue(context)); + expr = new SpelExpressionParser().parseRaw("&boat.class.name"); + try { + assertEquals(Boat.class.getName(), expr.getValue(context)); + fail("Expected BeanIsNotAFactoryException"); + } + catch (BeanIsNotAFactoryException binafe) { + // success + } + + // No such bean + try { + expr = new SpelExpressionParser().parseRaw("@truck"); + assertEquals("red", expr.getValue(context)); + fail("Expected NoSuchBeanDefinitionException"); + } + catch (NoSuchBeanDefinitionException nsbde) { + // success + } + + // No such factory bean + try { + expr = new SpelExpressionParser().parseRaw("&truck"); + assertEquals(CarFactoryBean.class.getName(), expr.getValue(context)); + fail("Expected NoSuchBeanDefinitionException"); + } + catch (NoSuchBeanDefinitionException nsbde) { + // success + } + } + + static class SimpleBeanResolver + implements org.springframework.expression.BeanResolver { + + static class Car { + + public String getColour() { + return "red"; + } + } + + static class CarFactoryBean implements FactoryBean<Car> { + + public Car getObject() { + return new Car(); + } + + public Class<Car> getObjectType() { + return Car.class; + } + + public boolean isSingleton() { + return false; + } + + } + + static class Boat { + + public String getColour() { + return "blue"; + } + + } + + StaticApplicationContext ac = new StaticApplicationContext(); + + public SimpleBeanResolver() { + ac.registerSingleton("car", CarFactoryBean.class); + ac.registerSingleton("boat", Boat.class); + } + + @Override + public Object resolve(EvaluationContext context, String beanName) + throws AccessException { + return ac.getBean(beanName); + } + } + +}
\ No newline at end of file diff --git a/spring-context/src/test/java/org/springframework/context/expression/MapAccessorTests.java b/spring-context/src/test/java/org/springframework/context/expression/MapAccessorTests.java index db50071c..41646319 100644 --- a/spring-context/src/test/java/org/springframework/context/expression/MapAccessorTests.java +++ b/spring-context/src/test/java/org/springframework/context/expression/MapAccessorTests.java @@ -37,50 +37,50 @@ public class MapAccessorTests { @Test public void mapAccessorCompilable() { Map<String, Object> testMap = getSimpleTestMap(); - StandardEvaluationContext sec = new StandardEvaluationContext(); + StandardEvaluationContext sec = new StandardEvaluationContext(); sec.addPropertyAccessor(new MapAccessor()); SpelExpressionParser sep = new SpelExpressionParser(); - + // basic Expression ex = sep.parseExpression("foo"); assertEquals("bar",ex.getValue(sec,testMap)); - assertTrue(SpelCompiler.compile(ex)); + assertTrue(SpelCompiler.compile(ex)); assertEquals("bar",ex.getValue(sec,testMap)); // compound expression ex = sep.parseExpression("foo.toUpperCase()"); assertEquals("BAR",ex.getValue(sec,testMap)); - assertTrue(SpelCompiler.compile(ex)); + assertTrue(SpelCompiler.compile(ex)); assertEquals("BAR",ex.getValue(sec,testMap)); - + // nested map Map<String,Map<String,Object>> nestedMap = getNestedTestMap(); ex = sep.parseExpression("aaa.foo.toUpperCase()"); assertEquals("BAR",ex.getValue(sec,nestedMap)); - assertTrue(SpelCompiler.compile(ex)); + assertTrue(SpelCompiler.compile(ex)); assertEquals("BAR",ex.getValue(sec,nestedMap)); - + // avoiding inserting checkcast because first part of expression returns a Map ex = sep.parseExpression("getMap().foo"); MapGetter mapGetter = new MapGetter(); assertEquals("bar",ex.getValue(sec,mapGetter)); - assertTrue(SpelCompiler.compile(ex)); + assertTrue(SpelCompiler.compile(ex)); assertEquals("bar",ex.getValue(sec,mapGetter)); } - + public static class MapGetter { Map<String,Object> map = new HashMap<String,Object>(); public MapGetter() { map.put("foo", "bar"); } - + @SuppressWarnings("rawtypes") public Map getMap() { return map; } } - + public Map<String,Object> getSimpleTestMap() { Map<String,Object> map = new HashMap<String,Object>(); map.put("foo","bar"); diff --git a/spring-context/src/test/java/org/springframework/context/expression/MethodBasedEvaluationContextTests.java b/spring-context/src/test/java/org/springframework/context/expression/MethodBasedEvaluationContextTests.java index 4c156989..2711b006 100644 --- a/spring-context/src/test/java/org/springframework/context/expression/MethodBasedEvaluationContextTests.java +++ b/spring-context/src/test/java/org/springframework/context/expression/MethodBasedEvaluationContextTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ import static org.junit.Assert.*; * Unit tests for {@link MethodBasedEvaluationContext}. * * @author Stephane Nicoll + * @author Sergey Podgurskiy */ public class MethodBasedEvaluationContextTests { @@ -62,6 +63,43 @@ public class MethodBasedEvaluationContextTests { assertNull(context.lookupVariable("p0")); } + @Test + public void varArgEmpty() { + Method method = ReflectionUtils.findMethod(SampleMethods.class, "hello", Boolean.class, String[].class); + MethodBasedEvaluationContext context = createEvaluationContext(method, new Object[] {null}); + + assertNull(context.lookupVariable("p0")); + assertNull(context.lookupVariable("p1")); + } + + @Test + public void varArgNull() { + Method method = ReflectionUtils.findMethod(SampleMethods.class, "hello", Boolean.class, String[].class); + MethodBasedEvaluationContext context = createEvaluationContext(method, new Object[] {null, null}); + + assertNull(context.lookupVariable("p0")); + assertNull(context.lookupVariable("p1")); + } + + @Test + public void varArgSingle() { + Method method = ReflectionUtils.findMethod(SampleMethods.class, "hello", Boolean.class, String[].class); + MethodBasedEvaluationContext context = createEvaluationContext(method, new Object[] {null, "hello"}); + + assertNull(context.lookupVariable("p0")); + assertEquals("hello", context.lookupVariable("p1")); + } + + @Test + public void varArgMultiple() { + Method method = ReflectionUtils.findMethod(SampleMethods.class, "hello", Boolean.class, String[].class); + MethodBasedEvaluationContext context = createEvaluationContext(method, + new Object[] {null, new String[]{"hello", "hi"}}); + + assertNull(context.lookupVariable("p0")); + assertArrayEquals(new String[]{"hello", "hi"}, (String[]) context.lookupVariable("p1")); + } + private MethodBasedEvaluationContext createEvaluationContext(Method method, Object[] args) { return new MethodBasedEvaluationContext(this, method, args, this.paramDiscover); } @@ -73,6 +111,10 @@ public class MethodBasedEvaluationContextTests { private void hello(String foo, Boolean flag) { } + private void hello(Boolean flag, String... vararg){ + + } + } }
\ No newline at end of file diff --git a/spring-context/src/test/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurerTests.java b/spring-context/src/test/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurerTests.java index e11ae476..03044630 100644 --- a/spring-context/src/test/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurerTests.java +++ b/spring-context/src/test/java/org/springframework/context/support/PropertySourcesPlaceholderConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.context.support; +import java.util.Optional; import java.util.Properties; import org.junit.Rule; @@ -24,6 +25,7 @@ import org.junit.rules.ExpectedException; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.PropertySource; import org.springframework.core.env.StandardEnvironment; @@ -39,6 +41,7 @@ import static org.springframework.beans.factory.support.BeanDefinitionBuilder.*; /** * @author Chris Beams + * @author Juergen Hoeller * @since 3.1 */ public class PropertySourcesPlaceholderConfigurerTests { @@ -46,6 +49,7 @@ public class PropertySourcesPlaceholderConfigurerTests { @Rule public ExpectedException thrown = ExpectedException.none(); + @Test public void replacementFromEnvironmentProperties() { DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); @@ -57,8 +61,7 @@ public class PropertySourcesPlaceholderConfigurerTests { MockEnvironment env = new MockEnvironment(); env.setProperty("my.name", "myValue"); - PropertySourcesPlaceholderConfigurer ppc = - new PropertySourcesPlaceholderConfigurer(); + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); ppc.setEnvironment(env); ppc.postProcessBeanFactory(bf); assertThat(bf.getBean(TestBean.class).getName(), equalTo("myValue")); @@ -73,10 +76,10 @@ public class PropertySourcesPlaceholderConfigurerTests { .addPropertyValue("name", "${my.name}") .getBeanDefinition()); - PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer(); + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); Resource resource = new ClassPathResource("PropertySourcesPlaceholderConfigurerTests.properties", this.getClass()); - pc.setLocation(resource); - pc.postProcessBeanFactory(bf); + ppc.setLocation(resource); + ppc.postProcessBeanFactory(bf); assertThat(bf.getBean(TestBean.class).getName(), equalTo("foo")); } @@ -101,11 +104,11 @@ public class PropertySourcesPlaceholderConfigurerTests { MutablePropertySources propertySources = new MutablePropertySources(); propertySources.addLast(new MockPropertySource().withProperty("my.name", "foo")); - PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer(); - pc.setPropertySources(propertySources); - pc.postProcessBeanFactory(bf); + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); + ppc.setPropertySources(propertySources); + ppc.postProcessBeanFactory(bf); assertThat(bf.getBean(TestBean.class).getName(), equalTo("foo")); - assertEquals(pc.getAppliedPropertySources().iterator().next(), propertySources.iterator().next()); + assertEquals(ppc.getAppliedPropertySources().iterator().next(), propertySources.iterator().next()); } @Test @@ -119,13 +122,13 @@ public class PropertySourcesPlaceholderConfigurerTests { MutablePropertySources propertySources = new MutablePropertySources(); propertySources.addLast(new MockPropertySource()); - PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer(); - pc.setPropertySources(propertySources); - pc.setEnvironment(new MockEnvironment().withProperty("my.name", "env")); - pc.setIgnoreUnresolvablePlaceholders(true); - pc.postProcessBeanFactory(bf); + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); + ppc.setPropertySources(propertySources); + ppc.setEnvironment(new MockEnvironment().withProperty("my.name", "env")); + ppc.setIgnoreUnresolvablePlaceholders(true); + ppc.postProcessBeanFactory(bf); assertThat(bf.getBean(TestBean.class).getName(), equalTo("${my.name}")); - assertEquals(pc.getAppliedPropertySources().iterator().next(), propertySources.iterator().next()); + assertEquals(ppc.getAppliedPropertySources().iterator().next(), propertySources.iterator().next()); } @Test @@ -140,17 +143,17 @@ public class PropertySourcesPlaceholderConfigurerTests { MutablePropertySources propertySources = new MutablePropertySources(); propertySources.addLast(new MockPropertySource()); - PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer(); - pc.setPropertySources(propertySources); - pc.setProperties(new Properties() {{ + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); + ppc.setPropertySources(propertySources); + ppc.setProperties(new Properties() {{ put("my.name", "local"); }}); - pc.setIgnoreUnresolvablePlaceholders(true); - pc.postProcessBeanFactory(bf); + ppc.setIgnoreUnresolvablePlaceholders(true); + ppc.postProcessBeanFactory(bf); assertThat(bf.getBean(TestBean.class).getName(), equalTo("${my.name}")); } - @Test(expected=BeanDefinitionStoreException.class) + @Test(expected = BeanDefinitionStoreException.class) public void ignoreUnresolvablePlaceholders_falseIsDefault() { DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); bf.registerBeanDefinition("testBean", @@ -158,9 +161,9 @@ public class PropertySourcesPlaceholderConfigurerTests { .addPropertyValue("name", "${my.name}") .getBeanDefinition()); - PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer(); + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); //pc.setIgnoreUnresolvablePlaceholders(false); // the default - pc.postProcessBeanFactory(bf); // should throw + ppc.postProcessBeanFactory(bf); // should throw } @Test @@ -171,13 +174,13 @@ public class PropertySourcesPlaceholderConfigurerTests { .addPropertyValue("name", "${my.name}") .getBeanDefinition()); - PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer(); - pc.setIgnoreUnresolvablePlaceholders(true); - pc.postProcessBeanFactory(bf); + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); + ppc.setIgnoreUnresolvablePlaceholders(true); + ppc.postProcessBeanFactory(bf); assertThat(bf.getBean(TestBean.class).getName(), equalTo("${my.name}")); } - @Test(expected=BeanDefinitionStoreException.class) + @Test(expected = BeanDefinitionStoreException.class) @SuppressWarnings("serial") public void nestedUnresolvablePlaceholder() { DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); @@ -186,11 +189,11 @@ public class PropertySourcesPlaceholderConfigurerTests { .addPropertyValue("name", "${my.name}") .getBeanDefinition()); - PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer(); - pc.setProperties(new Properties() {{ + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); + ppc.setProperties(new Properties() {{ put("my.name", "${bogus}"); }}); - pc.postProcessBeanFactory(bf); // should throw + ppc.postProcessBeanFactory(bf); // should throw } @Test @@ -202,12 +205,12 @@ public class PropertySourcesPlaceholderConfigurerTests { .addPropertyValue("name", "${my.name}") .getBeanDefinition()); - PropertySourcesPlaceholderConfigurer pc = new PropertySourcesPlaceholderConfigurer(); - pc.setProperties(new Properties() {{ + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); + ppc.setProperties(new Properties() {{ put("my.name", "${bogus}"); }}); - pc.setIgnoreUnresolvablePlaceholders(true); - pc.postProcessBeanFactory(bf); + ppc.setIgnoreUnresolvablePlaceholders(true); + ppc.postProcessBeanFactory(bf); assertThat(bf.getBean(TestBean.class).getName(), equalTo("${bogus}")); } @@ -296,6 +299,31 @@ public class PropertySourcesPlaceholderConfigurerTests { } @Test + public void trimValuesIsOffByDefault() { + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerBeanDefinition("testBean", rootBeanDefinition(TestBean.class) + .addPropertyValue("name", "${my.name}") + .getBeanDefinition()); + ppc.setEnvironment(new MockEnvironment().withProperty("my.name", " myValue ")); + ppc.postProcessBeanFactory(bf); + assertThat(bf.getBean(TestBean.class).getName(), equalTo(" myValue ")); + } + + @Test + public void trimValuesIsApplied() { + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); + ppc.setTrimValues(true); + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.registerBeanDefinition("testBean", rootBeanDefinition(TestBean.class) + .addPropertyValue("name", "${my.name}") + .getBeanDefinition()); + ppc.setEnvironment(new MockEnvironment().withProperty("my.name", " myValue ")); + ppc.postProcessBeanFactory(bf); + assertThat(bf.getBean(TestBean.class).getName(), equalTo("myValue")); + } + + @Test public void getAppliedPropertySourcesTooEarly() throws Exception { PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); thrown.expect(IllegalStateException.class); @@ -308,7 +336,7 @@ public class PropertySourcesPlaceholderConfigurerTests { PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); ClassPathResource doesNotHave = new ClassPathResource("test.properties", getClass()); ClassPathResource setToTrue = new ClassPathResource("placeholder.properties", getClass()); - ppc.setLocations(new Resource[] { doesNotHave, setToTrue }); + ppc.setLocations(doesNotHave, setToTrue); ppc.setIgnoreResourceNotFound(true); ppc.setIgnoreUnresolvablePlaceholders(true); DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); @@ -320,4 +348,57 @@ public class PropertySourcesPlaceholderConfigurerTests { assertThat(bf.getBean(TestBean.class).isJedi(), equalTo(true)); } + @Test + public void optionalPropertyWithValue() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.setConversionService(new DefaultConversionService()); + bf.registerBeanDefinition("testBean", + genericBeanDefinition(OptionalTestBean.class) + .addPropertyValue("name", "${my.name}") + .getBeanDefinition()); + + MockEnvironment env = new MockEnvironment(); + env.setProperty("my.name", "myValue"); + + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); + ppc.setEnvironment(env); + ppc.setIgnoreUnresolvablePlaceholders(true); + ppc.postProcessBeanFactory(bf); + assertThat(bf.getBean(OptionalTestBean.class).getName(), equalTo(Optional.of("myValue"))); + } + + @Test + public void optionalPropertyWithoutValue() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.setConversionService(new DefaultConversionService()); + bf.registerBeanDefinition("testBean", + genericBeanDefinition(OptionalTestBean.class) + .addPropertyValue("name", "${my.name}") + .getBeanDefinition()); + + MockEnvironment env = new MockEnvironment(); + env.setProperty("my.name", ""); + + PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer(); + ppc.setEnvironment(env); + ppc.setIgnoreUnresolvablePlaceholders(true); + ppc.setNullValue(""); + ppc.postProcessBeanFactory(bf); + assertThat(bf.getBean(OptionalTestBean.class).getName(), equalTo(Optional.empty())); + } + + + private static class OptionalTestBean { + + private Optional<String> name; + + public Optional<String> getName() { + return name; + } + + public void setName(Optional<String> name) { + this.name = name; + } + } + } diff --git a/spring-context/src/test/java/org/springframework/context/support/SerializableBeanFactoryMemoryLeakTests.java b/spring-context/src/test/java/org/springframework/context/support/SerializableBeanFactoryMemoryLeakTests.java index 527ca333..7e2c8b86 100644 --- a/spring-context/src/test/java/org/springframework/context/support/SerializableBeanFactoryMemoryLeakTests.java +++ b/spring-context/src/test/java/org/springframework/context/support/SerializableBeanFactoryMemoryLeakTests.java @@ -85,9 +85,11 @@ public class SerializableBeanFactoryMemoryLeakTests { ctx.refresh(); assertThat(serializableFactoryCount(), equalTo(1)); ctx.close(); - } catch (BeanCreationException ex) { + } + catch (BeanCreationException ex) { // ignore - this is expected on refresh() for failure case tests - } finally { + } + finally { assertThat(serializableFactoryCount(), equalTo(0)); } } diff --git a/spring-context/src/test/java/org/springframework/ejb/access/LocalStatelessSessionProxyFactoryBeanTests.java b/spring-context/src/test/java/org/springframework/ejb/access/LocalStatelessSessionProxyFactoryBeanTests.java index 9fbf0bbd..29b40fc1 100644 --- a/spring-context/src/test/java/org/springframework/ejb/access/LocalStatelessSessionProxyFactoryBeanTests.java +++ b/spring-context/src/test/java/org/springframework/ejb/access/LocalStatelessSessionProxyFactoryBeanTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -182,19 +182,19 @@ public class LocalStatelessSessionProxyFactoryBeanTests { } - public static interface MyHome extends EJBLocalHome { + public interface MyHome extends EJBLocalHome { MyBusinessMethods create() throws CreateException; } - public static interface MyBusinessMethods { + public interface MyBusinessMethods { int getValue(); } - public static interface MyEjb extends EJBLocalObject, MyBusinessMethods { + public interface MyEjb extends EJBLocalObject, MyBusinessMethods { } } diff --git a/spring-context/src/test/java/org/springframework/ejb/access/SimpleRemoteStatelessSessionProxyFactoryBeanTests.java b/spring-context/src/test/java/org/springframework/ejb/access/SimpleRemoteStatelessSessionProxyFactoryBeanTests.java index 8efc5b57..2d62ee73 100644 --- a/spring-context/src/test/java/org/springframework/ejb/access/SimpleRemoteStatelessSessionProxyFactoryBeanTests.java +++ b/spring-context/src/test/java/org/springframework/ejb/access/SimpleRemoteStatelessSessionProxyFactoryBeanTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -279,26 +279,25 @@ public class SimpleRemoteStatelessSessionProxyFactoryBeanTests extends SimpleRem } - protected static interface MyHome extends EJBHome { + protected interface MyHome extends EJBHome { MyBusinessMethods create() throws CreateException, RemoteException; } - protected static interface MyBusinessMethods { + protected interface MyBusinessMethods { int getValue() throws RemoteException; } - protected static interface MyLocalBusinessMethods { + protected interface MyLocalBusinessMethods { int getValue(); } - protected static interface MyEjb extends EJBObject, MyBusinessMethods { - + protected interface MyEjb extends EJBObject, MyBusinessMethods { } } diff --git a/spring-context/src/test/java/org/springframework/format/datetime/DateFormattingTests.java b/spring-context/src/test/java/org/springframework/format/datetime/DateFormattingTests.java index ffbd422e..0681d4ec 100644 --- a/spring-context/src/test/java/org/springframework/format/datetime/DateFormattingTests.java +++ b/spring-context/src/test/java/org/springframework/format/datetime/DateFormattingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -149,6 +149,14 @@ public class DateFormattingTests { } @Test + public void testBindDateTimeOverflow() { + MutablePropertyValues propertyValues = new MutablePropertyValues(); + propertyValues.add("dateAnnotatedPattern", "02/29/09 12:00 PM"); + binder.bind(propertyValues); + assertEquals(1, binder.getBindingResult().getErrorCount()); + } + + @Test public void testBindISODate() { MutablePropertyValues propertyValues = new MutablePropertyValues(); propertyValues.add("isoDate", "2009-10-31"); diff --git a/spring-context/src/test/java/org/springframework/format/datetime/joda/JodaTimeFormattingTests.java b/spring-context/src/test/java/org/springframework/format/datetime/joda/JodaTimeFormattingTests.java index 1e96b13c..b0de33ec 100644 --- a/spring-context/src/test/java/org/springframework/format/datetime/joda/JodaTimeFormattingTests.java +++ b/spring-context/src/test/java/org/springframework/format/datetime/joda/JodaTimeFormattingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -318,6 +318,14 @@ public class JodaTimeFormattingTests { } @Test + public void testBindDateTimeOverflow() { + MutablePropertyValues propertyValues = new MutablePropertyValues(); + propertyValues.add("dateTimeAnnotatedPattern", "02/29/09 12:00 PM"); + binder.bind(propertyValues); + assertEquals(1, binder.getBindingResult().getErrorCount()); + } + + @Test public void testBindDateTimeAnnotatedDefault() { MutablePropertyValues propertyValues = new MutablePropertyValues(); propertyValues.add("dateTimeAnnotatedDefault", new DateTime(2009, 10, 31, 12, 0, ISOChronology.getInstanceUTC())); diff --git a/spring-context/src/test/java/org/springframework/format/datetime/standard/DateTimeFormattingTests.java b/spring-context/src/test/java/org/springframework/format/datetime/standard/DateTimeFormattingTests.java index a60fbd69..3bc0efd3 100644 --- a/spring-context/src/test/java/org/springframework/format/datetime/standard/DateTimeFormattingTests.java +++ b/spring-context/src/test/java/org/springframework/format/datetime/standard/DateTimeFormattingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -124,7 +124,7 @@ public class DateTimeFormattingTests { @Test public void testBindLocalDateArray() { MutablePropertyValues propertyValues = new MutablePropertyValues(); - propertyValues.add("localDate", new String[]{"10/31/09"}); + propertyValues.add("localDate", new String[] {"10/31/09"}); binder.bind(propertyValues); assertEquals(0, binder.getBindingResult().getErrorCount()); } @@ -293,6 +293,14 @@ public class DateTimeFormattingTests { } @Test + public void testBindDateTimeOverflow() { + MutablePropertyValues propertyValues = new MutablePropertyValues(); + propertyValues.add("dateTimeAnnotatedPattern", "02/29/09 12:00 PM"); + binder.bind(propertyValues); + assertEquals(1, binder.getBindingResult().getErrorCount()); + } + + @Test public void testBindISODate() { MutablePropertyValues propertyValues = new MutablePropertyValues(); propertyValues.add("isoDate", "2009-10-31"); diff --git a/spring-context/src/test/java/org/springframework/format/support/FormattingConversionServiceTests.java b/spring-context/src/test/java/org/springframework/format/support/FormattingConversionServiceTests.java index a6f5779b..e7c034c3 100644 --- a/spring-context/src/test/java/org/springframework/format/support/FormattingConversionServiceTests.java +++ b/spring-context/src/test/java/org/springframework/format/support/FormattingConversionServiceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -218,7 +218,7 @@ public class FormattingConversionServiceTests { assertEquals(new LocalDate(2009, 11, 1), new LocalDate(dates.get(1))); assertEquals(new LocalDate(2009, 11, 2), new LocalDate(dates.get(2))); - Object model = BeanUtils.instantiate(modelClass); + Object model = modelClass.newInstance(); ConfigurablePropertyAccessor accessor = directFieldAccess ? PropertyAccessorFactory.forDirectFieldAccess(model) : PropertyAccessorFactory.forBeanPropertyAccess(model); accessor.setConversionService(formattingService); diff --git a/spring-context/src/test/java/org/springframework/jmx/access/MBeanClientInterceptorTests.java b/spring-context/src/test/java/org/springframework/jmx/access/MBeanClientInterceptorTests.java index b2f4569b..3f30e901 100644 --- a/spring-context/src/test/java/org/springframework/jmx/access/MBeanClientInterceptorTests.java +++ b/spring-context/src/test/java/org/springframework/jmx/access/MBeanClientInterceptorTests.java @@ -195,7 +195,8 @@ public class MBeanClientInterceptorTests extends AbstractMBeanServerTests { // now start the connector try { connector.start(); - } catch (BindException ex) { + } + catch (BindException ex) { System.out.println("Skipping remainder of JMX LazyConnectionToRemote test because binding to local port [" + port + "] failed: " + ex.getMessage()); return; @@ -205,13 +206,15 @@ public class MBeanClientInterceptorTests extends AbstractMBeanServerTests { try { assertEquals("Rob Harrop", bean.getName()); assertEquals(100, bean.getAge()); - } finally { + } + finally { connector.stop(); } try { bean.getName(); - } catch (JmxException ex) { + } + catch (JmxException ex) { // expected } @@ -222,7 +225,8 @@ public class MBeanClientInterceptorTests extends AbstractMBeanServerTests { try { assertEquals("Rob Harrop", bean.getName()); assertEquals(100, bean.getAge()); - } finally { + } + finally { connector.stop(); } } diff --git a/spring-context/src/test/java/org/springframework/jmx/access/RemoteMBeanClientInterceptorTests.java b/spring-context/src/test/java/org/springframework/jmx/access/RemoteMBeanClientInterceptorTests.java index 218fb8e9..dea449ec 100644 --- a/spring-context/src/test/java/org/springframework/jmx/access/RemoteMBeanClientInterceptorTests.java +++ b/spring-context/src/test/java/org/springframework/jmx/access/RemoteMBeanClientInterceptorTests.java @@ -65,7 +65,8 @@ public class RemoteMBeanClientInterceptorTests extends MBeanClientInterceptorTes this.connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(getServiceUrl(), null, getServer()); try { this.connectorServer.start(); - } catch (BindException ex) { + } + catch (BindException ex) { System.out.println("Skipping remote JMX tests because binding to local port [" + SERVICE_PORT + "] failed: " + ex.getMessage()); runTests = false; diff --git a/spring-context/src/test/java/org/springframework/jmx/export/NotificationListenerTests.java b/spring-context/src/test/java/org/springframework/jmx/export/NotificationListenerTests.java index 81dc5307..149e574c 100644 --- a/spring-context/src/test/java/org/springframework/jmx/export/NotificationListenerTests.java +++ b/spring-context/src/test/java/org/springframework/jmx/export/NotificationListenerTests.java @@ -172,7 +172,8 @@ public class NotificationListenerTests extends AbstractMBeanServerTests { if (notification instanceof AttributeChangeNotification) { AttributeChangeNotification changeNotification = (AttributeChangeNotification) notification; return "Name".equals(changeNotification.getAttributeName()); - } else { + } + else { return false; } } @@ -200,7 +201,8 @@ public class NotificationListenerTests extends AbstractMBeanServerTests { try { new NotificationListenerBean().afterPropertiesSet(); fail("Must have thrown an IllegalArgumentException (no NotificationListener supplied)"); - } catch (IllegalArgumentException expected) { + } + catch (IllegalArgumentException expected) { } } @@ -463,7 +465,8 @@ public class NotificationListenerTests extends AbstractMBeanServerTests { if (currentCount != null) { int count = currentCount.intValue() + 1; this.attributeCounts.put(attributeName, new Integer(count)); - } else { + } + else { this.attributeCounts.put(attributeName, new Integer(1)); } diff --git a/spring-context/src/test/java/org/springframework/jmx/export/annotation/AnnotationTestBean.java b/spring-context/src/test/java/org/springframework/jmx/export/annotation/AnnotationTestBean.java index 559b6449..92479607 100644 --- a/spring-context/src/test/java/org/springframework/jmx/export/annotation/AnnotationTestBean.java +++ b/spring-context/src/test/java/org/springframework/jmx/export/annotation/AnnotationTestBean.java @@ -28,7 +28,7 @@ import org.springframework.stereotype.Service; @ManagedResource(objectName = "bean:name=testBean4", description = "My Managed Bean", log = true, logFile = "jmx.log", currencyTimeLimit = 15, persistPolicy = "OnUpdate", persistPeriod = 200, persistLocation = "./foo", persistName = "bar.jmx") -@ManagedNotification(name="My Notification", notificationTypes={"type.foo", "type.bar"}) +@ManagedNotification(name = "My Notification", notificationTypes = { "type.foo", "type.bar" }) public class AnnotationTestBean implements IJmxTestBean { private String name; diff --git a/spring-context/src/test/java/org/springframework/jmx/export/annotation/AnotherAnnotationTestBeanImpl.java b/spring-context/src/test/java/org/springframework/jmx/export/annotation/AnotherAnnotationTestBeanImpl.java index 1acaefb0..8857bcc0 100644 --- a/spring-context/src/test/java/org/springframework/jmx/export/annotation/AnotherAnnotationTestBeanImpl.java +++ b/spring-context/src/test/java/org/springframework/jmx/export/annotation/AnotherAnnotationTestBeanImpl.java @@ -19,7 +19,7 @@ package org.springframework.jmx.export.annotation; /** * @author Stephane Nicoll */ -class AnotherAnnotationTestBeanImpl implements AnotherAnnotationTestBean { +public class AnotherAnnotationTestBeanImpl implements AnotherAnnotationTestBean { private String bar; diff --git a/spring-context/src/test/java/org/springframework/jmx/export/annotation/EnableMBeanExportConfigurationTests.java b/spring-context/src/test/java/org/springframework/jmx/export/annotation/EnableMBeanExportConfigurationTests.java index caad3982..90488829 100644 --- a/spring-context/src/test/java/org/springframework/jmx/export/annotation/EnableMBeanExportConfigurationTests.java +++ b/spring-context/src/test/java/org/springframework/jmx/export/annotation/EnableMBeanExportConfigurationTests.java @@ -19,7 +19,10 @@ package org.springframework.jmx.export.annotation; import javax.management.MBeanServer; import javax.management.ObjectName; +import org.junit.After; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -33,6 +36,7 @@ import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.ScopedProxyMode; import org.springframework.jmx.export.MBeanExporterTests; import org.springframework.jmx.export.TestDynamicMBean; +import org.springframework.jmx.export.metadata.InvalidMetadataException; import org.springframework.jmx.support.MBeanServerFactoryBean; import org.springframework.jmx.support.ObjectNameManager; import org.springframework.jmx.support.RegistrationPolicy; @@ -44,109 +48,109 @@ import static org.junit.Assert.*; * Tests for {@link EnableMBeanExport} and {@link MBeanExportConfiguration}. * * @author Phillip Webb + * @author Stephane Nicoll * @see AnnotationLazyInitMBeanTests */ public class EnableMBeanExportConfigurationTests { + @Rule + public final ExpectedException thrown = ExpectedException.none(); + + private AnnotationConfigApplicationContext ctx; + + @After + public void closeContext() { + if (this.ctx != null) { + this.ctx.close(); + } + } + @Test public void testLazyNaming() throws Exception { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext( - LazyNamingConfiguration.class); - try { - MBeanServer server = (MBeanServer) ctx.getBean("server"); - ObjectName oname = ObjectNameManager.getInstance("bean:name=testBean4"); - assertNotNull(server.getObjectInstance(oname)); - String name = (String) server.getAttribute(oname, "Name"); - assertEquals("Invalid name returned", "TEST", name); - } - finally { - ctx.close(); - } + load(LazyNamingConfiguration.class); + validateAnnotationTestBean(); + } + + private void load(Class<?>... config) { + this.ctx = new AnnotationConfigApplicationContext(config); } @Test public void testOnlyTargetClassIsExposed() throws Exception { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext( - ProxyConfiguration.class); - try { - MBeanServer server = (MBeanServer) ctx.getBean("server"); - ObjectName oname = ObjectNameManager.getInstance("bean:name=testBean4"); - assertNotNull(server.getObjectInstance(oname)); - assertEquals("TEST", server.getAttribute(oname, "Name")); - } - finally { - ctx.close(); - } + load(ProxyConfiguration.class); + validateAnnotationTestBean(); + } + + @Test + @SuppressWarnings("resource") + public void testPackagePrivateExtensionCantBeExposed() { + this.thrown.expect(InvalidMetadataException.class); + this.thrown.expectMessage(PackagePrivateTestBean.class.getName()); + this.thrown.expectMessage("must be public"); + new AnnotationConfigApplicationContext(PackagePrivateConfiguration.class); + } + + @Test + @SuppressWarnings("resource") + public void testPackagePrivateImplementationCantBeExposed() { + this.thrown.expect(InvalidMetadataException.class); + this.thrown.expectMessage(PackagePrivateAnnotationTestBean.class.getName()); + this.thrown.expectMessage("must be public"); + new AnnotationConfigApplicationContext(PackagePrivateInterfaceImplementationConfiguration.class); + } + + @Test + public void testPackagePrivateClassExtensionCanBeExposed() throws Exception { + load(PackagePrivateExtensionConfiguration.class); + validateAnnotationTestBean(); } @Test public void testPlaceholderBased() throws Exception { MockEnvironment env = new MockEnvironment(); env.setProperty("serverName", "server"); - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.setEnvironment(env); - ctx.register(PlaceholderBasedConfiguration.class); - ctx.refresh(); - try { - MBeanServer server = (MBeanServer) ctx.getBean("server"); - ObjectName oname = ObjectNameManager.getInstance("bean:name=testBean4"); - assertNotNull(server.getObjectInstance(oname)); - String name = (String) server.getAttribute(oname, "Name"); - assertEquals("Invalid name returned", "TEST", name); - } - finally { - ctx.close(); - } + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.setEnvironment(env); + context.register(PlaceholderBasedConfiguration.class); + context.refresh(); + this.ctx = context; + validateAnnotationTestBean(); } @Test public void testLazyAssembling() throws Exception { System.setProperty("domain", "bean"); - AnnotationConfigApplicationContext ctx = - new AnnotationConfigApplicationContext(LazyAssemblingConfiguration.class); + load(LazyAssemblingConfiguration.class); try { - MBeanServer server = (MBeanServer) ctx.getBean("server"); - - ObjectName oname = ObjectNameManager.getInstance("bean:name=testBean4"); - assertNotNull(server.getObjectInstance(oname)); - String name = (String) server.getAttribute(oname, "Name"); - assertEquals("Invalid name returned", "TEST", name); - - oname = ObjectNameManager.getInstance("bean:name=testBean5"); - assertNotNull(server.getObjectInstance(oname)); - name = (String) server.getAttribute(oname, "Name"); - assertEquals("Invalid name returned", "FACTORY", name); - - oname = ObjectNameManager.getInstance("spring:mbean=true"); - assertNotNull(server.getObjectInstance(oname)); - name = (String) server.getAttribute(oname, "Name"); - assertEquals("Invalid name returned", "Rob Harrop", name); - - oname = ObjectNameManager.getInstance("spring:mbean=another"); - assertNotNull(server.getObjectInstance(oname)); - name = (String) server.getAttribute(oname, "Name"); - assertEquals("Invalid name returned", "Juergen Hoeller", name); + MBeanServer server = (MBeanServer) this.ctx.getBean("server"); + + validateMBeanAttribute(server, "bean:name=testBean4", "TEST"); + validateMBeanAttribute(server, "bean:name=testBean5", "FACTORY"); + validateMBeanAttribute(server, "spring:mbean=true", "Rob Harrop"); + validateMBeanAttribute(server, "spring:mbean=another", "Juergen Hoeller"); } finally { System.clearProperty("domain"); - ctx.close(); } } @Test public void testComponentScan() throws Exception { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext( - ComponentScanConfiguration.class); - try { - MBeanServer server = (MBeanServer) ctx.getBean("server"); - ObjectName oname = ObjectNameManager.getInstance("bean:name=testBean4"); - assertNotNull(server.getObjectInstance(oname)); - String name = (String) server.getAttribute(oname, "Name"); - assertNull(name); - } - finally { - ctx.close(); - } + load(ComponentScanConfiguration.class); + MBeanServer server = (MBeanServer) this.ctx.getBean("server"); + validateMBeanAttribute(server, "bean:name=testBean4", null); + } + + private void validateAnnotationTestBean() throws Exception { + MBeanServer server = (MBeanServer) this.ctx.getBean("server"); + validateMBeanAttribute(server,"bean:name=testBean4", "TEST"); + } + + private void validateMBeanAttribute(MBeanServer server, String objectName, String expected) throws Exception { + ObjectName oname = ObjectNameManager.getInstance(objectName); + assertNotNull(server.getObjectInstance(oname)); + String name = (String) server.getAttribute(oname, "Name"); + assertEquals("Invalid name returned", expected, name); } @@ -271,4 +275,97 @@ public class EnableMBeanExportConfigurationTests { } } + @Configuration + @EnableMBeanExport(server = "server") + static class PackagePrivateConfiguration { + + @Bean + public MBeanServerFactoryBean server() throws Exception { + return new MBeanServerFactoryBean(); + } + + @Bean + public PackagePrivateTestBean testBean() { + return new PackagePrivateTestBean(); + } + } + + @ManagedResource(objectName = "bean:name=packagePrivate") + private static class PackagePrivateTestBean { + + private String name; + + @ManagedAttribute + public String getName() { + return this.name; + } + + @ManagedAttribute + public void setName(String name) { + this.name = name; + } + } + + + @Configuration + @EnableMBeanExport(server = "server") + static class PackagePrivateExtensionConfiguration { + + @Bean + public MBeanServerFactoryBean server() throws Exception { + return new MBeanServerFactoryBean(); + } + + @Bean + public PackagePrivateTestBeanExtension testBean() { + PackagePrivateTestBeanExtension bean = new PackagePrivateTestBeanExtension(); + bean.setName("TEST"); + return bean; + } + } + + private static class PackagePrivateTestBeanExtension extends AnnotationTestBean { + + } + + @Configuration + @EnableMBeanExport(server = "server") + static class PackagePrivateInterfaceImplementationConfiguration { + + @Bean + public MBeanServerFactoryBean server() throws Exception { + return new MBeanServerFactoryBean(); + } + + @Bean + public PackagePrivateAnnotationTestBean testBean() { + return new PackagePrivateAnnotationTestBean(); + } + } + + private static class PackagePrivateAnnotationTestBean implements AnotherAnnotationTestBean { + + private String bar; + + @Override + public void foo() { + + } + + @Override + public String getBar() { + return this.bar; + } + + @Override + public void setBar(String bar) { + this.bar = bar; + } + + @Override + public int getCacheEntries() { + return 0; + } + } + } diff --git a/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerMappedTests.java b/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerMappedTests.java index 21efe0ba..9b8ec774 100644 --- a/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerMappedTests.java +++ b/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerMappedTests.java @@ -47,7 +47,7 @@ public class MethodNameBasedMBeanInfoAssemblerMappedTests extends AbstractJmxAss public void testWithFallThrough() throws Exception { MethodNameBasedMBeanInfoAssembler assembler = getWithMapping("foobar", "add,myOperation,getName,setName,getAge"); - assembler.setManagedMethods(new String[]{"getNickName", "setNickName"}); + assembler.setManagedMethods("getNickName", "setNickName"); ModelMBeanInfo inf = assembler.getMBeanInfo(getBean(), getObjectName()); MBeanAttributeInfo attr = inf.getAttribute("NickName"); diff --git a/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerTests.java b/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerTests.java index 3b51e92b..dae9a8a3 100644 --- a/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerTests.java +++ b/spring-context/src/test/java/org/springframework/jmx/export/assembler/MethodNameBasedMBeanInfoAssemblerTests.java @@ -52,7 +52,7 @@ public class MethodNameBasedMBeanInfoAssemblerTests extends AbstractJmxAssembler @Override protected MBeanInfoAssembler getAssembler() { MethodNameBasedMBeanInfoAssembler assembler = new MethodNameBasedMBeanInfoAssembler(); - assembler.setManagedMethods(new String[] {"add", "myOperation", "getName", "setName", "getAge"}); + assembler.setManagedMethods("add", "myOperation", "getName", "setName", "getAge"); return assembler; } diff --git a/spring-context/src/test/java/org/springframework/jmx/support/ConnectorServerFactoryBeanTests.java b/spring-context/src/test/java/org/springframework/jmx/support/ConnectorServerFactoryBeanTests.java index d1b6758d..3fbbde43 100644 --- a/spring-context/src/test/java/org/springframework/jmx/support/ConnectorServerFactoryBeanTests.java +++ b/spring-context/src/test/java/org/springframework/jmx/support/ConnectorServerFactoryBeanTests.java @@ -68,7 +68,8 @@ public class ConnectorServerFactoryBeanTests extends AbstractMBeanServerTests { try { checkServerConnection(getServer()); - } finally { + } + finally { bean.destroy(); } } @@ -85,7 +86,8 @@ public class ConnectorServerFactoryBeanTests extends AbstractMBeanServerTests { try { checkServerConnection(getServer()); - } finally { + } + finally { bean.destroy(); } } @@ -103,7 +105,8 @@ public class ConnectorServerFactoryBeanTests extends AbstractMBeanServerTests { // Try to get the connector bean. ObjectInstance instance = getServer().getObjectInstance(ObjectName.getInstance(OBJECT_NAME)); assertNotNull("ObjectInstance should not be null", instance); - } finally { + } + finally { bean.destroy(); } } @@ -117,9 +120,11 @@ public class ConnectorServerFactoryBeanTests extends AbstractMBeanServerTests { // Try to get the connector bean. getServer().getObjectInstance(ObjectName.getInstance(OBJECT_NAME)); fail("Instance should not be found"); - } catch (InstanceNotFoundException ex) { + } + catch (InstanceNotFoundException ex) { // expected - } finally { + } + finally { bean.destroy(); } } diff --git a/spring-context/src/test/java/org/springframework/jmx/support/MBeanServerConnectionFactoryBeanTests.java b/spring-context/src/test/java/org/springframework/jmx/support/MBeanServerConnectionFactoryBeanTests.java index de4746c4..66058126 100644 --- a/spring-context/src/test/java/org/springframework/jmx/support/MBeanServerConnectionFactoryBeanTests.java +++ b/spring-context/src/test/java/org/springframework/jmx/support/MBeanServerConnectionFactoryBeanTests.java @@ -74,10 +74,12 @@ public class MBeanServerConnectionFactoryBeanTests extends AbstractMBeanServerTe // perform simple MBean count test assertEquals("MBean count should be the same", getServer().getMBeanCount(), connection.getMBeanCount()); - } finally { + } + finally { bean.destroy(); } - } finally { + } + finally { connectorServer.stop(); } } @@ -104,7 +106,8 @@ public class MBeanServerConnectionFactoryBeanTests extends AbstractMBeanServerTe connector = getConnectorServer(); connector.start(); assertEquals("Incorrect MBean count", getServer().getMBeanCount(), connection.getMBeanCount()); - } finally { + } + finally { bean.destroy(); if (connector != null) { connector.stop(); diff --git a/spring-context/src/test/java/org/springframework/jndi/JndiPropertySourceTests.java b/spring-context/src/test/java/org/springframework/jndi/JndiPropertySourceTests.java index a8a68cd0..cc8423dd 100644 --- a/spring-context/src/test/java/org/springframework/jndi/JndiPropertySourceTests.java +++ b/spring-context/src/test/java/org/springframework/jndi/JndiPropertySourceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ import static org.junit.Assert.*; * Unit tests for {@link JndiPropertySource}. * * @author Chris Beams + * @author Juergen Hoeller * @since 3.1 */ public class JndiPropertySourceTests { @@ -56,7 +57,7 @@ public class JndiPropertySourceTests { jndiLocator.setJndiTemplate(jndiTemplate); JndiPropertySource ps = new JndiPropertySource("jndiProperties", jndiLocator); - assertThat((String)ps.getProperty("p1"), equalTo("v1")); + assertThat(ps.getProperty("p1"), equalTo("v1")); } @Test @@ -75,7 +76,36 @@ public class JndiPropertySourceTests { jndiLocator.setJndiTemplate(jndiTemplate); JndiPropertySource ps = new JndiPropertySource("jndiProperties", jndiLocator); - assertThat((String)ps.getProperty("p1"), equalTo("v1")); + assertThat(ps.getProperty("p1"), equalTo("v1")); + } + + @Test + public void propertyWithDefaultClauseInResourceRefMode() { + JndiLocatorDelegate jndiLocator = new JndiLocatorDelegate() { + @Override + public Object lookup(String jndiName) throws NamingException { + throw new IllegalStateException("Should not get called"); + } + }; + jndiLocator.setResourceRef(true); + + JndiPropertySource ps = new JndiPropertySource("jndiProperties", jndiLocator); + assertThat(ps.getProperty("propertyKey:defaultValue"), nullValue()); + } + + @Test + public void propertyWithColonInNonResourceRefMode() { + JndiLocatorDelegate jndiLocator = new JndiLocatorDelegate() { + @Override + public Object lookup(String jndiName) throws NamingException { + assertEquals("my:key", jndiName); + return "my:value"; + } + }; + jndiLocator.setResourceRef(false); + + JndiPropertySource ps = new JndiPropertySource("jndiProperties", jndiLocator); + assertThat(ps.getProperty("my:key"), equalTo("my:value")); } } diff --git a/spring-context/src/test/java/org/springframework/remoting/rmi/RmiSupportTests.java b/spring-context/src/test/java/org/springframework/remoting/rmi/RmiSupportTests.java index 6debb825..a3aba60d 100644 --- a/spring-context/src/test/java/org/springframework/remoting/rmi/RmiSupportTests.java +++ b/spring-context/src/test/java/org/springframework/remoting/rmi/RmiSupportTests.java @@ -30,7 +30,6 @@ import java.rmi.UnknownHostException; import java.rmi.UnmarshalException; import org.aopalliance.intercept.MethodInvocation; - import org.junit.Test; import org.springframework.remoting.RemoteAccessException; @@ -342,7 +341,7 @@ public class RmiSupportTests { client.afterPropertiesSet(); fail("url isn't set, expected IllegalArgumentException"); } - catch(IllegalArgumentException e){ + catch (IllegalArgumentException ex){ // expected } } diff --git a/spring-context/src/test/java/org/springframework/scheduling/annotation/EnableAsyncTests.java b/spring-context/src/test/java/org/springframework/scheduling/annotation/EnableAsyncTests.java index ed7ea99f..5fa835f4 100644 --- a/spring-context/src/test/java/org/springframework/scheduling/annotation/EnableAsyncTests.java +++ b/spring-context/src/test/java/org/springframework/scheduling/annotation/EnableAsyncTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,19 +26,24 @@ import java.util.concurrent.Executor; import java.util.concurrent.Future; import org.junit.Test; +import org.mockito.Mockito; import org.springframework.aop.Advisor; import org.springframework.aop.framework.Advised; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.aop.support.AopUtils; import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.BeanNotOfRequiredTypeException; +import org.springframework.beans.factory.UnsatisfiedDependencyException; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.AdviceMode; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; import org.springframework.core.Ordered; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.stereotype.Component; import org.springframework.util.ReflectionUtils; import static org.hamcrest.CoreMatchers.anyOf; @@ -68,6 +73,48 @@ public class EnableAsyncTests { } @Test + public void proxyingOccursWithMockitoStub() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(AsyncConfigWithMockito.class, AsyncBeanUser.class); + ctx.refresh(); + + AsyncBeanUser asyncBeanUser = ctx.getBean(AsyncBeanUser.class); + AsyncBean asyncBean = asyncBeanUser.getAsyncBean(); + assertThat(AopUtils.isAopProxy(asyncBean), is(true)); + asyncBean.work(); + } + + @Test + public void properExceptionForExistingProxyDependencyMismatch() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(AsyncConfig.class, AsyncBeanWithInterface.class, AsyncBeanUser.class); + + try { + ctx.refresh(); + fail("Should have thrown UnsatisfiedDependencyException"); + } + catch (UnsatisfiedDependencyException ex) { + ex.printStackTrace(); + assertTrue(ex.getCause() instanceof BeanNotOfRequiredTypeException); + } + } + + @Test + public void properExceptionForResolvedProxyDependencyMismatch() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(AsyncConfig.class, AsyncBeanUser.class, AsyncBeanWithInterface.class); + + try { + ctx.refresh(); + fail("Should have thrown UnsatisfiedDependencyException"); + } + catch (UnsatisfiedDependencyException ex) { + ex.printStackTrace(); + assertTrue(ex.getCause() instanceof BeanNotOfRequiredTypeException); + } + } + + @Test public void withAsyncBeanWithExecutorQualifiedByName() throws ExecutionException, InterruptedException { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(AsyncWithExecutorQualifiedByNameConfig.class); @@ -107,7 +154,7 @@ public class EnableAsyncTests { @Test public void customAsyncAnnotationIsPropagated() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(CustomAsyncAnnotationConfig.class); + ctx.register(CustomAsyncAnnotationConfig.class, CustomAsyncBean.class); ctx.refresh(); Object bean = ctx.getBean(CustomAsyncBean.class); @@ -200,14 +247,31 @@ public class EnableAsyncTests { } - @Configuration - @EnableAsync(annotation = CustomAsync.class) - static class CustomAsyncAnnotationConfig { + @Component("asyncBean") + static class AsyncBeanWithInterface extends AsyncBean implements Runnable { - @Bean - public CustomAsyncBean asyncBean() { - return new CustomAsyncBean(); + @Override + public void run() { + } + } + + + static class AsyncBeanUser { + + private final AsyncBean asyncBean; + + public AsyncBeanUser(AsyncBean asyncBean) { + this.asyncBean = asyncBean; } + + public AsyncBean getAsyncBean() { + return asyncBean; + } + } + + + @EnableAsync(annotation = CustomAsync.class) + static class CustomAsyncAnnotationConfig { } @@ -260,6 +324,17 @@ public class EnableAsyncTests { @Configuration @EnableAsync + static class AsyncConfigWithMockito { + + @Bean @Lazy + public AsyncBean asyncBean() { + return Mockito.mock(AsyncBean.class); + } + } + + + @Configuration + @EnableAsync static class CustomExecutorAsyncConfig implements AsyncConfigurer { @Bean diff --git a/spring-context/src/test/java/org/springframework/scheduling/annotation/EnableSchedulingTests.java b/spring-context/src/test/java/org/springframework/scheduling/annotation/EnableSchedulingTests.java index 62399fbf..c3a46c6e 100644 --- a/spring-context/src/test/java/org/springframework/scheduling/annotation/EnableSchedulingTests.java +++ b/spring-context/src/test/java/org/springframework/scheduling/annotation/EnableSchedulingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,10 +19,8 @@ package org.springframework.scheduling.annotation; import java.util.Date; import java.util.concurrent.atomic.AtomicInteger; -import org.junit.Before; -import org.junit.Rule; +import org.junit.After; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; @@ -48,65 +46,151 @@ import static org.junit.Assert.*; */ public class EnableSchedulingTests { - @Rule - public final ExpectedException exception = ExpectedException.none(); + private AnnotationConfigApplicationContext ctx; - @Before - public void setUp() { - Assume.group(TestGroup.PERFORMANCE); + @After + public void tearDown() { + if (ctx != null) { + ctx.close(); + } } @Test public void withFixedRateTask() throws InterruptedException { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(FixedRateTaskConfig.class); + Assume.group(TestGroup.PERFORMANCE); + + ctx = new AnnotationConfigApplicationContext(FixedRateTaskConfig.class); Thread.sleep(100); assertThat(ctx.getBean(AtomicInteger.class).get(), greaterThanOrEqualTo(10)); - ctx.close(); } + @Test + public void withSubclass() throws InterruptedException { + Assume.group(TestGroup.PERFORMANCE); - @Configuration - @EnableScheduling - static class FixedRateTaskConfig { + ctx = new AnnotationConfigApplicationContext(FixedRateTaskConfigSubclass.class); - @Bean - public AtomicInteger counter() { - return new AtomicInteger(); - } + Thread.sleep(100); + assertThat(ctx.getBean(AtomicInteger.class).get(), greaterThanOrEqualTo(10)); + } - @Scheduled(fixedRate = 10) - public void task() { - counter().incrementAndGet(); - } + @Test + public void withExplicitScheduler() throws InterruptedException { + Assume.group(TestGroup.PERFORMANCE); + + ctx = new AnnotationConfigApplicationContext(ExplicitSchedulerConfig.class); + + Thread.sleep(100); + assertThat(ctx.getBean(AtomicInteger.class).get(), greaterThanOrEqualTo(10)); + assertThat(ctx.getBean(ExplicitSchedulerConfig.class).threadName, startsWith("explicitScheduler-")); } + @Test + public void withExplicitSchedulerAmbiguity_andSchedulingEnabled() { + // No exception raised as of 4.3, aligned with the behavior for @Async methods (SPR-14030) + ctx = new AnnotationConfigApplicationContext(AmbiguousExplicitSchedulerConfig.class); + } @Test - public void withSubclass() throws InterruptedException { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(FixedRateTaskConfigSubclass.class); + public void withExplicitScheduledTaskRegistrar() throws InterruptedException { + Assume.group(TestGroup.PERFORMANCE); + + ctx = new AnnotationConfigApplicationContext(ExplicitScheduledTaskRegistrarConfig.class); Thread.sleep(100); assertThat(ctx.getBean(AtomicInteger.class).get(), greaterThanOrEqualTo(10)); - ctx.close(); + assertThat(ctx.getBean(ExplicitScheduledTaskRegistrarConfig.class).threadName, startsWith("explicitScheduler1")); } + @Test + public void withAmbiguousTaskSchedulers_butNoActualTasks() { + ctx = new AnnotationConfigApplicationContext(SchedulingEnabled_withAmbiguousTaskSchedulers_butNoActualTasks.class); + } - @Configuration - static class FixedRateTaskConfigSubclass extends FixedRateTaskConfig { + @Test + public void withAmbiguousTaskSchedulers_andSingleTask() { + // No exception raised as of 4.3, aligned with the behavior for @Async methods (SPR-14030) + ctx = new AnnotationConfigApplicationContext(SchedulingEnabled_withAmbiguousTaskSchedulers_andSingleTask.class); + } + + @Test + public void withAmbiguousTaskSchedulers_andSingleTask_disambiguatedByScheduledTaskRegistrarBean() throws InterruptedException { + Assume.group(TestGroup.PERFORMANCE); + + ctx = new AnnotationConfigApplicationContext( + SchedulingEnabled_withAmbiguousTaskSchedulers_andSingleTask_disambiguatedByScheduledTaskRegistrar.class); + + Thread.sleep(100); + assertThat(ctx.getBean(ThreadAwareWorker.class).executedByThread, startsWith("explicitScheduler2-")); } + @Test + public void withAmbiguousTaskSchedulers_andSingleTask_disambiguatedBySchedulerNameAttribute() throws InterruptedException { + Assume.group(TestGroup.PERFORMANCE); + + ctx = new AnnotationConfigApplicationContext( + SchedulingEnabled_withAmbiguousTaskSchedulers_andSingleTask_disambiguatedBySchedulerNameAttribute.class); + + Thread.sleep(100); + assertThat(ctx.getBean(ThreadAwareWorker.class).executedByThread, startsWith("explicitScheduler2-")); + } @Test - public void withExplicitScheduler() throws InterruptedException { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ExplicitSchedulerConfig.class); + public void withTaskAddedVia_configureTasks() throws InterruptedException { + Assume.group(TestGroup.PERFORMANCE); + + ctx = new AnnotationConfigApplicationContext(SchedulingEnabled_withTaskAddedVia_configureTasks.class); Thread.sleep(100); - assertThat(ctx.getBean(AtomicInteger.class).get(), greaterThanOrEqualTo(10)); - assertThat(ctx.getBean(ExplicitSchedulerConfig.class).threadName, startsWith("explicitScheduler-")); - ctx.close(); + assertThat(ctx.getBean(ThreadAwareWorker.class).executedByThread, startsWith("taskScheduler-")); + } + + @Test + public void withTriggerTask() throws InterruptedException { + Assume.group(TestGroup.PERFORMANCE); + + ctx = new AnnotationConfigApplicationContext(TriggerTaskConfig.class); + + Thread.sleep(100); + assertThat(ctx.getBean(AtomicInteger.class).get(), greaterThan(1)); + } + + @Test + public void withInitiallyDelayedFixedRateTask() throws InterruptedException { + Assume.group(TestGroup.PERFORMANCE); + + ctx = new AnnotationConfigApplicationContext(FixedRateTaskConfig_withInitialDelay.class); + + Thread.sleep(1950); + AtomicInteger counter = ctx.getBean(AtomicInteger.class); + + // The @Scheduled method should have been called at least once but + // not more times than the delay allows. + assertThat(counter.get(), both(greaterThan(0)).and(lessThanOrEqualTo(10))); + } + + + @Configuration + @EnableScheduling + static class FixedRateTaskConfig { + + @Bean + public AtomicInteger counter() { + return new AtomicInteger(); + } + + @Scheduled(fixedRate = 10) + public void task() { + counter().incrementAndGet(); + } + } + + + @Configuration + static class FixedRateTaskConfigSubclass extends FixedRateTaskConfig { } @@ -136,15 +220,6 @@ public class EnableSchedulingTests { } - @Test - @SuppressWarnings("resource") - public void withExplicitSchedulerAmbiguity_andSchedulingEnabled() { - exception.expect(IllegalStateException.class); - exception.expectMessage(startsWith("More than one TaskScheduler bean exists within the context")); - new AnnotationConfigApplicationContext(AmbiguousExplicitSchedulerConfig.class); - } - - @Configuration @EnableScheduling static class AmbiguousExplicitSchedulerConfig { @@ -169,18 +244,6 @@ public class EnableSchedulingTests { } - @Test - public void withExplicitScheduledTaskRegistrar() throws InterruptedException { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext( - ExplicitScheduledTaskRegistrarConfig.class); - - Thread.sleep(100); - assertThat(ctx.getBean(AtomicInteger.class).get(), greaterThanOrEqualTo(10)); - assertThat(ctx.getBean(ExplicitScheduledTaskRegistrarConfig.class).threadName, startsWith("explicitScheduler1")); - ctx.close(); - } - - @Configuration @EnableScheduling static class ExplicitScheduledTaskRegistrarConfig implements SchedulingConfigurer { @@ -223,14 +286,6 @@ public class EnableSchedulingTests { } - @Test - public void withAmbiguousTaskSchedulers_butNoActualTasks() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext( - SchedulingEnabled_withAmbiguousTaskSchedulers_butNoActualTasks.class); - ctx.close(); - } - - @Configuration @EnableScheduling static class SchedulingEnabled_withAmbiguousTaskSchedulers_butNoActualTasks { @@ -251,15 +306,6 @@ public class EnableSchedulingTests { } - @Test - @SuppressWarnings("resource") - public void withAmbiguousTaskSchedulers_andSingleTask() { - exception.expect(IllegalStateException.class); - exception.expectMessage(startsWith("More than one TaskScheduler bean exists within the context")); - new AnnotationConfigApplicationContext(SchedulingEnabled_withAmbiguousTaskSchedulers_andSingleTask.class); - } - - @Configuration @EnableScheduling static class SchedulingEnabled_withAmbiguousTaskSchedulers_andSingleTask { @@ -284,17 +330,6 @@ public class EnableSchedulingTests { } - @Test - public void withAmbiguousTaskSchedulers_andSingleTask_disambiguatedByScheduledTaskRegistrarBean() throws InterruptedException { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext( - SchedulingEnabled_withAmbiguousTaskSchedulers_andSingleTask_disambiguatedByScheduledTaskRegistrar.class); - - Thread.sleep(20); - assertThat(ctx.getBean(ThreadAwareWorker.class).executedByThread, startsWith("explicitScheduler2-")); - ctx.close(); - } - - static class ThreadAwareWorker { String executedByThread; @@ -336,17 +371,6 @@ public class EnableSchedulingTests { } - @Test - public void withAmbiguousTaskSchedulers_andSingleTask_disambiguatedBySchedulerNameAttribute() throws InterruptedException { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext( - SchedulingEnabled_withAmbiguousTaskSchedulers_andSingleTask_disambiguatedBySchedulerNameAttribute.class); - - Thread.sleep(20); - assertThat(ctx.getBean(ThreadAwareWorker.class).executedByThread, startsWith("explicitScheduler2-")); - ctx.close(); - } - - @Configuration @EnableScheduling static class SchedulingEnabled_withAmbiguousTaskSchedulers_andSingleTask_disambiguatedBySchedulerNameAttribute implements SchedulingConfigurer { @@ -382,17 +406,6 @@ public class EnableSchedulingTests { } - @Test - public void withTaskAddedVia_configureTasks() throws InterruptedException { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext( - SchedulingEnabled_withTaskAddedVia_configureTasks.class); - - Thread.sleep(20); - assertThat(ctx.getBean(ThreadAwareWorker.class).executedByThread, startsWith("taskScheduler-")); - ctx.close(); - } - - @Configuration @EnableScheduling static class SchedulingEnabled_withTaskAddedVia_configureTasks implements SchedulingConfigurer { @@ -422,16 +435,6 @@ public class EnableSchedulingTests { } - @Test - public void withTriggerTask() throws InterruptedException { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(TriggerTaskConfig.class); - - Thread.sleep(100); - assertThat(ctx.getBean(AtomicInteger.class).get(), greaterThan(1)); - ctx.close(); - } - - @Configuration static class TriggerTaskConfig { @@ -462,21 +465,6 @@ public class EnableSchedulingTests { } - @Test - public void withInitiallyDelayedFixedRateTask() throws InterruptedException { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext( - FixedRateTaskConfig_withInitialDelay.class); - - Thread.sleep(1950); - AtomicInteger counter = ctx.getBean(AtomicInteger.class); - ctx.close(); - - // The @Scheduled method should have been called at least once but - // not more times than the delay allows. - assertThat(counter.get(), both(greaterThan(0)).and(lessThanOrEqualTo(10))); - } - - @Configuration @EnableScheduling static class FixedRateTaskConfig_withInitialDelay { diff --git a/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java b/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java index 0da2dddc..6f5a00b2 100644 --- a/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java +++ b/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,9 @@ import java.lang.annotation.Target; import java.lang.reflect.Method; import java.util.Calendar; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Properties; import java.util.TimeZone; @@ -37,6 +39,7 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.support.StaticApplicationContext; +import org.springframework.core.annotation.AliasFor; import org.springframework.scheduling.Trigger; import org.springframework.scheduling.TriggerContext; import org.springframework.scheduling.config.CronTask; @@ -331,6 +334,32 @@ public class ScheduledAnnotationBeanPostProcessorTests { } @Test + public void composedAnnotationWithInitialDelayAndFixedRate() { + BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class); + BeanDefinition targetDefinition = new RootBeanDefinition(ComposedAnnotationFixedRateTestBean.class); + context.registerBeanDefinition("postProcessor", processorDefinition); + context.registerBeanDefinition("target", targetDefinition); + context.refresh(); + + Object postProcessor = context.getBean("postProcessor"); + Object target = context.getBean("target"); + ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) new DirectFieldAccessor( + postProcessor).getPropertyValue("registrar"); + @SuppressWarnings("unchecked") + List<IntervalTask> fixedRateTasks = (List<IntervalTask>) new DirectFieldAccessor(registrar).getPropertyValue( + "fixedRateTasks"); + assertEquals(1, fixedRateTasks.size()); + IntervalTask task = fixedRateTasks.get(0); + ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable(); + Object targetObject = runnable.getTarget(); + Method targetMethod = runnable.getMethod(); + assertEquals(target, targetObject); + assertEquals("checkForUpdates", targetMethod.getName()); + assertEquals(5000L, task.getInterval()); + assertEquals(1000L, task.getInitialDelay()); + } + + @Test public void metaAnnotationWithCronExpression() { BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class); BeanDefinition targetDefinition = new RootBeanDefinition(MetaAnnotationCronTestBean.class); @@ -364,8 +393,8 @@ public class ScheduledAnnotationBeanPostProcessorTests { properties.setProperty("schedules.businessHours", businessHoursCronExpression); placeholderDefinition.getPropertyValues().addPropertyValue("properties", properties); BeanDefinition targetDefinition = new RootBeanDefinition(PropertyPlaceholderWithCronTestBean.class); - context.registerBeanDefinition("placeholder", placeholderDefinition); context.registerBeanDefinition("postProcessor", processorDefinition); + context.registerBeanDefinition("placeholder", placeholderDefinition); context.registerBeanDefinition("target", targetDefinition); context.refresh(); @@ -395,8 +424,8 @@ public class ScheduledAnnotationBeanPostProcessorTests { properties.setProperty("initialDelay", "1000"); placeholderDefinition.getPropertyValues().addPropertyValue("properties", properties); BeanDefinition targetDefinition = new RootBeanDefinition(PropertyPlaceholderWithFixedDelayTestBean.class); - context.registerBeanDefinition("placeholder", placeholderDefinition); context.registerBeanDefinition("postProcessor", processorDefinition); + context.registerBeanDefinition("placeholder", placeholderDefinition); context.registerBeanDefinition("target", targetDefinition); context.refresh(); @@ -427,8 +456,8 @@ public class ScheduledAnnotationBeanPostProcessorTests { properties.setProperty("initialDelay", "1000"); placeholderDefinition.getPropertyValues().addPropertyValue("properties", properties); BeanDefinition targetDefinition = new RootBeanDefinition(PropertyPlaceholderWithFixedRateTestBean.class); - context.registerBeanDefinition("placeholder", placeholderDefinition); context.registerBeanDefinition("postProcessor", processorDefinition); + context.registerBeanDefinition("placeholder", placeholderDefinition); context.registerBeanDefinition("target", targetDefinition); context.refresh(); @@ -451,6 +480,35 @@ public class ScheduledAnnotationBeanPostProcessorTests { } @Test + public void expressionWithCron() { + String businessHoursCronExpression = "0 0 9-17 * * MON-FRI"; + BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class); + BeanDefinition targetDefinition = new RootBeanDefinition(ExpressionWithCronTestBean.class); + context.registerBeanDefinition("postProcessor", processorDefinition); + context.registerBeanDefinition("target", targetDefinition); + Map<String, String> schedules = new HashMap<String, String>(); + schedules.put("businessHours", businessHoursCronExpression); + context.getBeanFactory().registerSingleton("schedules", schedules); + context.refresh(); + + Object postProcessor = context.getBean("postProcessor"); + Object target = context.getBean("target"); + ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) + new DirectFieldAccessor(postProcessor).getPropertyValue("registrar"); + @SuppressWarnings("unchecked") + List<CronTask> cronTasks = (List<CronTask>) + new DirectFieldAccessor(registrar).getPropertyValue("cronTasks"); + assertEquals(1, cronTasks.size()); + CronTask task = cronTasks.get(0); + ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable(); + Object targetObject = runnable.getTarget(); + Method targetMethod = runnable.getMethod(); + assertEquals(target, targetObject); + assertEquals("x", targetMethod.getName()); + assertEquals(businessHoursCronExpression, task.getExpression()); + } + + @Test public void propertyPlaceholderForMetaAnnotation() { String businessHoursCronExpression = "0 0 9-17 * * MON-FRI"; BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class); @@ -481,28 +539,44 @@ public class ScheduledAnnotationBeanPostProcessorTests { assertEquals(businessHoursCronExpression, task.getExpression()); } - @Test(expected = BeanCreationException.class) - public void emptyAnnotation() { + @Test + public void nonVoidReturnType() { BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class); - BeanDefinition targetDefinition = new RootBeanDefinition(EmptyAnnotationTestBean.class); + BeanDefinition targetDefinition = new RootBeanDefinition(NonVoidReturnTypeTestBean.class); context.registerBeanDefinition("postProcessor", processorDefinition); context.registerBeanDefinition("target", targetDefinition); context.refresh(); + + Object postProcessor = context.getBean("postProcessor"); + Object target = context.getBean("target"); + ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar) + new DirectFieldAccessor(postProcessor).getPropertyValue("registrar"); + @SuppressWarnings("unchecked") + List<CronTask> cronTasks = (List<CronTask>) + new DirectFieldAccessor(registrar).getPropertyValue("cronTasks"); + assertEquals(1, cronTasks.size()); + CronTask task = cronTasks.get(0); + ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable(); + Object targetObject = runnable.getTarget(); + Method targetMethod = runnable.getMethod(); + assertEquals(target, targetObject); + assertEquals("cron", targetMethod.getName()); + assertEquals("0 0 9-17 * * MON-FRI", task.getExpression()); } @Test(expected = BeanCreationException.class) - public void invalidCron() throws Throwable { + public void emptyAnnotation() { BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class); - BeanDefinition targetDefinition = new RootBeanDefinition(InvalidCronTestBean.class); + BeanDefinition targetDefinition = new RootBeanDefinition(EmptyAnnotationTestBean.class); context.registerBeanDefinition("postProcessor", processorDefinition); context.registerBeanDefinition("target", targetDefinition); context.refresh(); } @Test(expected = BeanCreationException.class) - public void nonVoidReturnType() { + public void invalidCron() throws Throwable { BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class); - BeanDefinition targetDefinition = new RootBeanDefinition(NonVoidReturnTypeTestBean.class); + BeanDefinition targetDefinition = new RootBeanDefinition(InvalidCronTestBean.class); context.registerBeanDefinition("postProcessor", processorDefinition); context.registerBeanDefinition("target", targetDefinition); context.refresh(); @@ -520,7 +594,7 @@ public class ScheduledAnnotationBeanPostProcessorTests { static class FixedDelayTestBean { - @Scheduled(fixedDelay=5000) + @Scheduled(fixedDelay = 5000) public void fixedDelay() { } } @@ -528,7 +602,7 @@ public class ScheduledAnnotationBeanPostProcessorTests { static class FixedRateTestBean { - @Scheduled(fixedRate=3000) + @Scheduled(fixedRate = 3000) public void fixedRate() { } } @@ -536,7 +610,7 @@ public class ScheduledAnnotationBeanPostProcessorTests { static class FixedRateWithInitialDelayTestBean { - @Scheduled(fixedRate=3000, initialDelay=1000) + @Scheduled(fixedRate = 3000, initialDelay = 1000) public void fixedRate() { } } @@ -553,8 +627,8 @@ public class ScheduledAnnotationBeanPostProcessorTests { static class SeveralFixedRatesWithRepeatedScheduledAnnotationTestBean { - @Scheduled(fixedRate=4000) - @Scheduled(fixedRate=4000, initialDelay=2000) + @Scheduled(fixedRate = 4000) + @Scheduled(fixedRate = 4000, initialDelay = 2000) public void fixedRate() { } } @@ -562,8 +636,8 @@ public class ScheduledAnnotationBeanPostProcessorTests { static class FixedRatesBaseBean { - @Scheduled(fixedRate=4000) - @Scheduled(fixedRate=4000, initialDelay=2000) + @Scheduled(fixedRate = 4000) + @Scheduled(fixedRate = 4000, initialDelay = 2000) public void fixedRate() { } } @@ -573,10 +647,10 @@ public class ScheduledAnnotationBeanPostProcessorTests { } - static interface FixedRatesDefaultMethod { + interface FixedRatesDefaultMethod { - @Scheduled(fixedRate=4000) - @Scheduled(fixedRate=4000, initialDelay=2000) + @Scheduled(fixedRate = 4000) + @Scheduled(fixedRate = 4000, initialDelay = 2000) default void fixedRate() { } } @@ -589,7 +663,7 @@ public class ScheduledAnnotationBeanPostProcessorTests { @Validated static class CronTestBean { - @Scheduled(cron="*/7 * * * * ?") + @Scheduled(cron = "*/7 * * * * ?") private void cron() throws IOException { throw new IOException("no no no"); } @@ -598,7 +672,7 @@ public class ScheduledAnnotationBeanPostProcessorTests { static class CronWithTimezoneTestBean { - @Scheduled(cron="0 0 0-4,6-23 * * ?", zone = "GMT+10") + @Scheduled(cron = "0 0 0-4,6-23 * * ?", zone = "GMT+10") protected void cron() throws IOException { throw new IOException("no no no"); } @@ -607,56 +681,68 @@ public class ScheduledAnnotationBeanPostProcessorTests { static class CronWithInvalidTimezoneTestBean { - @Scheduled(cron="0 0 0-4,6-23 * * ?", zone = "FOO") + @Scheduled(cron = "0 0 0-4,6-23 * * ?", zone = "FOO") public void cron() throws IOException { throw new IOException("no no no"); } } - static class EmptyAnnotationTestBean { + static class NonVoidReturnTypeTestBean { - @Scheduled - public void invalid() { + @Scheduled(cron = "0 0 9-17 * * MON-FRI") + public String cron() { + return "oops"; } } - static class InvalidCronTestBean { + static class EmptyAnnotationTestBean { - @Scheduled(cron="abc") + @Scheduled public void invalid() { } } - static class NonVoidReturnTypeTestBean { + static class InvalidCronTestBean { - @Scheduled(fixedRate=3000) - public String invalid() { - return "oops"; + @Scheduled(cron = "abc") + public void invalid() { } } static class NonEmptyParamListTestBean { - @Scheduled(fixedRate=3000) + @Scheduled(fixedRate = 3000) public void invalid(String oops) { } } - @Scheduled(fixedRate=5000) + @Scheduled(fixedRate = 5000) @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) - private static @interface EveryFiveSeconds {} - + private @interface EveryFiveSeconds { + } - @Scheduled(cron="0 0 * * * ?") + @Scheduled(cron = "0 0 * * * ?") @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) - private static @interface Hourly {} + private @interface Hourly { + } + + @Scheduled(initialDelay = 1000) + @Retention(RetentionPolicy.RUNTIME) + private @interface WaitASec { + + @AliasFor(annotation = Scheduled.class) + long fixedDelay() default -1; + + @AliasFor(annotation = Scheduled.class) + long fixedRate() default -1; + } static class MetaAnnotationFixedRateTestBean { @@ -667,6 +753,14 @@ public class ScheduledAnnotationBeanPostProcessorTests { } + static class ComposedAnnotationFixedRateTestBean { + + @WaitASec(fixedRate = 5000) + public void checkForUpdates() { + } + } + + static class MetaAnnotationCronTestBean { @Hourly @@ -674,7 +768,6 @@ public class ScheduledAnnotationBeanPostProcessorTests { } } - static class PropertyPlaceholderWithCronTestBean { @Scheduled(cron = "${schedules.businessHours}") @@ -685,7 +778,7 @@ public class ScheduledAnnotationBeanPostProcessorTests { static class PropertyPlaceholderWithFixedDelayTestBean { - @Scheduled(fixedDelayString="${fixedDelay}", initialDelayString="${initialDelay}") + @Scheduled(fixedDelayString = "${fixedDelay}", initialDelayString = "${initialDelay}") public void fixedDelay() { } } @@ -693,16 +786,24 @@ public class ScheduledAnnotationBeanPostProcessorTests { static class PropertyPlaceholderWithFixedRateTestBean { - @Scheduled(fixedRateString="${fixedRate}", initialDelayString="${initialDelay}") + @Scheduled(fixedRateString = "${fixedRate}", initialDelayString = "${initialDelay}") public void fixedRate() { } } - @Scheduled(cron="${schedules.businessHours}") + static class ExpressionWithCronTestBean { + + @Scheduled(cron = "#{schedules.businessHours}") + public void x() { + } + } + + + @Scheduled(cron = "${schedules.businessHours}") @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) - private static @interface BusinessHours { + private @interface BusinessHours { } diff --git a/spring-context/src/test/java/org/springframework/scheduling/config/LazyScheduledTasksBeanDefinitionParserTests.java b/spring-context/src/test/java/org/springframework/scheduling/config/LazyScheduledTasksBeanDefinitionParserTests.java index 3eef8738..191553a8 100644 --- a/spring-context/src/test/java/org/springframework/scheduling/config/LazyScheduledTasksBeanDefinitionParserTests.java +++ b/spring-context/src/test/java/org/springframework/scheduling/config/LazyScheduledTasksBeanDefinitionParserTests.java @@ -41,15 +41,19 @@ public class LazyScheduledTasksBeanDefinitionParserTests { while (!task.executed) { try { Thread.sleep(10); - } catch (Exception e) { /* Do Nothing */ } + } + catch (Exception ex) { /* Do Nothing */ } } } + static class Task { + volatile boolean executed = false; public void doWork() { executed = true; } } + } diff --git a/spring-context/src/test/java/org/springframework/scheduling/support/CronSequenceGeneratorTests.java b/spring-context/src/test/java/org/springframework/scheduling/support/CronSequenceGeneratorTests.java index 6c4df6b0..07b7537c 100644 --- a/spring-context/src/test/java/org/springframework/scheduling/support/CronSequenceGeneratorTests.java +++ b/spring-context/src/test/java/org/springframework/scheduling/support/CronSequenceGeneratorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,31 +29,66 @@ import static org.junit.Assert.*; public class CronSequenceGeneratorTests { @Test - public void testAt50Seconds() { + public void at50Seconds() { assertEquals(new Date(2012, 6, 2, 1, 0), new CronSequenceGenerator("*/15 * 1-4 * * *").next(new Date(2012, 6, 1, 9, 53, 50))); } @Test - public void testAt0Seconds() { + public void at0Seconds() { assertEquals(new Date(2012, 6, 2, 1, 0), new CronSequenceGenerator("*/15 * 1-4 * * *").next(new Date(2012, 6, 1, 9, 53))); } @Test - public void testAt0Minutes() { + public void at0Minutes() { assertEquals(new Date(2012, 6, 2, 1, 0), new CronSequenceGenerator("0 */2 1-4 * * *").next(new Date(2012, 6, 1, 9, 0))); } @Test(expected = IllegalArgumentException.class) - public void testWith0Increment() { + public void with0Increment() { new CronSequenceGenerator("*/0 * * * * *").next(new Date(2012, 6, 1, 9, 0)); } @Test(expected = IllegalArgumentException.class) - public void testWithNegativeIncrement() { + public void withNegativeIncrement() { new CronSequenceGenerator("*/-1 * * * * *").next(new Date(2012, 6, 1, 9, 0)); } + @Test(expected = IllegalArgumentException.class) + public void withInvertedMinuteRange() { + new CronSequenceGenerator("* 6-5 * * * *").next(new Date(2012, 6, 1, 9, 0)); + } + + @Test(expected = IllegalArgumentException.class) + public void withInvertedHourRange() { + new CronSequenceGenerator("* * 6-5 * * *").next(new Date(2012, 6, 1, 9, 0)); + } + + @Test + public void withSameMinuteRange() { + new CronSequenceGenerator("* 6-6 * * * *").next(new Date(2012, 6, 1, 9, 0)); + } + + @Test + public void withSameHourRange() { + new CronSequenceGenerator("* * 6-6 * * *").next(new Date(2012, 6, 1, 9, 0)); + } + + @Test + public void validExpression() { + assertTrue(CronSequenceGenerator.isValidExpression("0 */2 1-4 * * *")); + } + + @Test + public void invalidExpression() { + assertFalse(CronSequenceGenerator.isValidExpression("0 */2 1-4 * * * *")); + } + + @Test + public void nullExpression() { + assertFalse(CronSequenceGenerator.isValidExpression(null)); + } + } diff --git a/spring-context/src/test/java/org/springframework/scripting/groovy/GroovyScriptFactoryTests.java b/spring-context/src/test/java/org/springframework/scripting/groovy/GroovyScriptFactoryTests.java index 9ab27884..c8abcc42 100644 --- a/spring-context/src/test/java/org/springframework/scripting/groovy/GroovyScriptFactoryTests.java +++ b/spring-context/src/test/java/org/springframework/scripting/groovy/GroovyScriptFactoryTests.java @@ -268,7 +268,7 @@ public class GroovyScriptFactoryTests { @Test public void testScriptedClassThatDoesNotHaveANoArgCtor() throws Exception { ScriptSource script = mock(ScriptSource.class); - final String badScript = "class Foo { public Foo(String foo) {}}"; + String badScript = "class Foo { public Foo(String foo) {}}"; given(script.getScriptAsString()).willReturn(badScript); given(script.suggestedClassName()).willReturn("someName"); GroovyScriptFactory factory = new GroovyScriptFactory(ScriptFactoryPostProcessor.INLINE_SCRIPT_PREFIX @@ -285,11 +285,10 @@ public class GroovyScriptFactoryTests { @Test public void testScriptedClassThatHasNoPublicNoArgCtor() throws Exception { ScriptSource script = mock(ScriptSource.class); - final String badScript = "class Foo { protected Foo() {}}"; + String badScript = "class Foo { protected Foo() {} \n String toString() { 'X' }}"; given(script.getScriptAsString()).willReturn(badScript); given(script.suggestedClassName()).willReturn("someName"); - GroovyScriptFactory factory = new GroovyScriptFactory(ScriptFactoryPostProcessor.INLINE_SCRIPT_PREFIX - + badScript); + GroovyScriptFactory factory = new GroovyScriptFactory(ScriptFactoryPostProcessor.INLINE_SCRIPT_PREFIX + badScript); try { factory.getScriptedObject(script); fail("Must have thrown a ScriptCompilationException (no oublic no-arg ctor in scripted class)."); @@ -466,7 +465,7 @@ public class GroovyScriptFactoryTests { @Test // SPR-6268 public void testProxyTargetClassNotAllowedIfNotGroovy() throws Exception { try { - new ClassPathXmlApplicationContext("jruby-with-xsd-proxy-target-class.xml", getClass()); + new ClassPathXmlApplicationContext("groovy-with-xsd-proxy-target-class.xml", getClass()); } catch (BeanCreationException ex) { assertTrue(ex.getMessage().contains("Cannot use proxyTargetClass=true")); @@ -562,7 +561,7 @@ public class GroovyScriptFactoryTests { testMetaClass("org/springframework/scripting/groovy/calculators-with-xsd.xml"); } - private void testMetaClass(final String xmlFile) { + private void testMetaClass(String xmlFile) { // expect the exception we threw in the custom metaclass to show it got invoked try { ApplicationContext ctx = new ClassPathXmlApplicationContext(xmlFile); diff --git a/spring-context/src/test/java/org/springframework/scripting/jruby/AdvisedJRubyScriptFactoryTests.java b/spring-context/src/test/java/org/springframework/scripting/jruby/AdvisedJRubyScriptFactoryTests.java index 368effe8..10d1391a 100644 --- a/spring-context/src/test/java/org/springframework/scripting/jruby/AdvisedJRubyScriptFactoryTests.java +++ b/spring-context/src/test/java/org/springframework/scripting/jruby/AdvisedJRubyScriptFactoryTests.java @@ -58,7 +58,8 @@ public final class AdvisedJRubyScriptFactoryTests { assertEquals(0, advice.getCalls()); bean.getMessage(); assertEquals(1, advice.getCalls()); - } finally { + } + finally { ctx.close(); } } @@ -76,7 +77,8 @@ public final class AdvisedJRubyScriptFactoryTests { assertEquals(0, advice.getCalls()); bean.getMessage(); assertEquals(1, advice.getCalls()); - } finally { + } + finally { ctx.close(); } } diff --git a/spring-context/src/test/java/org/springframework/tests/sample/beans/Employee.java b/spring-context/src/test/java/org/springframework/tests/sample/beans/Employee.java index 40301c7a..fc2c639f 100644 --- a/spring-context/src/test/java/org/springframework/tests/sample/beans/Employee.java +++ b/spring-context/src/test/java/org/springframework/tests/sample/beans/Employee.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,13 @@ public class Employee extends TestBean { private String co; + public Employee() { + } + + public Employee(String name) { + super(name); + } + public String getCompany() { return co; } diff --git a/spring-context/src/test/java/org/springframework/validation/DataBinderTests.java b/spring-context/src/test/java/org/springframework/validation/DataBinderTests.java index b9090e8b..bdb12118 100644 --- a/spring-context/src/test/java/org/springframework/validation/DataBinderTests.java +++ b/spring-context/src/test/java/org/springframework/validation/DataBinderTests.java @@ -32,6 +32,7 @@ import java.util.List; import java.util.ListIterator; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.TreeSet; @@ -1112,6 +1113,27 @@ public class DataBinderTests { } @Test + public void testOptionalProperty() { + OptionalHolder bean = new OptionalHolder(); + DataBinder binder = new DataBinder(bean); + binder.setConversionService(new DefaultConversionService()); + + MutablePropertyValues pvs = new MutablePropertyValues(); + pvs.add("id", "1"); + pvs.add("name", null); + binder.bind(pvs); + assertEquals("1", bean.getId()); + assertFalse(bean.getName().isPresent()); + + pvs = new MutablePropertyValues(); + pvs.add("id", "2"); + pvs.add("name", "myName"); + binder.bind(pvs); + assertEquals("2", bean.getId()); + assertEquals("myName", bean.getName().get()); + } + + @Test public void testValidatorNoErrors() { TestBean tb = new TestBean(); tb.setAge(33); @@ -1976,7 +1998,6 @@ public class DataBinderTests { } - @SuppressWarnings("unused") private static class Book { private String Title; @@ -2011,6 +2032,30 @@ public class DataBinderTests { } + private static class OptionalHolder { + + private String id; + + private Optional<String> name; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public Optional<String> getName() { + return name; + } + + public void setName(Optional<String> name) { + this.name = name; + } + } + + private static class TestBeanValidator implements Validator { @Override diff --git a/spring-context/src/test/java/org/springframework/validation/beanvalidation/SpringValidatorAdapterTests.java b/spring-context/src/test/java/org/springframework/validation/beanvalidation/SpringValidatorAdapterTests.java new file mode 100644 index 00000000..90d0c480 --- /dev/null +++ b/spring-context/src/test/java/org/springframework/validation/beanvalidation/SpringValidatorAdapterTests.java @@ -0,0 +1,225 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.Documented; +import java.lang.annotation.Inherited; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.util.Locale; +import javax.validation.Constraint; +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import javax.validation.Payload; +import javax.validation.Validation; +import javax.validation.constraints.Size; + +import org.junit.Before; +import org.junit.Test; + +import org.springframework.beans.BeanWrapper; +import org.springframework.beans.BeanWrapperImpl; +import org.springframework.context.support.StaticMessageSource; +import org.springframework.util.ObjectUtils; +import org.springframework.validation.BeanPropertyBindingResult; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; +import static org.hamcrest.core.Is.*; +import static org.junit.Assert.*; + +/** + * @author Kazuki Shimizu + * @since 4.3 + */ +public class SpringValidatorAdapterTests { + + private final SpringValidatorAdapter validatorAdapter = new SpringValidatorAdapter( + Validation.buildDefaultValidatorFactory().getValidator()); + + private final StaticMessageSource messageSource = new StaticMessageSource(); + + + @Before + public void setupSpringValidatorAdapter() { + messageSource.addMessage("Size", Locale.ENGLISH, "Size of {0} is must be between {2} and {1}"); + messageSource.addMessage("Same", Locale.ENGLISH, "{2} must be same value with {1}"); + messageSource.addMessage("password", Locale.ENGLISH, "Password"); + messageSource.addMessage("confirmPassword", Locale.ENGLISH, "Password(Confirm)"); + } + + + @Test // SPR-13406 + public void testApplyMessageSourceResolvableToStringArgumentValueWithResolvedLogicalFieldName() { + TestBean testBean = new TestBean(); + testBean.setPassword("password"); + testBean.setConfirmPassword("PASSWORD"); + + BeanPropertyBindingResult errors = new BeanPropertyBindingResult(testBean, "testBean"); + validatorAdapter.validate(testBean, errors); + + assertThat(errors.getFieldErrorCount("password"), is(1)); + assertThat(messageSource.getMessage(errors.getFieldError("password"), Locale.ENGLISH), + is("Password must be same value with Password(Confirm)")); + + } + + @Test // SPR-13406 + public void testApplyMessageSourceResolvableToStringArgumentValueWithUnresolvedLogicalFieldName() { + TestBean testBean = new TestBean(); + testBean.setEmail("test@example.com"); + testBean.setConfirmEmail("TEST@EXAMPLE.IO"); + + BeanPropertyBindingResult errors = new BeanPropertyBindingResult(testBean, "testBean"); + validatorAdapter.validate(testBean, errors); + + assertThat(errors.getFieldErrorCount("email"), is(1)); + assertThat(messageSource.getMessage(errors.getFieldError("email"), Locale.ENGLISH), + is("email must be same value with confirmEmail")); + + } + + @Test // SPR-13406 + public void testNoStringArgumentValue() { + TestBean testBean = new TestBean(); + testBean.setPassword("pass"); + testBean.setConfirmPassword("pass"); + + BeanPropertyBindingResult errors = new BeanPropertyBindingResult(testBean, "testBean"); + validatorAdapter.validate(testBean, errors); + + assertThat(errors.getFieldErrorCount("password"), is(1)); + assertThat(messageSource.getMessage(errors.getFieldError("password"), Locale.ENGLISH), + is("Size of Password is must be between 8 and 128")); + + } + + + @Same(field = "password", comparingField = "confirmPassword") + @Same(field = "email", comparingField = "confirmEmail") + static class TestBean { + + @Size(min = 8, max = 128) + private String password; + private String confirmPassword; + + private String email; + private String confirmEmail; + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getConfirmPassword() { + return confirmPassword; + } + + public void setConfirmPassword(String confirmPassword) { + this.confirmPassword = confirmPassword; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getConfirmEmail() { + return confirmEmail; + } + + public void setConfirmEmail(String confirmEmail) { + this.confirmEmail = confirmEmail; + } + } + + + @Documented + @Constraint(validatedBy = {SameValidator.class}) + @Target({TYPE, ANNOTATION_TYPE}) + @Retention(RUNTIME) + @Repeatable(SameGroup.class) + @interface Same { + + String message() default "{org.springframework.validation.beanvalidation.Same.message}"; + + Class<?>[] groups() default {}; + + Class<? extends Payload>[] payload() default {}; + + String field(); + + String comparingField(); + + @Target({TYPE, ANNOTATION_TYPE}) + @Retention(RUNTIME) + @Documented + @interface List { + Same[] value(); + } + } + + + @Documented + @Inherited + @Retention(RUNTIME) + @Target({TYPE, ANNOTATION_TYPE}) + @interface SameGroup { + + Same[] value(); + } + + public static class SameValidator implements ConstraintValidator<Same, Object> { + + private String field; + + private String comparingField; + + private String message; + + public void initialize(Same constraintAnnotation) { + field = constraintAnnotation.field(); + comparingField = constraintAnnotation.comparingField(); + message = constraintAnnotation.message(); + } + + public boolean isValid(Object value, ConstraintValidatorContext context) { + BeanWrapper beanWrapper = new BeanWrapperImpl(value); + Object fieldValue = beanWrapper.getPropertyValue(field); + Object comparingFieldValue = beanWrapper.getPropertyValue(comparingField); + boolean matched = ObjectUtils.nullSafeEquals(fieldValue, comparingFieldValue); + if (matched) { + return true; + } + else { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(message) + .addNode(field) + .addConstraintViolation(); + return false; + } + } + } + +} |