Skip to content

Commit

Permalink
Merge pull request #40819 from FWest98/fw/defaultmappercustomizer
Browse files Browse the repository at this point in the history
Move standard `ObjectMapper` customization to dedicated Customizer
  • Loading branch information
geoand authored May 31, 2024
2 parents 433856f + 5e259f1 commit 7c51431
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import io.quarkus.gizmo.ResultHandle;
import io.quarkus.jackson.JacksonMixin;
import io.quarkus.jackson.ObjectMapperCustomizer;
import io.quarkus.jackson.runtime.ConfigurationCustomizer;
import io.quarkus.jackson.runtime.JacksonBuildTimeConfig;
import io.quarkus.jackson.runtime.JacksonSupport;
import io.quarkus.jackson.runtime.JacksonSupportRecorder;
Expand Down Expand Up @@ -111,6 +112,8 @@ public class JacksonProcessor {
@BuildStep
void unremovable(Capabilities capabilities, BuildProducer<UnremovableBeanBuildItem> producer,
BuildProducer<AdditionalBeanBuildItem> additionalProducer) {
additionalProducer.produce(AdditionalBeanBuildItem.unremovableOf(ConfigurationCustomizer.class));

if (capabilities.isPresent(Capability.VERTX_CORE)) {
producer.produce(UnremovableBeanBuildItem.beanTypes(ObjectMapper.class));
additionalProducer.produce(AdditionalBeanBuildItem.unremovableOf(VertxHybridPoolObjectMapperCustomizer.class));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
public interface ObjectMapperCustomizer extends Comparable<ObjectMapperCustomizer> {

int MINIMUM_PRIORITY = Integer.MIN_VALUE;
int MAXIMUM_PRIORITY = Integer.MAX_VALUE;
// we use this priority to give a chance to other customizers to override serializers / deserializers
// that might have been added by the modules that Quarkus registers automatically
// (Jackson will keep the last registered serializer / deserializer for a given type
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package io.quarkus.jackson.runtime;

import java.time.ZoneId;
import java.util.TimeZone;

import jakarta.inject.Inject;
import jakarta.inject.Singleton;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import io.quarkus.jackson.ObjectMapperCustomizer;

@Singleton
public class ConfigurationCustomizer implements ObjectMapperCustomizer {
@Inject
JacksonBuildTimeConfig jacksonBuildTimeConfig;

@Inject
JacksonSupport jacksonSupport;

@Override
public void customize(ObjectMapper objectMapper) {
if (!jacksonBuildTimeConfig.failOnUnknownProperties) {
// this feature is enabled by default, so we disable it
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
}
if (!jacksonBuildTimeConfig.failOnEmptyBeans) {
// this feature is enabled by default, so we disable it
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
}
if (!jacksonBuildTimeConfig.writeDatesAsTimestamps) {
// this feature is enabled by default, so we disable it
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
if (!jacksonBuildTimeConfig.writeDurationsAsTimestamps) {
// this feature is enabled by default, so we disable it
objectMapper.disable(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS);
}
if (jacksonBuildTimeConfig.acceptCaseInsensitiveEnums) {
objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);
}
JsonInclude.Include serializationInclusion = jacksonBuildTimeConfig.serializationInclusion.orElse(null);
if (serializationInclusion != null) {
objectMapper.setSerializationInclusion(serializationInclusion);
}
ZoneId zoneId = jacksonBuildTimeConfig.timezone.orElse(null);
if ((zoneId != null) && !zoneId.getId().equals("UTC")) { // Jackson uses UTC as the default, so let's not reset it
objectMapper.setTimeZone(TimeZone.getTimeZone(zoneId));
}
if (jacksonSupport.configuredNamingStrategy().isPresent()) {
objectMapper.setPropertyNamingStrategy(jacksonSupport.configuredNamingStrategy().get());
}
}

@Override
public int priority() {
// we return the maximum possible priority to make sure these
// settings are always applied first, before any other customizers.
return ObjectMapperCustomizer.MAXIMUM_PRIORITY;
}
}
Original file line number Diff line number Diff line change
@@ -1,64 +1,27 @@
package io.quarkus.jackson.runtime;

import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.TimeZone;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Produces;
import jakarta.inject.Singleton;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import io.quarkus.arc.All;
import io.quarkus.arc.DefaultBean;
import io.quarkus.jackson.ObjectMapperCustomizer;

@ApplicationScoped
public class ObjectMapperProducer {

@DefaultBean
@Singleton
@Produces
public ObjectMapper objectMapper(@All List<ObjectMapperCustomizer> customizers,
JacksonBuildTimeConfig jacksonBuildTimeConfig, JacksonSupport jacksonSupport) {
ObjectMapper objectMapper = new ObjectMapper();
if (!jacksonBuildTimeConfig.failOnUnknownProperties) {
// this feature is enabled by default, so we disable it
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
}
if (!jacksonBuildTimeConfig.failOnEmptyBeans) {
// this feature is enabled by default, so we disable it
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
}
if (!jacksonBuildTimeConfig.writeDatesAsTimestamps) {
// this feature is enabled by default, so we disable it
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
if (!jacksonBuildTimeConfig.writeDurationsAsTimestamps) {
// this feature is enabled by default, so we disable it
objectMapper.disable(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS);
}
if (jacksonBuildTimeConfig.acceptCaseInsensitiveEnums) {
objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);
}
JsonInclude.Include serializationInclusion = jacksonBuildTimeConfig.serializationInclusion.orElse(null);
if (serializationInclusion != null) {
objectMapper.setSerializationInclusion(serializationInclusion);
}
ZoneId zoneId = jacksonBuildTimeConfig.timezone.orElse(null);
if ((zoneId != null) && !zoneId.getId().equals("UTC")) { // Jackson uses UTC as the default, so let's not reset it
objectMapper.setTimeZone(TimeZone.getTimeZone(zoneId));
}
if (jacksonSupport.configuredNamingStrategy().isPresent()) {
objectMapper.setPropertyNamingStrategy(jacksonSupport.configuredNamingStrategy().get());
}
List<ObjectMapperCustomizer> sortedCustomizers = sortCustomizersInDescendingPriorityOrder(customizers);
for (ObjectMapperCustomizer customizer : sortedCustomizers) {
customizer.customize(objectMapper);
Expand Down

0 comments on commit 7c51431

Please sign in to comment.