Skip to content

Commit d003f66

Browse files
committed
Tests for annotation lookups in interfaces (currently ignored for CGLIB proxies)
Issue: SPR-15271 Issue: SPR-14949 Issue: SPR-14322
1 parent d4a1b59 commit d003f66

File tree

4 files changed

+311
-31
lines changed

4 files changed

+311
-31
lines changed

spring-aspects/src/test/java/org/springframework/transaction/aspectj/TransactionAspectTests.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -185,14 +185,15 @@ public Object performTransactionalOperation() throws Throwable {
185185

186186
/**
187187
* Note: resolution does not occur. Thus we can't make a class transactional if
188-
* it implements a transactionally annotated interface. This behaviour could only
188+
* it implements a transactionally annotated interface. This behavior could only
189189
* be changed in AbstractFallbackTransactionAttributeSource in Spring proper.
190+
* See SPR-14322.
190191
*/
191192
@Test
192193
public void testDoesNotResolveTxAnnotationOnMethodFromClassImplementingAnnotatedInterface() throws Exception {
193194
AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource();
194-
Method m = ImplementsAnnotatedInterface.class.getMethod("echo", Throwable.class);
195-
TransactionAttribute ta = atas.getTransactionAttribute(m, ImplementsAnnotatedInterface.class);
195+
Method method = ImplementsAnnotatedInterface.class.getMethod("echo", Throwable.class);
196+
TransactionAttribute ta = atas.getTransactionAttribute(method, ImplementsAnnotatedInterface.class);
196197
assertNull(ta);
197198
}
198199

spring-context/src/test/java/org/springframework/cache/CacheReproTests.java

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
2121
import java.util.List;
2222
import java.util.Optional;
2323

24+
import org.junit.Ignore;
2425
import org.junit.Rule;
2526
import org.junit.Test;
2627
import org.junit.rules.ExpectedException;
@@ -57,8 +58,9 @@ public class CacheReproTests {
5758
@Rule
5859
public final ExpectedException thrown = ExpectedException.none();
5960

61+
6062
@Test
61-
public void spr11124() throws Exception {
63+
public void spr11124MultipleAnnotations() throws Exception {
6264
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr11124Config.class);
6365
Spr11124Service bean = context.getBean(Spr11124Service.class);
6466
bean.single(2);
@@ -69,7 +71,7 @@ public void spr11124() throws Exception {
6971
}
7072

7173
@Test
72-
public void spr11249() throws Exception {
74+
public void spr11249PrimitiveVarargs() throws Exception {
7375
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr11249Config.class);
7476
Spr11249Service bean = context.getBean(Spr11249Service.class);
7577
Object result = bean.doSomething("op", 2, 3);
@@ -166,6 +168,31 @@ public void spr14853AdaptsToOptionalWithSync() {
166168
assertSame(tb2, cache.get("tb1").get());
167169
}
168170

171+
@Test
172+
public void spr15271FindsOnInterfaceWithInterfaceProxy() {
173+
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr15271ConfigA.class);
174+
Spr15271Interface bean = context.getBean(Spr15271Interface.class);
175+
Cache cache = context.getBean(CacheManager.class).getCache("itemCache");
176+
177+
TestBean tb = new TestBean("tb1");
178+
bean.insertItem(tb);
179+
assertSame(tb, bean.findById("tb1").get());
180+
assertSame(tb, cache.get("tb1").get());
181+
}
182+
183+
@Test @Ignore // TODO
184+
public void spr15271FindsOnInterfaceWithCglibProxy() {
185+
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spr15271ConfigB.class);
186+
Spr15271Interface bean = context.getBean(Spr15271Interface.class);
187+
Cache cache = context.getBean(CacheManager.class).getCache("itemCache");
188+
189+
TestBean tb = new TestBean("tb1");
190+
bean.insertItem(tb);
191+
assertSame(tb, bean.findById("tb1").get());
192+
assertSame(tb, cache.get("tb1").get());
193+
}
194+
195+
169196
@Configuration
170197
@EnableCaching
171198
public static class Spr11124Config {
@@ -357,6 +384,7 @@ public Spr14230Service service() {
357384
}
358385
}
359386

387+
360388
public static class Spr14853Service {
361389

362390
@Cacheable(value = "itemCache", sync = true)
@@ -371,6 +399,7 @@ public TestBean insertItem(TestBean item) {
371399

372400
}
373401

402+
374403
@Configuration
375404
@EnableCaching
376405
public static class Spr14853Config {
@@ -386,4 +415,60 @@ public Spr14853Service service() {
386415
}
387416
}
388417

418+
419+
public interface Spr15271Interface {
420+
421+
@Cacheable(value = "itemCache", sync = true)
422+
Optional<TestBean> findById(String id);
423+
424+
@CachePut(cacheNames = "itemCache", key = "#item.name")
425+
TestBean insertItem(TestBean item);
426+
}
427+
428+
429+
public static class Spr15271Service implements Spr15271Interface {
430+
431+
@Override
432+
public Optional<TestBean> findById(String id) {
433+
return Optional.of(new TestBean(id));
434+
}
435+
436+
@Override
437+
public TestBean insertItem(TestBean item) {
438+
return item;
439+
}
440+
}
441+
442+
443+
@Configuration
444+
@EnableCaching
445+
public static class Spr15271ConfigA {
446+
447+
@Bean
448+
public CacheManager cacheManager() {
449+
return new ConcurrentMapCacheManager();
450+
}
451+
452+
@Bean
453+
public Spr15271Interface service() {
454+
return new Spr15271Service();
455+
}
456+
}
457+
458+
459+
@Configuration
460+
@EnableCaching(proxyTargetClass = true)
461+
public static class Spr15271ConfigB {
462+
463+
@Bean
464+
public CacheManager cacheManager() {
465+
return new ConcurrentMapCacheManager();
466+
}
467+
468+
@Bean
469+
public Spr15271Interface service() {
470+
return new Spr15271Service();
471+
}
472+
}
473+
389474
}

spring-context/src/test/java/org/springframework/scheduling/annotation/EnableAsyncTests.java

Lines changed: 110 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
2525
import java.util.concurrent.Executor;
2626
import java.util.concurrent.Future;
2727

28+
import org.junit.Ignore;
2829
import org.junit.Test;
2930
import org.mockito.Mockito;
3031

@@ -196,8 +197,32 @@ public void customExecutorIsPropagated() throws InterruptedException {
196197

197198
asyncBean.fail();
198199
Thread.sleep(500);
199-
Method m = ReflectionUtils.findMethod(AsyncBean.class, "fail");
200-
exceptionHandler.assertCalledWith(m, UnsupportedOperationException.class);
200+
Method method = ReflectionUtils.findMethod(AsyncBean.class, "fail");
201+
exceptionHandler.assertCalledWith(method, UnsupportedOperationException.class);
202+
203+
ctx.close();
204+
}
205+
206+
@Test
207+
public void spr14949FindsOnInterfaceWithInterfaceProxy() throws InterruptedException {
208+
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Spr14949ConfigA.class);
209+
210+
AsyncInterface asyncBean = ctx.getBean(AsyncInterface.class);
211+
asyncBean.work();
212+
Thread.sleep(500);
213+
assertThat(asyncBean.getThreadOfExecution().getName(), startsWith("Custom-"));
214+
215+
ctx.close();
216+
}
217+
218+
@Test @Ignore // TODO
219+
public void spr14949FindsOnInterfaceWithCglibProxy() throws InterruptedException {
220+
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Spr14949ConfigB.class);
221+
222+
AsyncInterface asyncBean = ctx.getBean(AsyncInterface.class);
223+
asyncBean.work();
224+
Thread.sleep(500);
225+
assertThat(asyncBean.getThreadOfExecution().getName(), startsWith("Custom-"));
201226

202227
ctx.close();
203228
}
@@ -333,6 +358,28 @@ public AsyncBean asyncBean() {
333358
}
334359

335360

361+
@Configuration
362+
@EnableAsync
363+
static class AsyncWithExecutorQualifiedByNameConfig {
364+
365+
@Bean
366+
public AsyncBeanWithExecutorQualifiedByName asyncBean() {
367+
return new AsyncBeanWithExecutorQualifiedByName();
368+
}
369+
370+
@Bean
371+
public Executor e1() {
372+
return new ThreadPoolTaskExecutor();
373+
}
374+
375+
@Bean
376+
@Qualifier("e2")
377+
public Executor otherExecutor() {
378+
return new ThreadPoolTaskExecutor();
379+
}
380+
}
381+
382+
336383
@Configuration
337384
@EnableAsync
338385
static class CustomExecutorAsyncConfig implements AsyncConfigurer {
@@ -362,24 +409,75 @@ public AsyncUncaughtExceptionHandler exceptionHandler() {
362409
}
363410

364411

412+
public interface AsyncInterface {
413+
414+
@Async
415+
void work();
416+
417+
Thread getThreadOfExecution();
418+
}
419+
420+
421+
public static class AsyncService implements AsyncInterface {
422+
423+
private Thread threadOfExecution;
424+
425+
@Override
426+
public void work() {
427+
this.threadOfExecution = Thread.currentThread();
428+
}
429+
430+
@Override
431+
public Thread getThreadOfExecution() {
432+
return threadOfExecution;
433+
}
434+
}
435+
436+
365437
@Configuration
366438
@EnableAsync
367-
static class AsyncWithExecutorQualifiedByNameConfig {
439+
static class Spr14949ConfigA implements AsyncConfigurer {
368440

369441
@Bean
370-
public AsyncBeanWithExecutorQualifiedByName asyncBean() {
371-
return new AsyncBeanWithExecutorQualifiedByName();
442+
public AsyncInterface asyncBean() {
443+
return new AsyncService();
372444
}
373445

374-
@Bean
375-
public Executor e1() {
376-
return new ThreadPoolTaskExecutor();
446+
@Override
447+
public Executor getAsyncExecutor() {
448+
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
449+
executor.setThreadNamePrefix("Custom-");
450+
executor.initialize();
451+
return executor;
377452
}
378453

454+
@Override
455+
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
456+
return null;
457+
}
458+
}
459+
460+
461+
@Configuration
462+
@EnableAsync(proxyTargetClass = true)
463+
static class Spr14949ConfigB implements AsyncConfigurer {
464+
379465
@Bean
380-
@Qualifier("e2")
381-
public Executor otherExecutor() {
382-
return new ThreadPoolTaskExecutor();
466+
public AsyncInterface asyncBean() {
467+
return new AsyncService();
468+
}
469+
470+
@Override
471+
public Executor getAsyncExecutor() {
472+
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
473+
executor.setThreadNamePrefix("Custom-");
474+
executor.initialize();
475+
return executor;
476+
}
477+
478+
@Override
479+
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
480+
return null;
383481
}
384482
}
385483

0 commit comments

Comments
 (0)