Skip to content

Commit

Permalink
Merge pull request #37993 from geoand/#37942
Browse files Browse the repository at this point in the history
Register JsonSubTypes.Type values for native mode
  • Loading branch information
geoand authored Jan 3, 2024
2 parents 6cef0d5 + d7c765c commit d98da34
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.jboss.jandex.Type;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.SimpleObjectIdResolver;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
Expand Down Expand Up @@ -79,7 +80,7 @@ public class JacksonProcessor {
private static final DotName JSON_AUTO_DETECT = DotName.createSimple(JsonAutoDetect.class.getName());

private static final DotName JSON_TYPE_ID_RESOLVER = DotName.createSimple(JsonTypeIdResolver.class.getName());

private static final DotName JSON_SUBTYPES = DotName.createSimple(JsonSubTypes.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");
Expand All @@ -98,6 +99,7 @@ public class JacksonProcessor {
// this list can probably be enriched with more modules
private static final List<String> MODULES_NAMES_TO_AUTO_REGISTER = Arrays.asList(TIME_MODULE, JDK8_MODULE,
PARAMETER_NAMES_MODULE);
private static final String[] EMPTY_STRING = new String[0];

@Inject
CombinedIndexBuildItem combinedIndexBuildItem;
Expand Down Expand Up @@ -271,6 +273,25 @@ void register(
}
}

// register @JsonSubTypes.Type values for reflection
Set<String> subTypeTypesNames = new HashSet<>();
for (AnnotationInstance subTypeInstance : index.getAnnotations(JSON_SUBTYPES)) {
AnnotationValue subTypeValue = subTypeInstance.value();
if (subTypeValue != null) {
for (AnnotationInstance subTypeTypeInstance : subTypeValue.asNestedArray()) {
AnnotationValue subTypeTypeValue = subTypeTypeInstance.value();
if (subTypeTypeValue != null) {
subTypeTypesNames.add(subTypeTypeValue.asClass().name().toString());
}
}

}
}
if (!subTypeTypesNames.isEmpty()) {
reflectiveClass.produce(ReflectiveClassBuildItem.builder(subTypeTypesNames.toArray(EMPTY_STRING))
.methods().fields().build());
}

// this needs to be registered manually since the runtime module is not indexed by Jandex
additionalBeans.produce(new AdditionalBeanBuildItem(ObjectMapperProducer.class));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.quarkus.it.jackson;

import java.util.List;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import io.quarkus.it.jackson.model.Elephant;
import io.quarkus.it.jackson.model.MammalFamily;
import io.quarkus.it.jackson.model.Whale;

@Path("jsonSubTypes")
public class JsonSubTypesResource {

private final ObjectMapper objectMapper;

public JsonSubTypesResource(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}

@GET
public String test() throws JsonProcessingException {
return objectMapper.writeValueAsString(new MammalFamily(List.of(
new Whale(30.0, "white"), new Elephant(10, "africa"))));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.quarkus.it.jackson.model;

public record Elephant(
int hornLength, String continent) implements Mammal {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.quarkus.it.jackson.model;

import static com.fasterxml.jackson.annotation.JsonTypeInfo.As.PROPERTY;
import static com.fasterxml.jackson.annotation.JsonTypeInfo.Id.NAME;

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

@JsonTypeInfo(use = NAME, include = PROPERTY)
@JsonSubTypes({
@JsonSubTypes.Type(value = Elephant.class, name = "Elephant"),
@JsonSubTypes.Type(value = Whale.class, name = "Whale"),
})
public interface Mammal {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.quarkus.it.jackson.model;

import java.util.Collection;

import io.quarkus.runtime.annotations.RegisterForReflection;

@RegisterForReflection
public record MammalFamily(Collection<Mammal> mammals) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.quarkus.it.jackson.model;

public record Whale(
double swimSpeed, String color) implements Mammal {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.quarkus.it.jackson;

import io.quarkus.test.junit.QuarkusIntegrationTest;

@QuarkusIntegrationTest
public class JsonSubTypesResourceIT extends JsonSubTypesResourceTest {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.quarkus.it.jackson;

import static io.restassured.RestAssured.given;
import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;

import io.quarkus.test.junit.QuarkusTest;
import io.restassured.http.ContentType;
import io.restassured.response.Response;

@QuarkusTest
class JsonSubTypesResourceTest {

@Test
void test() {
Response response = given()
.accept(ContentType.JSON)
.when()
.get("jsonSubTypes")
.then()
.statusCode(200)
.extract().response();
assertThat(response.jsonPath().getString("mammals[0].color")).isEqualTo("white");
assertThat(response.jsonPath().getString("mammals[1].continent")).isEqualTo("africa");
}
}

0 comments on commit d98da34

Please sign in to comment.