diff --git a/spring-aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests.java b/spring-aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests.java index 7d1f1f73fb5..c12bf120498 100644 --- a/spring-aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests.java +++ b/spring-aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -185,14 +185,15 @@ public class TransactionAspectTests { /** * Note: resolution does not occur. Thus we can't make a class transactional if - * it implements a transactionally annotated interface. This behaviour could only + * it implements a transactionally annotated interface. This behavior could only * be changed in AbstractFallbackTransactionAttributeSource in Spring proper. + * See SPR-14322. */ @Test public void testDoesNotResolveTxAnnotationOnMethodFromClassImplementingAnnotatedInterface() throws Exception { AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); - Method m = ImplementsAnnotatedInterface.class.getMethod("echo", Throwable.class); - TransactionAttribute ta = atas.getTransactionAttribute(m, ImplementsAnnotatedInterface.class); + Method method = ImplementsAnnotatedInterface.class.getMethod("echo", Throwable.class); + TransactionAttribute ta = atas.getTransactionAttribute(method, ImplementsAnnotatedInterface.class); assertNull(ta); } 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 12939b9c68f..24495bdb1d8 100644 --- a/spring-context/src/test/java/org/springframework/cache/CacheReproTests.java +++ b/spring-context/src/test/java/org/springframework/cache/CacheReproTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author 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.util.Collections; import java.util.List; import java.util.Optional; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -57,8 +58,9 @@ public class CacheReproTests { @Rule public final ExpectedException thrown = ExpectedException.none(); + @Test - public void spr11124() throws Exception { + public void spr11124MultipleAnnotations() throws Exception { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr11124Config.class); Spr11124Service bean = context.getBean(Spr11124Service.class); bean.single(2); @@ -69,7 +71,7 @@ public class CacheReproTests { } @Test - public void spr11249() throws Exception { + public void spr11249PrimitiveVarargs() throws Exception { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr11249Config.class); Spr11249Service bean = context.getBean(Spr11249Service.class); Object result = bean.doSomething("op", 2, 3); @@ -166,6 +168,31 @@ public class CacheReproTests { assertSame(tb2, cache.get("tb1").get()); } + @Test + public void spr15271FindsOnInterfaceWithInterfaceProxy() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr15271ConfigA.class); + Spr15271Interface bean = context.getBean(Spr15271Interface.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()); + } + + @Test @Ignore // TODO + public void spr15271FindsOnInterfaceWithCglibProxy() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr15271ConfigB.class); + Spr15271Interface bean = context.getBean(Spr15271Interface.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()); + } + + @Configuration @EnableCaching public static class Spr11124Config { @@ -357,6 +384,7 @@ public class CacheReproTests { } } + public static class Spr14853Service { @Cacheable(value = "itemCache", sync = true) @@ -371,6 +399,7 @@ public class CacheReproTests { } + @Configuration @EnableCaching public static class Spr14853Config { @@ -386,4 +415,60 @@ public class CacheReproTests { } } + + public interface Spr15271Interface { + + @Cacheable(value = "itemCache", sync = true) + Optional findById(String id); + + @CachePut(cacheNames = "itemCache", key = "#item.name") + TestBean insertItem(TestBean item); + } + + + public static class Spr15271Service implements Spr15271Interface { + + @Override + public Optional findById(String id) { + return Optional.of(new TestBean(id)); + } + + @Override + public TestBean insertItem(TestBean item) { + return item; + } + } + + + @Configuration + @EnableCaching + public static class Spr15271ConfigA { + + @Bean + public CacheManager cacheManager() { + return new ConcurrentMapCacheManager(); + } + + @Bean + public Spr15271Interface service() { + return new Spr15271Service(); + } + } + + + @Configuration + @EnableCaching(proxyTargetClass = true) + public static class Spr15271ConfigB { + + @Bean + public CacheManager cacheManager() { + return new ConcurrentMapCacheManager(); + } + + @Bean + public Spr15271Interface service() { + return new Spr15271Service(); + } + } + } 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 81642602c89..3e5cf952f85 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-2016 the original author or authors. + * Copyright 2002-2017 the original author 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.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.Future; +import org.junit.Ignore; import org.junit.Test; import org.mockito.Mockito; @@ -196,8 +197,32 @@ public class EnableAsyncTests { asyncBean.fail(); Thread.sleep(500); - Method m = ReflectionUtils.findMethod(AsyncBean.class, "fail"); - exceptionHandler.assertCalledWith(m, UnsupportedOperationException.class); + Method method = ReflectionUtils.findMethod(AsyncBean.class, "fail"); + exceptionHandler.assertCalledWith(method, UnsupportedOperationException.class); + + ctx.close(); + } + + @Test + public void spr14949FindsOnInterfaceWithInterfaceProxy() throws InterruptedException { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Spr14949ConfigA.class); + + AsyncInterface asyncBean = ctx.getBean(AsyncInterface.class); + asyncBean.work(); + Thread.sleep(500); + assertThat(asyncBean.getThreadOfExecution().getName(), startsWith("Custom-")); + + ctx.close(); + } + + @Test @Ignore // TODO + public void spr14949FindsOnInterfaceWithCglibProxy() throws InterruptedException { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Spr14949ConfigB.class); + + AsyncInterface asyncBean = ctx.getBean(AsyncInterface.class); + asyncBean.work(); + Thread.sleep(500); + assertThat(asyncBean.getThreadOfExecution().getName(), startsWith("Custom-")); ctx.close(); } @@ -333,6 +358,28 @@ public class EnableAsyncTests { } + @Configuration + @EnableAsync + static class AsyncWithExecutorQualifiedByNameConfig { + + @Bean + public AsyncBeanWithExecutorQualifiedByName asyncBean() { + return new AsyncBeanWithExecutorQualifiedByName(); + } + + @Bean + public Executor e1() { + return new ThreadPoolTaskExecutor(); + } + + @Bean + @Qualifier("e2") + public Executor otherExecutor() { + return new ThreadPoolTaskExecutor(); + } + } + + @Configuration @EnableAsync static class CustomExecutorAsyncConfig implements AsyncConfigurer { @@ -362,24 +409,75 @@ public class EnableAsyncTests { } + public interface AsyncInterface { + + @Async + void work(); + + Thread getThreadOfExecution(); + } + + + public static class AsyncService implements AsyncInterface { + + private Thread threadOfExecution; + + @Override + public void work() { + this.threadOfExecution = Thread.currentThread(); + } + + @Override + public Thread getThreadOfExecution() { + return threadOfExecution; + } + } + + @Configuration @EnableAsync - static class AsyncWithExecutorQualifiedByNameConfig { + static class Spr14949ConfigA implements AsyncConfigurer { @Bean - public AsyncBeanWithExecutorQualifiedByName asyncBean() { - return new AsyncBeanWithExecutorQualifiedByName(); + public AsyncInterface asyncBean() { + return new AsyncService(); } - @Bean - public Executor e1() { - return new ThreadPoolTaskExecutor(); + @Override + public Executor getAsyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setThreadNamePrefix("Custom-"); + executor.initialize(); + return executor; } + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return null; + } + } + + + @Configuration + @EnableAsync(proxyTargetClass = true) + static class Spr14949ConfigB implements AsyncConfigurer { + @Bean - @Qualifier("e2") - public Executor otherExecutor() { - return new ThreadPoolTaskExecutor(); + public AsyncInterface asyncBean() { + return new AsyncService(); + } + + @Override + public Executor getAsyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setThreadNamePrefix("Custom-"); + executor.initialize(); + return executor; + } + + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return null; } } diff --git a/spring-tx/src/test/java/org/springframework/transaction/annotation/EnableTransactionManagementTests.java b/spring-tx/src/test/java/org/springframework/transaction/annotation/EnableTransactionManagementTests.java index ed4e127dba7..915c7ad0563 100644 --- a/spring-tx/src/test/java/org/springframework/transaction/annotation/EnableTransactionManagementTests.java +++ b/spring-tx/src/test/java/org/springframework/transaction/annotation/EnableTransactionManagementTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author 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,8 +16,10 @@ package org.springframework.transaction.annotation; +import java.util.Collection; import java.util.Map; +import org.junit.Ignore; import org.junit.Test; import org.springframework.aop.support.AopUtils; @@ -34,7 +36,6 @@ import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.stereotype.Service; import org.springframework.tests.transaction.CallCountingTransactionManager; import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.transaction.annotation.AnnotationTransactionNamespaceHandlerTests.TransactionalTestBean; import org.springframework.transaction.config.TransactionManagementConfigUtils; import org.springframework.transaction.event.TransactionalEventListenerFactory; @@ -45,6 +46,7 @@ import static org.junit.Assert.*; * Tests demonstrating use of @EnableTransactionManagement @Configuration classes. * * @author Chris Beams + * @author Juergen Hoeller * @author Stephane Nicoll * @author Sam Brannen * @since 3.1 @@ -132,7 +134,7 @@ public class EnableTransactionManagementTests { } @Test - public void spr11915() { + public void spr11915TransactionManagerAsManualSingleton() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Spr11915Config.class); TransactionalTestBean bean = ctx.getBean(TransactionalTestBean.class); CallCountingTransactionManager txManager = ctx.getBean("qualifiedTransactionManager", CallCountingTransactionManager.class); @@ -150,6 +152,52 @@ public class EnableTransactionManagementTests { ctx.close(); } + @Test + public void spr14322FindsOnInterfaceWithInterfaceProxy() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Spr14322ConfigA.class); + TransactionalTestInterface bean = ctx.getBean(TransactionalTestInterface.class); + CallCountingTransactionManager txManager = ctx.getBean(CallCountingTransactionManager.class); + + bean.saveFoo(); + assertThat(txManager.begun, equalTo(1)); + assertThat(txManager.commits, equalTo(1)); + assertThat(txManager.rollbacks, equalTo(0)); + + ctx.close(); + } + + @Test @Ignore // TODO + public void spr14322FindsOnInterfaceWithCglibProxy() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Spr14322ConfigB.class); + TransactionalTestInterface bean = ctx.getBean(TransactionalTestInterface.class); + CallCountingTransactionManager txManager = ctx.getBean(CallCountingTransactionManager.class); + + bean.saveFoo(); + assertThat(txManager.begun, equalTo(1)); + assertThat(txManager.commits, equalTo(1)); + assertThat(txManager.rollbacks, equalTo(0)); + + ctx.close(); + } + + + @Service + public static class TransactionalTestBean { + + @Transactional(readOnly = true) + public Collection findAllFoos() { + return null; + } + + @Transactional("qualifiedTransactionManager") + public void saveQualifiedFoo() { + } + + @Transactional(transactionManager = "qualifiedTransactionManager") + public void saveQualifiedFooWithAttributeAlias() { + } + } + @Configuration @EnableTransactionManagement @@ -204,6 +252,36 @@ public class EnableTransactionManagementTests { } + @Configuration + static class TxManagerConfig { + + @Bean + public TransactionalTestBean testBean() { + return new TransactionalTestBean(); + } + + @Bean + public PlatformTransactionManager txManager() { + return new CallCountingTransactionManager(); + } + } + + + @Configuration + static class MultiTxManagerConfig extends TxManagerConfig implements TransactionManagementConfigurer { + + @Bean + public PlatformTransactionManager txManager2() { + return new CallCountingTransactionManager(); + } + + @Override + public PlatformTransactionManager annotationDrivenTransactionManager() { + return txManager2(); + } + } + + @Configuration @EnableTransactionManagement static class Spr11915Config { @@ -221,12 +299,29 @@ public class EnableTransactionManagementTests { } + public interface TransactionalTestInterface { + + @Transactional + void saveFoo(); + } + + + @Service + public static class TransactionalTestService implements TransactionalTestInterface { + + @Override + public void saveFoo() { + } + } + + @Configuration - static class TxManagerConfig { + @EnableTransactionManagement + static class Spr14322ConfigA { @Bean - public TransactionalTestBean testBean() { - return new TransactionalTestBean(); + public TransactionalTestInterface testBean() { + return new TransactionalTestService(); } @Bean @@ -237,16 +332,17 @@ public class EnableTransactionManagementTests { @Configuration - static class MultiTxManagerConfig extends TxManagerConfig implements TransactionManagementConfigurer { + @EnableTransactionManagement(proxyTargetClass = true) + static class Spr14322ConfigB { @Bean - public PlatformTransactionManager txManager2() { - return new CallCountingTransactionManager(); + public TransactionalTestInterface testBean() { + return new TransactionalTestService(); } - @Override - public PlatformTransactionManager annotationDrivenTransactionManager() { - return txManager2(); + @Bean + public PlatformTransactionManager txManager() { + return new CallCountingTransactionManager(); } }