more work on [#120], now Map type
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java
index 5f8e332..261ffc8 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java
@@ -827,26 +827,6 @@
return deser;
}
- // Copied almost verbatim from "createCollectionDeserializer" -- should try to share more code
- @Override
- public JsonDeserializer<?> createCollectionLikeDeserializer(DeserializationContext ctxt,
- CollectionLikeType type, final BeanDescription beanDesc)
- throws JsonMappingException
- {
- JavaType contentType = type.getContentType();
- // Very first thing: is deserializer hard-coded for elements?
- JsonDeserializer<Object> contentDeser = contentType.getValueHandler();
-
- // Then optional type info (1.5): if type has been resolved, we may already know type deserializer:
- TypeDeserializer contentTypeDeser = contentType.getTypeHandler();
- // but if not, may still be possible to find:
- if (contentTypeDeser == null) {
- contentTypeDeser = findTypeDeserializer(ctxt.getConfig(), contentType);
- }
- return _findCustomCollectionLikeDeserializer(type, ctxt.getConfig(), beanDesc,
- contentTypeDeser, contentDeser);
- }
-
protected JsonDeserializer<?> _findCustomCollectionDeserializer(CollectionType type,
DeserializationConfig config, BeanDescription beanDesc,
TypeDeserializer elementTypeDeserializer, JsonDeserializer<?> elementDeserializer)
@@ -861,6 +841,36 @@
}
return null;
}
+
+ // Copied almost verbatim from "createCollectionDeserializer" -- should try to share more code
+ @Override
+ public JsonDeserializer<?> createCollectionLikeDeserializer(DeserializationContext ctxt,
+ CollectionLikeType type, final BeanDescription beanDesc)
+ throws JsonMappingException
+ {
+ JavaType contentType = type.getContentType();
+ // Very first thing: is deserializer hard-coded for elements?
+ JsonDeserializer<Object> contentDeser = contentType.getValueHandler();
+ final DeserializationConfig config = ctxt.getConfig();
+
+ // Then optional type info (1.5): if type has been resolved, we may already know type deserializer:
+ TypeDeserializer contentTypeDeser = contentType.getTypeHandler();
+ // but if not, may still be possible to find:
+ if (contentTypeDeser == null) {
+ contentTypeDeser = findTypeDeserializer(config, contentType);
+ }
+ JsonDeserializer<?> deser = _findCustomCollectionLikeDeserializer(type, config, beanDesc,
+ contentTypeDeser, contentDeser);
+ if (deser != null) {
+ // and then new with 2.2: ability to post-process it too (Issue#120)
+ if (_factoryConfig.hasDeserializerModifiers()) {
+ for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
+ deser = mod.modifyCollectionLikeDeserializer(config, type, beanDesc, deser);
+ }
+ }
+ }
+ return deser;
+ }
protected JsonDeserializer<?> _findCustomCollectionLikeDeserializer(CollectionLikeType type,
DeserializationConfig config, BeanDescription beanDesc,
@@ -906,48 +916,56 @@
}
// 23-Nov-2010, tatu: Custom deserializer?
- JsonDeserializer<?> custom = _findCustomMapDeserializer(type, config, beanDesc,
+ JsonDeserializer<?> deser = _findCustomMapDeserializer(type, config, beanDesc,
keyDes, contentTypeDeser, contentDeser);
- if (custom != null) {
- return custom;
- }
- // Value handling is identical for all, but EnumMap requires special handling for keys
- Class<?> mapClass = type.getRawClass();
- if (EnumMap.class.isAssignableFrom(mapClass)) {
- Class<?> kt = keyType.getRawClass();
- if (kt == null || !kt.isEnum()) {
- throw new IllegalArgumentException("Can not construct EnumMap; generic (key) type not available");
+ if (deser == null) {
+ // Value handling is identical for all, but EnumMap requires special handling for keys
+ Class<?> mapClass = type.getRawClass();
+ if (EnumMap.class.isAssignableFrom(mapClass)) {
+ Class<?> kt = keyType.getRawClass();
+ if (kt == null || !kt.isEnum()) {
+ throw new IllegalArgumentException("Can not construct EnumMap; generic (key) type not available");
+ }
+ deser = new EnumMapDeserializer(type, null, contentDeser);
}
- return new EnumMapDeserializer(type, null, contentDeser);
- }
- // Otherwise, generic handler works ok.
-
- /* But there is one more twist: if we are being asked to instantiate
- * an interface or abstract Map, we need to either find something
- * that implements the thing, or give up.
- *
- * Note that we do NOT try to guess based on secondary interfaces
- * here; that would probably not work correctly since casts would
- * fail later on (as the primary type is not the interface we'd
- * be implementing)
- */
- if (type.isInterface() || type.isAbstract()) {
- @SuppressWarnings("rawtypes")
- Class<? extends Map> fallback = _mapFallbacks.get(mapClass.getName());
- if (fallback == null) {
- throw new IllegalArgumentException("Can not find a deserializer for non-concrete Map type "+type);
+ // Otherwise, generic handler works ok.
+
+ /* But there is one more twist: if we are being asked to instantiate
+ * an interface or abstract Map, we need to either find something
+ * that implements the thing, or give up.
+ *
+ * Note that we do NOT try to guess based on secondary interfaces
+ * here; that would probably not work correctly since casts would
+ * fail later on (as the primary type is not the interface we'd
+ * be implementing)
+ */
+ if (deser == null) {
+ if (type.isInterface() || type.isAbstract()) {
+ @SuppressWarnings("rawtypes")
+ Class<? extends Map> fallback = _mapFallbacks.get(mapClass.getName());
+ if (fallback == null) {
+ throw new IllegalArgumentException("Can not find a deserializer for non-concrete Map type "+type);
+ }
+ mapClass = fallback;
+ type = (MapType) config.constructSpecializedType(type, mapClass);
+ // But if so, also need to re-check creators...
+ beanDesc = config.introspectForCreation(type);
+ }
+ ValueInstantiator inst = findValueInstantiator(ctxt, beanDesc);
+ MapDeserializer md = new MapDeserializer(type, inst, keyDes, contentDeser, contentTypeDeser);
+ md.setIgnorableProperties(config.getAnnotationIntrospector().findPropertiesToIgnore(beanDesc.getClassInfo()));
+ deser = md;
}
- mapClass = fallback;
- type = (MapType) config.constructSpecializedType(type, mapClass);
- // But if so, also need to re-check creators...
- beanDesc = config.introspectForCreation(type);
}
- ValueInstantiator inst = findValueInstantiator(ctxt, beanDesc);
- MapDeserializer md = new MapDeserializer(type, inst, keyDes, contentDeser, contentTypeDeser);
- md.setIgnorableProperties(config.getAnnotationIntrospector().findPropertiesToIgnore(beanDesc.getClassInfo()));
- return md;
+ // and then new with 2.2: ability to post-process it too (Issue#120)
+ if (_factoryConfig.hasDeserializerModifiers()) {
+ for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
+ deser = mod.modifyMapDeserializer(config, type, beanDesc, deser);
+ }
+ }
+ return deser;
}
// Copied almost verbatim from "createMapDeserializer" -- should try to share more code
@@ -958,6 +976,7 @@
{
JavaType keyType = type.getKeyType();
JavaType contentType = type.getContentType();
+ final DeserializationConfig config = ctxt.getConfig();
// First: is there annotation-specified deserializer for values?
@SuppressWarnings("unchecked")
@@ -974,10 +993,19 @@
TypeDeserializer contentTypeDeser = contentType.getTypeHandler();
// but if not, may still be possible to find:
if (contentTypeDeser == null) {
- contentTypeDeser = findTypeDeserializer(ctxt.getConfig(), contentType);
+ contentTypeDeser = findTypeDeserializer(config, contentType);
}
- return _findCustomMapLikeDeserializer(type, ctxt.getConfig(),
+ JsonDeserializer<?> deser = _findCustomMapLikeDeserializer(type, config,
beanDesc, keyDes, contentTypeDeser, contentDeser);
+ if (deser != null) {
+ // and then new with 2.2: ability to post-process it too (Issue#120)
+ if (_factoryConfig.hasDeserializerModifiers()) {
+ for (BeanDeserializerModifier mod : _factoryConfig.deserializerModifiers()) {
+ deser = mod.modifyMapLikeDeserializer(config, type, beanDesc, deser);
+ }
+ }
+ }
+ return deser;
}
protected JsonDeserializer<?> _findCustomMapDeserializer(MapType type,
diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerModifier.java b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerModifier.java
index 759ee12..08be681 100644
--- a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerModifier.java
+++ b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerModifier.java
@@ -130,6 +130,22 @@
CollectionLikeType type, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
return deserializer;
}
+
+ /**
+ * @since 2.2
+ */
+ public JsonDeserializer<?> modifyMapDeserializer(DeserializationConfig config,
+ MapType type, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
+ return deserializer;
+ }
+
+ /**
+ * @since 2.2
+ */
+ public JsonDeserializer<?> modifyMapLikeDeserializer(DeserializationConfig config,
+ MapLikeType type, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
+ return deserializer;
+ }
/*
@@ -137,14 +153,6 @@
JavaType type, BeanDescription beanDesc)
throws JsonMappingException;
- public abstract JsonDeserializer<?> createMapDeserializer(DeserializationContext ctxt,
- MapType type, BeanDescription beanDesc)
- throws JsonMappingException;
-
- public abstract JsonDeserializer<?> createMapLikeDeserializer(DeserializationContext ctxt,
- MapLikeType type, BeanDescription beanDesc)
- throws JsonMappingException;
-
public abstract KeyDeserializer createKeyDeserializer(DeserializationContext ctxt,
JavaType type)
throws JsonMappingException;
diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/TestBeanDeserializer.java b/src/test/java/com/fasterxml/jackson/databind/deser/TestBeanDeserializer.java
index 0af98cb..c85ee72 100644
--- a/src/test/java/com/fasterxml/jackson/databind/deser/TestBeanDeserializer.java
+++ b/src/test/java/com/fasterxml/jackson/databind/deser/TestBeanDeserializer.java
@@ -12,6 +12,7 @@
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.ArrayType;
import com.fasterxml.jackson.databind.type.CollectionType;
+import com.fasterxml.jackson.databind.type.MapType;
@SuppressWarnings("serial")
public class TestBeanDeserializer extends BaseMapTest
@@ -169,6 +170,20 @@
};
}
}
+
+ static class MapDeserializerModifier extends BeanDeserializerModifier {
+ public JsonDeserializer<?> modifyMapDeserializer(DeserializationConfig config, MapType valueType,
+ BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
+ return (JsonDeserializer<?>) new StdDeserializer<Object>(Object.class) {
+ @Override public Object deserialize(JsonParser jp,
+ DeserializationContext ctxt) {
+ HashMap<String,String> map = new HashMap<String,String>();
+ map.put("a", "foo");
+ return map;
+ }
+ };
+ }
+ }
/*
/********************************************************
@@ -247,4 +262,15 @@
assertEquals(1, result.size());
assertEquals("foo", result.get(0));
}
+
+ public void testModifyMapDeserializer() throws Exception
+ {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.registerModule(new SimpleModule("test")
+ .setDeserializerModifier(new MapDeserializerModifier())
+ );
+ Map<?,?> result = mapper.readValue("{\"a\":1,\"b\":2}", Map.class);
+ assertEquals(1, result.size());
+ assertEquals("foo", result.get("a"));
+ }
}