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());