Skip to content

Commit f518ad9

Browse files
committed
Add (de)serializerByType() and mixIn() to Jackson2ObjectMapperBuilder
Issue: SPR-12313
1 parent 25bb58a commit f518ad9

File tree

2 files changed

+96
-23
lines changed

2 files changed

+96
-23
lines changed

spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,18 @@ public Jackson2ObjectMapperBuilder serializers(JsonSerializer<?>... serializers)
172172
return this;
173173
}
174174

175+
/**
176+
* Configure a custom serializer for the given type.
177+
* @see #serializers(JsonSerializer...)
178+
* @since 4.1.2
179+
*/
180+
public Jackson2ObjectMapperBuilder serializerByType(Class<?> type, JsonSerializer<?> serializer) {
181+
if (serializers != null) {
182+
this.serializers.put(type, serializer);
183+
}
184+
return this;
185+
}
186+
175187
/**
176188
* Configure custom serializers for the given types.
177189
* @see #serializers(JsonSerializer...)
@@ -183,6 +195,17 @@ public Jackson2ObjectMapperBuilder serializersByType(Map<Class<?>, JsonSerialize
183195
return this;
184196
}
185197

198+
/**
199+
* Configure a custom deserializer for the given type.
200+
* @since 4.1.2
201+
*/
202+
public Jackson2ObjectMapperBuilder deserializerByType(Class<?> type, JsonDeserializer<?> deserializer) {
203+
if (deserializers != null) {
204+
this.deserializers.put(type, deserializer);
205+
}
206+
return this;
207+
}
208+
186209
/**
187210
* Configure custom deserializers for the given types.
188211
*/
@@ -193,6 +216,21 @@ public Jackson2ObjectMapperBuilder deserializersByType(Map<Class<?>, JsonDeseria
193216
return this;
194217
}
195218

219+
/**
220+
* Add mix-in annotations to use for augmenting specified class or interface.
221+
* @param target class (or interface) whose annotations to effectively override
222+
* @param mixinSource class (or interface) whose annotations are to be "added"
223+
* to target's annotations as value
224+
* @since 4.1.2
225+
* @see com.fasterxml.jackson.databind.ObjectMapper#addMixInAnnotations(Class, Class)
226+
*/
227+
public Jackson2ObjectMapperBuilder mixIn(Class<?> target, Class<?> mixinSource) {
228+
if (mixIns != null) {
229+
this.mixIns.put(target, mixinSource);
230+
}
231+
return this;
232+
}
233+
196234
/**
197235
* Add mix-in annotations to use for augmenting specified class or interface.
198236
* @param mixIns Map of entries with target classes (or interface) whose annotations

spring-web/src/test/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilderTests.java

Lines changed: 58 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.fasterxml.jackson.core.JsonParser;
2929
import com.fasterxml.jackson.databind.DeserializationFeature;
3030
import com.fasterxml.jackson.databind.JsonDeserializer;
31+
import com.fasterxml.jackson.databind.JsonMappingException;
3132
import com.fasterxml.jackson.databind.JsonSerializer;
3233
import com.fasterxml.jackson.databind.MapperFeature;
3334
import com.fasterxml.jackson.databind.Module;
@@ -37,6 +38,7 @@
3738
import com.fasterxml.jackson.databind.cfg.DeserializerFactoryConfig;
3839
import com.fasterxml.jackson.databind.cfg.SerializerFactoryConfig;
3940
import com.fasterxml.jackson.databind.deser.BasicDeserializerFactory;
41+
import com.fasterxml.jackson.databind.deser.Deserializers;
4042
import com.fasterxml.jackson.databind.deser.std.DateDeserializers;
4143
import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector;
4244
import com.fasterxml.jackson.databind.module.SimpleModule;
@@ -190,46 +192,76 @@ public void propertyNamingStrategy() {
190192
assertSame(strategy, objectMapper.getDeserializationConfig().getPropertyNamingStrategy());
191193
}
192194

195+
@Test
196+
public void serializerByType() {
197+
JsonSerializer<Number> serializer = new NumberSerializer();
198+
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json()
199+
.serializerByType(Boolean.class, serializer).build();
200+
assertTrue(getSerializerFactoryConfig(objectMapper).hasSerializers());
201+
Serializers serializers = getSerializerFactoryConfig(objectMapper).serializers().iterator().next();
202+
assertTrue(serializers.findSerializer(null, SimpleType.construct(Boolean.class), null) == serializer);
203+
}
204+
205+
@Test
206+
public void deserializerByType() throws JsonMappingException {
207+
JsonDeserializer<Date> deserializer = new DateDeserializers.DateDeserializer();
208+
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json()
209+
.deserializerByType(Date.class, deserializer).build();
210+
assertTrue(getDeserializerFactoryConfig(objectMapper).hasDeserializers());
211+
Deserializers deserializers = getDeserializerFactoryConfig(objectMapper).deserializers().iterator().next();
212+
assertTrue(deserializers.findBeanDeserializer(SimpleType.construct(Date.class), null, null) == deserializer);
213+
}
214+
215+
@Test
216+
public void mixIn() {
217+
Class<?> target = String.class;
218+
Class<?> mixInSource = Object.class;
219+
220+
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().mixIn(target,
221+
mixInSource).build();
222+
223+
assertEquals(1, objectMapper.mixInCount());
224+
assertSame(mixInSource, objectMapper.findMixInClassFor(target));
225+
}
226+
193227
@Test
194228
public void mixIns() {
195229
Class<?> target = String.class;
196-
Class<?> mixinSource = Object.class;
230+
Class<?> mixInSource = Object.class;
197231
Map<Class<?>, Class<?>> mixIns = new HashMap<Class<?>, Class<?>>();
198-
mixIns.put(target, mixinSource);
232+
mixIns.put(target, mixInSource);
199233

200234
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().mixIns(mixIns).build();
201235

202236
assertEquals(1, objectMapper.mixInCount());
203-
assertSame(mixinSource, objectMapper.findMixInClassFor(target));
237+
assertSame(mixInSource, objectMapper.findMixInClassFor(target));
204238
}
205239

206240
@Test
207-
public void completeSetup() {
241+
public void completeSetup() throws JsonMappingException {
208242
NopAnnotationIntrospector annotationIntrospector = NopAnnotationIntrospector.instance;
209243

210-
Map<Class<?>, JsonDeserializer<?>> deserializers = new HashMap<Class<?>, JsonDeserializer<?>>();
211-
deserializers.put(Date.class, new DateDeserializers.DateDeserializer());
244+
Map<Class<?>, JsonDeserializer<?>> deserializerMap = new HashMap<Class<?>, JsonDeserializer<?>>();
245+
JsonDeserializer<Date> deserializer = new DateDeserializers.DateDeserializer();
246+
deserializerMap.put(Date.class, deserializer);
212247

213248
JsonSerializer<Class<?>> serializer1 = new ClassSerializer();
214249
JsonSerializer<Number> serializer2 = new NumberSerializer();
215250

216-
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
217-
218-
builder.serializers(serializer1);
219-
builder.serializersByType(Collections.<Class<?>, JsonSerializer<?>>singletonMap(Boolean.class, serializer2));
220-
builder.deserializersByType(deserializers);
221-
builder.annotationIntrospector(annotationIntrospector);
222-
223-
builder.featuresToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS,
224-
DeserializationFeature.UNWRAP_ROOT_VALUE,
225-
JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER,
226-
JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS);
227-
228-
builder.featuresToDisable(MapperFeature.AUTO_DETECT_GETTERS,
229-
MapperFeature.AUTO_DETECT_FIELDS, JsonParser.Feature.AUTO_CLOSE_SOURCE,
230-
JsonGenerator.Feature.QUOTE_FIELD_NAMES);
231-
232-
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
251+
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json()
252+
.serializers(serializer1)
253+
.serializersByType(Collections.<Class<?>, JsonSerializer<?>>singletonMap(Boolean.class, serializer2))
254+
.deserializersByType(deserializerMap)
255+
.annotationIntrospector(annotationIntrospector)
256+
.featuresToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS,
257+
DeserializationFeature.UNWRAP_ROOT_VALUE,
258+
JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER,
259+
JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS)
260+
.featuresToDisable(MapperFeature.AUTO_DETECT_GETTERS,
261+
MapperFeature.AUTO_DETECT_FIELDS,
262+
JsonParser.Feature.AUTO_CLOSE_SOURCE,
263+
JsonGenerator.Feature.QUOTE_FIELD_NAMES)
264+
.serializationInclusion(JsonInclude.Include.NON_NULL);
233265

234266
ObjectMapper objectMapper = new ObjectMapper();
235267
builder.configure(objectMapper);
@@ -242,6 +274,9 @@ public void completeSetup() {
242274
assertTrue(serializers.findSerializer(null, SimpleType.construct(Boolean.class), null) == serializer2);
243275
assertNull(serializers.findSerializer(null, SimpleType.construct(Number.class), null));
244276

277+
Deserializers deserializers = getDeserializerFactoryConfig(objectMapper).deserializers().iterator().next();
278+
assertTrue(deserializers.findBeanDeserializer(SimpleType.construct(Date.class), null, null) == deserializer);
279+
245280
assertTrue(annotationIntrospector == objectMapper.getSerializationConfig().getAnnotationIntrospector());
246281
assertTrue(annotationIntrospector == objectMapper.getDeserializationConfig().getAnnotationIntrospector());
247282

0 commit comments

Comments
 (0)