Infer reflection hints for Jackson annotation class attributes
Closes gh-29646 Closes gh-29386
This commit is contained in:
parent
1e47f31210
commit
e6397c8a38
|
@ -85,7 +85,7 @@ dependencies {
|
|||
testImplementation("org.skyscreamer:jsonassert")
|
||||
testImplementation("com.squareup.okhttp3:mockwebserver")
|
||||
testImplementation("org.jetbrains.kotlinx:kotlinx-serialization-json")
|
||||
testImplementation("com.fasterxml.jackson.core:jackson-annotations")
|
||||
testImplementation("com.fasterxml.jackson.core:jackson-databind")
|
||||
testFixturesImplementation("com.google.code.findbugs:jsr305")
|
||||
testFixturesImplementation("org.junit.platform:junit-platform-launcher")
|
||||
testFixturesImplementation("org.junit.jupiter:junit-jupiter-api")
|
||||
|
|
|
@ -16,12 +16,15 @@
|
|||
|
||||
package org.springframework.aot.hint;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.RecordComponent;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import kotlin.jvm.JvmClassMappingKt;
|
||||
import kotlin.reflect.KClass;
|
||||
|
@ -161,27 +164,32 @@ public class BindingReflectionHintsRegistrar {
|
|||
|
||||
private void registerJacksonHints(ReflectionHints hints, Class<?> clazz) {
|
||||
ReflectionUtils.doWithFields(clazz, field ->
|
||||
MergedAnnotations
|
||||
.from(field, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY)
|
||||
.stream(JACKSON_ANNOTATION)
|
||||
.filter(MergedAnnotation::isMetaPresent)
|
||||
.forEach(annotation -> {
|
||||
forEachJacksonAnnotation(field, annotation -> {
|
||||
Field sourceField = (Field) annotation.getSource();
|
||||
if (sourceField != null) {
|
||||
hints.registerField(sourceField);
|
||||
}
|
||||
}));
|
||||
ReflectionUtils.doWithMethods(clazz, method ->
|
||||
MergedAnnotations
|
||||
.from(method, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY)
|
||||
.stream(JACKSON_ANNOTATION)
|
||||
.filter(MergedAnnotation::isMetaPresent)
|
||||
.forEach(annotation -> {
|
||||
forEachJacksonAnnotation(method, annotation -> {
|
||||
Method sourceMethod = (Method) annotation.getSource();
|
||||
if (sourceMethod != null) {
|
||||
hints.registerMethod(sourceMethod, ExecutableMode.INVOKE);
|
||||
}
|
||||
}));
|
||||
forEachJacksonAnnotation(clazz, annotation -> annotation.getRoot().asMap().values().forEach(value -> {
|
||||
if (value instanceof Class<?> classValue) {
|
||||
hints.registerType(classValue, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private void forEachJacksonAnnotation(AnnotatedElement element, Consumer<MergedAnnotation<Annotation>> action) {
|
||||
MergedAnnotations
|
||||
.from(element, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY)
|
||||
.stream(JACKSON_ANNOTATION)
|
||||
.filter(MergedAnnotation::isMetaPresent)
|
||||
.forEach(action::accept);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,6 +21,10 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonNaming;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
|
||||
|
@ -252,6 +256,15 @@ public class BindingReflectionHintsRegistrarTests {
|
|||
.accepts(this.hints);
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerTypeForJacksonCustomStrategy() {
|
||||
bindingRegistrar.registerReflectionHints(this.hints.reflection(), SampleRecordWithJacksonCustomStrategy.class);
|
||||
assertThat(RuntimeHintsPredicates.reflection().onType(PropertyNamingStrategies.UpperSnakeCaseStrategy.class).withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS))
|
||||
.accepts(this.hints);
|
||||
assertThat(RuntimeHintsPredicates.reflection().onType(SampleRecordWithJacksonCustomStrategy.Builder.class).withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS))
|
||||
.accepts(this.hints);
|
||||
}
|
||||
|
||||
|
||||
static class SampleEmptyClass {
|
||||
}
|
||||
|
@ -356,4 +369,28 @@ public class BindingReflectionHintsRegistrarTests {
|
|||
|
||||
static class SampleClassWithInheritedJsonProperty extends SampleClassWithJsonProperty {}
|
||||
|
||||
@JsonNaming(PropertyNamingStrategies.UpperSnakeCaseStrategy.class)
|
||||
@JsonDeserialize(builder = SampleRecordWithJacksonCustomStrategy.Builder.class)
|
||||
record SampleRecordWithJacksonCustomStrategy(String name) {
|
||||
|
||||
@JsonPOJOBuilder(withPrefix = "")
|
||||
public static class Builder {
|
||||
private String name;
|
||||
|
||||
public static Builder newInstance() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public Builder id(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SampleRecordWithJacksonCustomStrategy build() {
|
||||
return new SampleRecordWithJacksonCustomStrategy(name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue