diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java index 4709aef1db..e0862b3342 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.TimeZone; +import java.util.function.Function; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonFilter; @@ -45,6 +46,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategy; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.cfg.HandlerInstantiator; +import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair; import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.FilterProvider; @@ -260,6 +262,23 @@ public class Jackson2ObjectMapperBuilder { return this; } + /** + * Alternative to {@link #annotationIntrospector(AnnotationIntrospector)} + * that allows combining with rather than replacing the currently set + * introspector, e.g. via + * {@link AnnotationIntrospectorPair#pair(AnnotationIntrospector, AnnotationIntrospector)}. + * @param pairingFunction a function to apply to the currently set + * introspector (possibly {@code null}); the result of the function becomes + * the new introspector. + * @since 5.2.4 + */ + public Jackson2ObjectMapperBuilder annotationIntrospector( + Function pairingFunction) { + + this.annotationIntrospector = pairingFunction.apply(this.annotationIntrospector); + return this; + } + /** * Specify a {@link com.fasterxml.jackson.databind.PropertyNamingStrategy} to * configure the {@link ObjectMapper} with. diff --git a/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java b/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java index 6abfffe527..46e6a75c02 100644 --- a/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java +++ b/spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,6 +43,7 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.Version; +import com.fasterxml.jackson.databind.AnnotationIntrospector; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonDeserializer; @@ -60,6 +61,7 @@ import com.fasterxml.jackson.databind.cfg.SerializerFactoryConfig; import com.fasterxml.jackson.databind.deser.BasicDeserializerFactory; import com.fasterxml.jackson.databind.deser.Deserializers; import com.fasterxml.jackson.databind.deser.std.DateDeserializers; +import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair; import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.module.SimpleSerializers; @@ -431,7 +433,7 @@ public class Jackson2ObjectMapperBuilderTests { @Test public void completeSetup() throws JsonMappingException { - NopAnnotationIntrospector annotationIntrospector = NopAnnotationIntrospector.instance; + NopAnnotationIntrospector introspector = NopAnnotationIntrospector.instance; Map, JsonDeserializer> deserializerMap = new HashMap<>(); JsonDeserializer deserializer = new DateDeserializers.DateDeserializer(); @@ -445,7 +447,8 @@ public class Jackson2ObjectMapperBuilderTests { .serializers(serializer1) .serializersByType(Collections.singletonMap(Boolean.class, serializer2)) .deserializersByType(deserializerMap) - .annotationIntrospector(annotationIntrospector) + .annotationIntrospector(introspector) + .annotationIntrospector(current -> AnnotationIntrospector.pair(current, introspector)) .featuresToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS, DeserializationFeature.UNWRAP_ROOT_VALUE, JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, @@ -470,8 +473,13 @@ public class Jackson2ObjectMapperBuilderTests { Deserializers deserializers = getDeserializerFactoryConfig(mapper).deserializers().iterator().next(); assertThat(deserializers.findBeanDeserializer(SimpleType.construct(Date.class), null, null)).isSameAs(deserializer); - assertThat(mapper.getSerializationConfig().getAnnotationIntrospector()).isSameAs(annotationIntrospector); - assertThat(mapper.getDeserializationConfig().getAnnotationIntrospector()).isSameAs(annotationIntrospector); + AnnotationIntrospectorPair pair1 = + (AnnotationIntrospectorPair) mapper.getSerializationConfig().getAnnotationIntrospector(); + AnnotationIntrospectorPair pair2 = + (AnnotationIntrospectorPair) mapper.getDeserializationConfig().getAnnotationIntrospector(); + + assertThat(pair1.allIntrospectors()).containsExactly(introspector, introspector); + assertThat(pair2.allIntrospectors()).containsExactly(introspector, introspector); assertThat(mapper.getSerializationConfig().isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS)).isTrue(); assertThat(mapper.getDeserializationConfig().isEnabled(DeserializationFeature.UNWRAP_ROOT_VALUE)).isTrue();