diff --git a/extensions/jackson/deployment/src/main/java/io/quarkus/jackson/deployment/JacksonProcessor.java b/extensions/jackson/deployment/src/main/java/io/quarkus/jackson/deployment/JacksonProcessor.java index d41d1406b765f..3908aa8582dfb 100755 --- a/extensions/jackson/deployment/src/main/java/io/quarkus/jackson/deployment/JacksonProcessor.java +++ b/extensions/jackson/deployment/src/main/java/io/quarkus/jackson/deployment/JacksonProcessor.java @@ -53,6 +53,7 @@ public class JacksonProcessor { private static final DotName JSON_DESERIALIZE = DotName.createSimple(JsonDeserialize.class.getName()); private static final DotName JSON_SERIALIZE = DotName.createSimple(JsonSerialize.class.getName()); private static final DotName JSON_CREATOR = DotName.createSimple("com.fasterxml.jackson.annotation.JsonCreator"); + private static final DotName JSON_NAMING = DotName.createSimple("com.fasterxml.jackson.databind.annotation.JsonNaming"); private static final DotName BUILDER_VOID = DotName.createSimple(Void.class.getName()); private static final String TIME_MODULE = "com.fasterxml.jackson.datatype.jsr310.JavaTimeModule"; @@ -117,7 +118,7 @@ CapabilityBuildItem register() { AnnotationValue usingValue = deserializeInstance.value("using"); if (usingValue != null) { // the Deserializers are constructed internally by Jackson using a no-args constructor - reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, usingValue.asClass().toString())); + reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, usingValue.asClass().name().toString())); } } @@ -128,7 +129,7 @@ CapabilityBuildItem register() { AnnotationValue usingValue = serializeInstance.value("using"); if (usingValue != null) { // the Deserializers are constructed internally by Jackson using a no-args constructor - reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, usingValue.asClass().toString())); + reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, usingValue.asClass().name().toString())); } } } @@ -140,6 +141,14 @@ CapabilityBuildItem register() { } } + // register @JsonNaming strategy implementations for reflection + for (AnnotationInstance jsonNamingInstance : index.getAnnotations(JSON_NAMING)) { + AnnotationValue strategyValue = jsonNamingInstance.value("value"); + if (strategyValue != null) { + reflectiveClass.produce(new ReflectiveClassBuildItem(true, true, strategyValue.asClass().name().toString())); + } + } + // this needs to be registered manually since the runtime module is not indexed by Jandex additionalBeans.produce(new AdditionalBeanBuildItem(ObjectMapperProducer.class)); diff --git a/integration-tests/jackson/src/main/java/io/quarkus/it/jackson/ModelWithJsonNamingStrategyResource.java b/integration-tests/jackson/src/main/java/io/quarkus/it/jackson/ModelWithJsonNamingStrategyResource.java new file mode 100644 index 0000000000000..ef3692133a658 --- /dev/null +++ b/integration-tests/jackson/src/main/java/io/quarkus/it/jackson/ModelWithJsonNamingStrategyResource.java @@ -0,0 +1,28 @@ +package io.quarkus.it.jackson; + +import java.io.IOException; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import io.quarkus.it.jackson.model.SampleResponse; + +@Path("/json-naming/") +public class ModelWithJsonNamingStrategyResource { + + private final ObjectMapper objectMapper; + + public ModelWithJsonNamingStrategyResource(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + public String get() throws IOException { + return objectMapper.writeValueAsString(new SampleResponse("My blog post")); + } +} diff --git a/integration-tests/jackson/src/main/java/io/quarkus/it/jackson/model/SampleResponse.java b/integration-tests/jackson/src/main/java/io/quarkus/it/jackson/model/SampleResponse.java new file mode 100644 index 0000000000000..6badef9590475 --- /dev/null +++ b/integration-tests/jackson/src/main/java/io/quarkus/it/jackson/model/SampleResponse.java @@ -0,0 +1,35 @@ +package io.quarkus.it.jackson.model; + +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.databind.annotation.JsonNaming; + +import io.quarkus.runtime.annotations.RegisterForReflection; + +@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) +@RegisterForReflection +public class SampleResponse { + + private String blogTitle; + + public SampleResponse() { + } + + public SampleResponse(String blogTitle) { + this.blogTitle = blogTitle; + } + + public String getBlogTitle() { + return blogTitle; + } + + public void setBlogTitle(String blogTitle) { + this.blogTitle = blogTitle; + } + + @Override + public String toString() { + return "SampleResponse{" + + "blogTitle='" + blogTitle + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/integration-tests/jackson/src/test/java/io/quarkus/it/jackson/ModelWithJsonNamingStrategyResourceIT.java b/integration-tests/jackson/src/test/java/io/quarkus/it/jackson/ModelWithJsonNamingStrategyResourceIT.java new file mode 100644 index 0000000000000..9411062a9e385 --- /dev/null +++ b/integration-tests/jackson/src/test/java/io/quarkus/it/jackson/ModelWithJsonNamingStrategyResourceIT.java @@ -0,0 +1,9 @@ +package io.quarkus.it.jackson; + +import io.quarkus.test.junit.NativeImageTest; + +@NativeImageTest +public class ModelWithJsonNamingStrategyResourceIT extends ModelWithJsonNamingStrategyResourceTest { + + // Execute the same tests but in native mode. +} diff --git a/integration-tests/jackson/src/test/java/io/quarkus/it/jackson/ModelWithJsonNamingStrategyResourceTest.java b/integration-tests/jackson/src/test/java/io/quarkus/it/jackson/ModelWithJsonNamingStrategyResourceTest.java new file mode 100644 index 0000000000000..0eec2037f7cb1 --- /dev/null +++ b/integration-tests/jackson/src/test/java/io/quarkus/it/jackson/ModelWithJsonNamingStrategyResourceTest.java @@ -0,0 +1,24 @@ +package io.quarkus.it.jackson; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.containsString; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +public class ModelWithJsonNamingStrategyResourceTest { + + @Test + public void testStrategy() throws IOException { + given() + .when().get("/json-naming/") + .then() + .statusCode(200) + .body(containsString("blog_title")); + } + +}