Skip to content

Commit

Permalink
Merge pull request quarkusio#7142 from geoand/quarkusio#7116
Browse files Browse the repository at this point in the history
Ensure that user provided ObjectMapperCustomizer objects always have higher priority
  • Loading branch information
geoand authored Feb 11, 2020
2 parents 8d9665a + fe27eb7 commit a3bab8c
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,11 @@ void generateCustomizer(BuildProducer<GeneratedBeanBuildItem> generatedBeans,

customize.returnValue(null);
}

// ensure that the things we auto-register have the lower priority - this ensures that user registered modules take priority
try (MethodCreator priority = classCreator.getMethodCreator("priority", int.class)) {
priority.returnValue(priority.load(ObjectMapperCustomizer.MINIMUM_PRIORITY));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,22 @@
* <p>
* See also {@link ObjectMapperProducer#objectMapper}.
*/
public interface ObjectMapperCustomizer {
public interface ObjectMapperCustomizer extends Comparable<ObjectMapperCustomizer> {

int MINIMUM_PRIORITY = Integer.MIN_VALUE;
int DEFAULT_PRIORITY = 0;

void customize(ObjectMapper objectMapper);

/**
* Defines the priority that the customizers are applied.
* A lower integer value means that the customizer will be applied after a customizer with a higher priority
*/
default int priority() {
return DEFAULT_PRIORITY;
}

default int compareTo(ObjectMapperCustomizer o) {
return Integer.compare(o.priority(), priority());
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package io.quarkus.jackson;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Instance;
import javax.enterprise.inject.Produces;
Expand All @@ -17,9 +21,20 @@ public class ObjectMapperProducer {
@Produces
public ObjectMapper objectMapper(Instance<ObjectMapperCustomizer> customizers) {
ObjectMapper objectMapper = new ObjectMapper();
for (ObjectMapperCustomizer customizer : customizers) {
List<ObjectMapperCustomizer> sortedCustomizers = sortCustomizersInDescendingPriorityOrder(customizers);
for (ObjectMapperCustomizer customizer : sortedCustomizers) {
customizer.customize(objectMapper);
}
return objectMapper;
}

private List<ObjectMapperCustomizer> sortCustomizersInDescendingPriorityOrder(
Instance<ObjectMapperCustomizer> customizers) {
List<ObjectMapperCustomizer> sortedCustomizers = new ArrayList<>();
for (ObjectMapperCustomizer customizer : customizers) {
sortedCustomizers.add(customizer);
}
Collections.sort(sortedCustomizers);
return sortedCustomizers;
}
}
10 changes: 10 additions & 0 deletions extensions/resteasy-jackson/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-internal</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.quarkus.resteasy.jackson;

import java.time.ZonedDateTime;

import com.fasterxml.jackson.annotation.JsonProperty;

public class DateDto {
@JsonProperty("current_date")
private ZonedDateTime currentDate;

public void setCurrentDate(ZonedDateTime currentDate) {
this.currentDate = currentDate;
}

public ZonedDateTime getCurrentDate() {
return currentDate;
}

public DateDto(ZonedDateTime currentDate) {
this.currentDate = currentDate;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.quarkus.resteasy.jackson;

import java.time.ZonedDateTime;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Produces(MediaType.APPLICATION_JSON)
@Path("/hello")
public class HelloResource {

@GET
public DateDto hello() {
return new DateDto(ZonedDateTime.now());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package io.quarkus.resteasy.jackson;

import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.test.QuarkusDevModeTest;
import io.restassured.RestAssured;

// this test really belongs in the jackson module, but it's been added here to avoid test classpath issues
public class MultipleTimeModuleTest {

@RegisterExtension
static QuarkusDevModeTest TEST = new QuarkusDevModeTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addClasses(TimeCustomizer.class, DateDto.class, HelloResource.class));

@Test
public void testDateIsAlwaysInTheExpectedFormat() {
verifyExpectedResult();

modifyResource();
verifyExpectedResult();

modifyResource();
verifyExpectedResult();

modifyResource();
verifyExpectedResult();
}

private void verifyExpectedResult() {
RestAssured.get("/hello").then()
.statusCode(200)
.body(containsString("Z"), not(containsString("+")));
}

private void modifyResource() {
TEST.modifySourceFile("TimeCustomizer.java", s -> s.replace("hello",
"hello2"));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.quarkus.resteasy.jackson;

import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatterBuilder;

import javax.inject.Singleton;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.ser.ZonedDateTimeSerializer;

import io.quarkus.jackson.ObjectMapperCustomizer;

@Singleton
public class TimeCustomizer implements ObjectMapperCustomizer {

@Override
public void customize(ObjectMapper objectMapper) {
JavaTimeModule customDateModule = new JavaTimeModule();
customDateModule.addSerializer(ZonedDateTime.class, new ZonedDateTimeSerializer(
new DateTimeFormatterBuilder().appendInstant(0).toFormatter().withZone(ZoneId.of("Z"))));
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.registerModule(customDateModule);
}
}

0 comments on commit a3bab8c

Please sign in to comment.