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.

Closes: #2332
Original Pull Request: #2333
This commit is contained in:
Mark Paluch
2021-03-19 15:25:48 +01:00
committed by Christoph Strobl
parent 9224710c53
commit 79ed0a75c7
2 changed files with 49 additions and 6 deletions

View File

@@ -23,6 +23,7 @@ import java.util.Map;
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 class PreferredConstructor<T, P extends PersistentProperty<P>> {
private final @Nullable String name;
private final TypeInformation<T> type;
private final MergedAnnotations annotations;
private final String key;
private final @Nullable PersistentEntity<T, P> entity;
@@ -199,7 +201,8 @@ public class PreferredConstructor<T, P extends PersistentProperty<P>> {
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 class PreferredConstructor<T, P extends PersistentProperty<P>> {
}
@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 class PreferredConstructor<T, P extends PersistentProperty<P>> {
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.
*

View File

@@ -17,9 +17,15 @@ package org.springframework.data.mapping;
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 @@ class PreferredConstructorDiscovererUnitTests<P extends PersistentProperty<P>> {
});
}
@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 @@ class PreferredConstructorDiscovererUnitTests<P extends PersistentProperty<P>> {
super(value);
}
}
static class ClassWithMetaAnnotatedParameter {
ClassWithMetaAnnotatedParameter(@MyValue String value) {
}
}
@Target({ ElementType.PARAMETER, })
@Retention(RetentionPolicy.RUNTIME)
@Value("${hello-world}")
@interface MyValue {
}
}