From 594eb8e21bf9fb95e6edd68ea179d0a6a8488bb6 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 19 Mar 2021 15:24:39 +0100 Subject: [PATCH 1/2] Prepare issue branch. --- pom.xml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index f0f583b51e..2bd93edcff 100644 --- a/pom.xml +++ b/pom.xml @@ -1,11 +1,13 @@ - + 4.0.0 org.springframework.data spring-data-commons - 2.5.0-SNAPSHOT + 2.5.0-GH-2332-SNAPSHOT Spring Data Core @@ -339,7 +341,7 @@ 0.1.4 test - + org.jmolecules.integrations jmolecules-spring From dacc843c8b79ecbb84222ec02f0529ed0ee1917c Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 19 Mar 2021 15:25:48 +0100 Subject: [PATCH 2/2] Support @Value meta-annotations and expose MergedAnnotations on PreferredConstructor parameters. We now support composed annotation that are annotated with `@Value`. we also expose MergedAnnotations through PreferredConstructor.Parameter for further use by store modules that want to inspect constructor argument annotations. --- .../data/mapping/PreferredConstructor.java | 25 ++++++++++++---- ...eferredConstructorDiscovererUnitTests.java | 30 +++++++++++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/springframework/data/mapping/PreferredConstructor.java b/src/main/java/org/springframework/data/mapping/PreferredConstructor.java index a779c6a2ad..69eaa09f56 100644 --- a/src/main/java/org/springframework/data/mapping/PreferredConstructor.java +++ b/src/main/java/org/springframework/data/mapping/PreferredConstructor.java @@ -23,6 +23,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.annotation.MergedAnnotations; import org.springframework.data.annotation.PersistenceConstructor; import org.springframework.data.util.Lazy; import org.springframework.data.util.TypeInformation; @@ -175,6 +176,7 @@ public static class Parameter> { private final @Nullable String name; private final TypeInformation type; + private final MergedAnnotations annotations; private final String key; private final @Nullable PersistentEntity entity; @@ -199,7 +201,8 @@ public Parameter(@Nullable String name, TypeInformation type, Annotation[] an this.name = name; this.type = type; - this.key = getValue(annotations); + this.annotations = MergedAnnotations.from(annotations); + this.key = getValue(this.annotations); this.entity = entity; this.enclosingClassCache = Lazy.of(() -> { @@ -216,12 +219,12 @@ public Parameter(@Nullable String name, TypeInformation type, Annotation[] an } @Nullable - private static String getValue(Annotation[] annotations) { + private static String getValue(MergedAnnotations annotations) { - return Arrays.stream(annotations)// - .filter(it -> it.annotationType() == Value.class)// - .findFirst().map(it -> ((Value) it).value())// - .filter(StringUtils::hasText).orElse(null); + return annotations.get(Value.class) // + .getValue("value", String.class) // + .filter(StringUtils::hasText) // + .orElse(null); } /** @@ -243,6 +246,16 @@ public TypeInformation getType() { return type; } + /** + * Merged annotations that this parameter is annotated with. + * + * @return + * @since 2.5 + */ + public MergedAnnotations getAnnotations() { + return annotations; + } + /** * Returns the raw resolved type of the parameter. * diff --git a/src/test/java/org/springframework/data/mapping/PreferredConstructorDiscovererUnitTests.java b/src/test/java/org/springframework/data/mapping/PreferredConstructorDiscovererUnitTests.java index 031f916046..297791f9db 100755 --- a/src/test/java/org/springframework/data/mapping/PreferredConstructorDiscovererUnitTests.java +++ b/src/test/java/org/springframework/data/mapping/PreferredConstructorDiscovererUnitTests.java @@ -17,9 +17,15 @@ import static org.assertj.core.api.Assertions.*; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.util.Iterator; import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Value; import org.springframework.data.annotation.PersistenceConstructor; import org.springframework.data.mapping.PreferredConstructor.Parameter; import org.springframework.data.mapping.PreferredConstructorDiscovererUnitTests.Outer.Inner; @@ -135,6 +141,16 @@ void capturesSuperClassEnclosingTypeParameterOfNonStaticInnerClass() { }); } + @Test // GH-2332 + void detectsMetaAnnotatedValueAnnotation() { + + assertThat(PreferredConstructorDiscoverer.discover(ClassWithMetaAnnotatedParameter.class)).satisfies(ctor -> { + + assertThat(ctor.getParameters().get(0).getSpelExpression()).isEqualTo("${hello-world}"); + assertThat(ctor.getParameters().get(0).getAnnotations()).isNotNull(); + }); + } + static class SyntheticConstructor { @PersistenceConstructor private SyntheticConstructor(String x) {} @@ -204,4 +220,18 @@ public NonStaticInnerWithGenericArgUsedInCtor(T value) { super(value); } } + + static class ClassWithMetaAnnotatedParameter { + + ClassWithMetaAnnotatedParameter(@MyValue String value) { + + } + } + + @Target({ ElementType.PARAMETER, }) + @Retention(RetentionPolicy.RUNTIME) + @Value("${hello-world}") + @interface MyValue { + + } }