yet more work on [JACKSON-756]
diff --git a/release-notes/CREDITS b/release-notes/CREDITS
index 1120544..39c108a 100644
--- a/release-notes/CREDITS
+++ b/release-notes/CREDITS
@@ -849,3 +849,8 @@
Stephan Bailliez:
* Reported [JACKSON-757] Problems with Enum values, annotations on constructors
[1.9.4]
+
+Mika Mannermaa:
+ * Reported [JACKSON-756] Problems with enums, @JsonCreator, when used as keys
+ of EnumMap, regular Map, or contents of EnumSet
+ [1.9.4]
diff --git a/release-notes/VERSION b/release-notes/VERSION
index bad3a3d..6e1bf4b 100644
--- a/release-notes/VERSION
+++ b/release-notes/VERSION
@@ -16,6 +16,9 @@
* [JACKSON-753] JsonParserDelegate missing delegation of getBooleanValue(),
getEmbeddedObject()
(reported by Sebastian T)
+ * [JACKSON-756] Problems with enums, @JsonCreator, when used as keys
+ of EnumMap, regular Map, or contents of EnumSet
+ (reported by Mika M)
* [JACKSON-757] Problems with Enum values, annotations on constructors
(reported by Stephan B)
diff --git a/src/mapper/java/org/codehaus/jackson/map/deser/BasicDeserializerFactory.java b/src/mapper/java/org/codehaus/jackson/map/deser/BasicDeserializerFactory.java
index 8fdda5d..8a11d03 100644
--- a/src/mapper/java/org/codehaus/jackson/map/deser/BasicDeserializerFactory.java
+++ b/src/mapper/java/org/codehaus/jackson/map/deser/BasicDeserializerFactory.java
@@ -15,6 +15,7 @@
import org.codehaus.jackson.map.deser.std.MapDeserializer;
import org.codehaus.jackson.map.deser.std.ObjectArrayDeserializer;
import org.codehaus.jackson.map.deser.std.PrimitiveArrayDeserializers;
+import org.codehaus.jackson.map.deser.std.StdKeyDeserializers;
import org.codehaus.jackson.map.deser.std.StringCollectionDeserializer;
import org.codehaus.jackson.map.ext.OptionalHandlerFactory;
import org.codehaus.jackson.map.introspect.*;
@@ -43,6 +44,13 @@
* types. These need not go through factory.
*/
final static HashMap<ClassKey, JsonDeserializer<Object>> _simpleDeserializers = StdDeserializers.constructAll();
+
+ /**
+ * Set of available key deserializers is currently limited
+ * to standard types; and all known instances are storing
+ * in this map.
+ */
+ final static HashMap<JavaType, KeyDeserializer> _keyDeserializers = StdKeyDeserializers.constructAll();
/* We do some defaulting for abstract Map classes and
* interfaces, to avoid having to use exact types or annotations in
diff --git a/src/mapper/java/org/codehaus/jackson/map/deser/BeanDeserializerFactory.java b/src/mapper/java/org/codehaus/jackson/map/deser/BeanDeserializerFactory.java
index 11a9d73..5a6d46a 100644
--- a/src/mapper/java/org/codehaus/jackson/map/deser/BeanDeserializerFactory.java
+++ b/src/mapper/java/org/codehaus/jackson/map/deser/BeanDeserializerFactory.java
@@ -6,6 +6,7 @@
import org.codehaus.jackson.map.*;
import org.codehaus.jackson.map.deser.impl.CreatorCollector;
import org.codehaus.jackson.map.deser.impl.CreatorProperty;
+import org.codehaus.jackson.map.deser.std.StdKeyDeserializers;
import org.codehaus.jackson.map.deser.std.ThrowableDeserializer;
import org.codehaus.jackson.map.introspect.*;
import org.codehaus.jackson.map.type.*;
@@ -292,6 +293,7 @@
BeanProperty property)
throws JsonMappingException
{
+ // First: possible custom deserializers
if (_factoryConfig.hasKeyDeserializers()) {
BasicBeanDescription beanDesc = config.introspectClassAnnotations(type.getRawClass());
for (KeyDeserializers d : _factoryConfig.keyDeserializers()) {
@@ -301,7 +303,24 @@
}
}
}
- return null;
+ // and if none found, standard ones:
+ // No serializer needed if it's plain old String, or Object/untyped
+ Class<?> raw = type.getRawClass();
+ if (raw == String.class || raw == Object.class) {
+ return StdKeyDeserializers.constructStringKeyDeserializer(config, type);
+ }
+ // Most other keys are of limited number of static types
+ KeyDeserializer kdes = _keyDeserializers.get(type);
+ if (kdes != null) {
+ return kdes;
+ }
+ // And then other one-offs; first, Enum:
+ if (type.isEnumType()) {
+ return StdKeyDeserializers.constructEnumKeyDeserializer(config, type);
+ }
+ // One more thing: can we find ctor(String) or valueOf(String)?
+ kdes = StdKeyDeserializers.findStringBasedKeyDeserializer(config, type);
+ return kdes;
}
@Override
diff --git a/src/mapper/java/org/codehaus/jackson/map/deser/StdDeserializerProvider.java b/src/mapper/java/org/codehaus/jackson/map/deser/StdDeserializerProvider.java
index 5237392..6fc6c2c 100644
--- a/src/mapper/java/org/codehaus/jackson/map/deser/StdDeserializerProvider.java
+++ b/src/mapper/java/org/codehaus/jackson/map/deser/StdDeserializerProvider.java
@@ -11,7 +11,6 @@
import org.codehaus.jackson.map.*;
import org.codehaus.jackson.map.deser.BeanDeserializer;
import org.codehaus.jackson.map.introspect.AnnotatedClass;
-import org.codehaus.jackson.map.deser.std.StdKeyDeserializers;
import org.codehaus.jackson.map.type.*;
import org.codehaus.jackson.map.util.ClassUtil;
import org.codehaus.jackson.map.util.RootNameLookup;
@@ -33,13 +32,6 @@
*/
/**
- * Set of available key deserializers is currently limited
- * to standard types; and all known instances are storing
- * in this map.
- */
- final static HashMap<JavaType, KeyDeserializer> _keyDeserializers = StdKeyDeserializers.constructAll();
-
- /**
* We will also cache some dynamically constructed deserializers;
* specifically, ones that are expensive to construct.
* This currently means bean and Enum deserializers; array, List and Map
@@ -198,37 +190,14 @@
JavaType type, BeanProperty property)
throws JsonMappingException
{
- // 1.8: check if there are custom key deserializers...
KeyDeserializer kd = _factory.createKeyDeserializer(config, type, property);
- if (kd == null) {
- // No serializer needed if it's plain old String, or Object/untyped
- Class<?> raw = type.getRawClass();
- if (raw == String.class || raw == Object.class) {
- return null;
- }
- // Most other keys are of limited number of static types
- KeyDeserializer kdes = _keyDeserializers.get(type);
- if (kdes != null) {
- return kdes;
- }
- // And then other one-offs; first, Enum:
- if (type.isEnumType()) {
- return StdKeyDeserializers.constructEnumKeyDeserializer(config, type);
- }
- // One more thing: can we find ctor(String) or valueOf(String)?
- kdes = StdKeyDeserializers.findStringBasedKeyDeserializer(config, type);
- if (kdes != null) {
- return kdes;
- }
- if (kd == null) {
- // otherwise, will probably fail:
- return _handleUnknownKeyDeserializer(type);
- }
- }
- // One more thing: contextuality:
+ // One more thing: contextuality
if (kd instanceof ContextualKeyDeserializer) {
kd = ((ContextualKeyDeserializer) kd).createContextual(config, property);
}
+ if (kd == null) { // if none found, need to use a placeholder that'll fail
+ return _handleUnknownKeyDeserializer(type);
+ }
return kd;
}
@@ -447,9 +416,7 @@
protected JsonDeserializer<Object> _handleUnknownValueDeserializer(JavaType type)
throws JsonMappingException
{
- /* Let's try to figure out the reason, to give better error
- * messages
- */
+ // Let's try to figure out the reason, to give better error
Class<?> rawClass = type.getRawClass();
if (!ClassUtil.isConcrete(rawClass)) {
throw new JsonMappingException("Can not find a Value deserializer for abstract type "+type);
diff --git a/src/mapper/java/org/codehaus/jackson/map/deser/std/MapDeserializer.java b/src/mapper/java/org/codehaus/jackson/map/deser/std/MapDeserializer.java
index 2bdb8ac..ee71967 100644
--- a/src/mapper/java/org/codehaus/jackson/map/deser/std/MapDeserializer.java
+++ b/src/mapper/java/org/codehaus/jackson/map/deser/std/MapDeserializer.java
@@ -304,7 +304,7 @@
for (; t == JsonToken.FIELD_NAME; t = jp.nextToken()) {
// Must point to field name
String fieldName = jp.getCurrentName();
- Object key = (keyDes == null) ? fieldName : keyDes.deserializeKey(fieldName, ctxt);
+ Object key = keyDes.deserializeKey(fieldName, ctxt);
// And then the value...
t = jp.nextToken();
if (_ignorableProperties != null && _ignorableProperties.contains(fieldName)) {
@@ -369,7 +369,7 @@
}
// other property? needs buffering
String fieldName = jp.getCurrentName();
- Object key = (_keyDeserializer == null) ? fieldName : _keyDeserializer.deserializeKey(fieldName, ctxt);
+ Object key = _keyDeserializer.deserializeKey(fieldName, ctxt);
Object value;
if (t == JsonToken.VALUE_NULL) {
value = null;
diff --git a/src/mapper/java/org/codehaus/jackson/map/deser/std/StdKeyDeserializer.java b/src/mapper/java/org/codehaus/jackson/map/deser/std/StdKeyDeserializer.java
index 257cee4..4b8a459 100644
--- a/src/mapper/java/org/codehaus/jackson/map/deser/std/StdKeyDeserializer.java
+++ b/src/mapper/java/org/codehaus/jackson/map/deser/std/StdKeyDeserializer.java
@@ -67,6 +67,36 @@
/*
/**********************************************************
+ /* First: the standard "String as String" deserializer
+ /**********************************************************
+ */
+
+ final static class StringKD extends StdKeyDeserializer
+ {
+ private final static StringKD sString = new StringKD(String.class);
+ private final static StringKD sObject = new StringKD(Object.class);
+
+ private StringKD(Class<?> nominalType) { super(nominalType); }
+
+ public static StringKD forType(Class<?> nominalType)
+ {
+ if (nominalType == String.class) {
+ return sString;
+ }
+ if (nominalType == Object.class) {
+ return sObject;
+ }
+ return new StringKD(nominalType);
+ }
+
+ @Override
+ public String _parse(String key, DeserializationContext ctxt) throws JsonMappingException {
+ return key;
+ }
+ }
+
+ /*
+ /**********************************************************
/* Key deserializer implementations; wrappers
/**********************************************************
*/
diff --git a/src/mapper/java/org/codehaus/jackson/map/deser/std/StdKeyDeserializers.java b/src/mapper/java/org/codehaus/jackson/map/deser/std/StdKeyDeserializers.java
index d09e49f..1518fad 100644
--- a/src/mapper/java/org/codehaus/jackson/map/deser/std/StdKeyDeserializers.java
+++ b/src/mapper/java/org/codehaus/jackson/map/deser/std/StdKeyDeserializers.java
@@ -49,7 +49,7 @@
/* As with other cases involving primitive types, we can use
* default TypeFactory ok, even if it's not our first choice:
*/
- _keyDeserializers.put(TypeFactory.defaultInstance().constructType(keyClass), kdeser);
+ _keyDeserializers.put(TypeFactory.defaultInstance().uncheckedSimpleType(keyClass), kdeser);
}
public static HashMap<JavaType, KeyDeserializer> constructAll()
@@ -59,10 +59,15 @@
/*
/**********************************************************
- /* Dynamic factory methods
+ /* Factory methods
/**********************************************************
*/
+ public static KeyDeserializer constructStringKeyDeserializer(DeserializationConfig config, JavaType type)
+ {
+ return StdKeyDeserializer.StringKD.forType(type.getClass());
+ }
+
public static KeyDeserializer constructEnumKeyDeserializer(DeserializationConfig config, JavaType type)
{
EnumResolver<?> er = EnumResolver.constructUnsafe(type.getRawClass(), config.getAnnotationIntrospector());