From fcb75b6a1e61dd1772eda2b8a5e40671314c8ff5 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Sat, 14 Oct 2023 19:43:41 -0700 Subject: [PATCH 1/2] Search implemented interfaces on superclass for @ServiceConnection Refine original fix to also search interfaces on the superclass. Fixes gh-37671 --- .../ServiceConnectionContextCustomizerFactory.java | 6 +++++- ...rviceConnectionContextCustomizerFactoryTests.java | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionContextCustomizerFactory.java b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionContextCustomizerFactory.java index 9c991328b4d..c54c77b0451 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionContextCustomizerFactory.java +++ b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionContextCustomizerFactory.java @@ -54,7 +54,10 @@ class ServiceConnectionContextCustomizerFactory implements ContextCustomizerFact } private void findSources(Class clazz, List> sources) { - ReflectionUtils.doWithFields(clazz, (field) -> { + if (clazz == Object.class || clazz == null) { + return; + } + ReflectionUtils.doWithLocalFields(clazz, (field) -> { MergedAnnotations annotations = MergedAnnotations.from(field); annotations.stream(ServiceConnection.class) .forEach((annotation) -> sources.add(createSource(field, annotation))); @@ -65,6 +68,7 @@ class ServiceConnectionContextCustomizerFactory implements ContextCustomizerFact for (Class implementedInterface : clazz.getInterfaces()) { findSources(implementedInterface, sources); } + findSources(clazz.getSuperclass(), sources); } @SuppressWarnings("unchecked") diff --git a/spring-boot-project/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionContextCustomizerFactoryTests.java b/spring-boot-project/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionContextCustomizerFactoryTests.java index dc487d12c7e..ba3071e8aa3 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionContextCustomizerFactoryTests.java +++ b/spring-boot-project/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionContextCustomizerFactoryTests.java @@ -94,6 +94,14 @@ class ServiceConnectionContextCustomizerFactoryTests { assertThat(customizer.getSources()).hasSize(2); } + @Test + void createContextCustomizerWhenInheritedImplementedInterfaceHasServiceConnectionsReturnsCustomizer() { + ServiceConnectionContextCustomizer customizer = (ServiceConnectionContextCustomizer) this.factory + .createContextCustomizer(ServiceConnectionsImplSubclass.class, null); + assertThat(customizer).isNotNull(); + assertThat(customizer.getSources()).hasSize(2); + } + @Test void createContextCustomizerWhenClassHasNonStaticServiceConnectionFailsWithHelpfulException() { assertThatIllegalStateException() @@ -186,6 +194,10 @@ class ServiceConnectionContextCustomizerFactoryTests { } + static class ServiceConnectionsImplSubclass extends ServiceConnectionsImpl { + + } + static class NonStaticServiceConnection { @ServiceConnection From 343046d30ccdd9ee3612b6915a3bc0235bef25ce Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Sat, 14 Oct 2023 19:51:42 -0700 Subject: [PATCH 2/2] Polish --- ...viceConnectionContextCustomizerFactory.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionContextCustomizerFactory.java b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionContextCustomizerFactory.java index c54c77b0451..1f18f06c1a0 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionContextCustomizerFactory.java +++ b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ServiceConnectionContextCustomizerFactory.java @@ -49,26 +49,26 @@ class ServiceConnectionContextCustomizerFactory implements ContextCustomizerFact public ContextCustomizer createContextCustomizer(Class testClass, List configAttributes) { List> sources = new ArrayList<>(); - findSources(testClass, sources); + collectSources(testClass, sources); return new ServiceConnectionContextCustomizer(sources); } - private void findSources(Class clazz, List> sources) { - if (clazz == Object.class || clazz == null) { + private void collectSources(Class candidate, List> sources) { + if (candidate == Object.class || candidate == null) { return; } - ReflectionUtils.doWithLocalFields(clazz, (field) -> { + ReflectionUtils.doWithLocalFields(candidate, (field) -> { MergedAnnotations annotations = MergedAnnotations.from(field); annotations.stream(ServiceConnection.class) .forEach((annotation) -> sources.add(createSource(field, annotation))); }); - if (TestContextAnnotationUtils.searchEnclosingClass(clazz)) { - findSources(clazz.getEnclosingClass(), sources); + if (TestContextAnnotationUtils.searchEnclosingClass(candidate)) { + collectSources(candidate.getEnclosingClass(), sources); } - for (Class implementedInterface : clazz.getInterfaces()) { - findSources(implementedInterface, sources); + for (Class implementedInterface : candidate.getInterfaces()) { + collectSources(implementedInterface, sources); } - findSources(clazz.getSuperclass(), sources); + collectSources(candidate.getSuperclass(), sources); } @SuppressWarnings("unchecked")