Skip to content

Commit

Permalink
Fixed #1161
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Mar 15, 2016
1 parent 4a97f18 commit 493ba8d
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 32 deletions.
3 changes: 3 additions & 0 deletions release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ Project: jackson-databind
(reported by Xavi T)
#1154: @JsonFormat.pattern on dates is now ignored if shape is not explicitely provided
(reported by Yoann R)
#1161: `DeserializationFeature.READ_ENUMS_USING_TO_STRING` not dynamically
changeable with 2.7
(reported by asa-git@github)
- Minor fixes to `AnnotationIntrospector.findEnumValues()` to correct problems with
merging of explicit enum value names.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1252,7 +1252,8 @@ public JsonDeserializer<?> createEnumDeserializer(DeserializationContext ctxt,
}
// Need to consider @JsonValue if one found
if (deser == null) {
deser = new EnumDeserializer(constructEnumResolver(enumClass, config, beanDesc.findJsonValueMethod()));
deser = new EnumDeserializer(constructEnumResolver(enumClass,
config, beanDesc.findJsonValueMethod()));
}
}

Expand Down Expand Up @@ -1436,7 +1437,6 @@ private KeyDeserializer _createEnumKeyDeserializer(DeserializationContext ctxt,
return StdKeyDeserializers.constructDelegatingKeyDeserializer(config, type, valueDesForKey);
}
}

EnumResolver enumRes = constructEnumResolver(enumClass, config, beanDesc.findJsonValueMethod());
// May have @JsonCreator for static factory method:
final AnnotationIntrospector ai = config.getAnnotationIntrospector();
Expand Down Expand Up @@ -1919,10 +1919,8 @@ protected EnumResolver constructEnumResolver(Class<?> enumClass,
}
return EnumResolver.constructUnsafeUsingMethod(enumClass, accessor);
}
// May need to use Enum.toString()
if (config.isEnabled(DeserializationFeature.READ_ENUMS_USING_TO_STRING)) {
return EnumResolver.constructUnsafeUsingToString(enumClass);
}
// 14-Mar-2016, tatu: We used to check `DeserializationFeature.READ_ENUMS_USING_TO_STRING`
// here, but that won't do: it must be dynamically changeable...
return EnumResolver.constructUnsafe(enumClass, config.getAnnotationIntrospector());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,26 @@ public class EnumDeserializer
/**
* @since 2.6
*/
protected final CompactStringObjectMap _enumLookup;
protected Object[] _enumsByIndex;

/**
* @since 2.6
* @since 2.7.3
*/
protected Object[] _enumsByIndex;
protected final CompactStringObjectMap _lookupByName;

public EnumDeserializer(EnumResolver res)
/**
* Alternatively, we may need a different lookup object if "use toString"
* is defined.
*
* @since 2.7.3
*/
protected CompactStringObjectMap _lookupByToString;

public EnumDeserializer(EnumResolver byNameResolver)
{
super(res.getEnumClass());
_enumLookup = res.constructLookup();
_enumsByIndex = res.getRawEnums();
super(byNameResolver.getEnumClass());
_lookupByName = byNameResolver.constructLookup();
_enumsByIndex = byNameResolver.getRawEnums();
}

/**
Expand Down Expand Up @@ -80,10 +88,12 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOEx

// Usually should just get string value:
if (curr == JsonToken.VALUE_STRING || curr == JsonToken.FIELD_NAME) {
String name = p.getText();
Object result = _enumLookup.find(name);
CompactStringObjectMap lookup = ctxt.isEnabled(DeserializationFeature.READ_ENUMS_USING_TO_STRING)
? _getToStringLookup() : _lookupByName;
final String name = p.getText();
Object result = lookup.find(name);
if (result == null) {
return _deserializeAltString(p, ctxt, name);
return _deserializeAltString(p, ctxt, lookup, name);
}
return result;
}
Expand All @@ -106,8 +116,14 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOEx
return _deserializeOther(p, ctxt);
}

/*
/**********************************************************
/* Internal helper methods
/**********************************************************
*/

private final Object _deserializeAltString(JsonParser p, DeserializationContext ctxt,
String name) throws IOException
CompactStringObjectMap lookup, String name) throws IOException
{
name = name.trim();
if (name.length() == 0) {
Expand All @@ -133,7 +149,7 @@ private final Object _deserializeAltString(JsonParser p, DeserializationContext
}
if (!ctxt.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)) {
throw ctxt.weirdStringException(name, _enumClass(),
"value not one of declared Enum instance names: "+_enumLookup.keys());
"value not one of declared Enum instance names: "+lookup.keys());
}
return null;
}
Expand Down Expand Up @@ -169,6 +185,21 @@ protected Class<?> _enumClass() {
return handledType();
}

protected CompactStringObjectMap _getToStringLookup()
{
CompactStringObjectMap lookup = _lookupByToString;
// note: exact locking not needed; all we care for here is to try to
// reduce contention for the initial resolution
if (lookup == null) {
synchronized (this) {
lookup = EnumResolver.constructUnsafeUsingToString(_enumClass())
.constructLookup();
}
_lookupByToString = lookup;
}
return lookup;
}

/*
/**********************************************************
/* Additional helper classes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public static StdKeyDeserializer forType(Class<?> raw)

@Override
public Object deserializeKey(String key, DeserializationContext ctxt)
throws IOException, JsonProcessingException
throws IOException
{
if (key == null) { // is this even legal call?
return null;
Expand Down Expand Up @@ -318,13 +318,21 @@ final static class EnumKD extends StdKeyDeserializer
{
private static final long serialVersionUID = 1L;

protected final EnumResolver _resolver;
protected final EnumResolver _byNameResolver;

protected final AnnotatedMethod _factory;

/**
* Lazily constructed alternative in case there is need to
* use 'toString()' method as the source.
*
* @since 2.7.3
*/
protected EnumResolver _byToStringResolver;

protected EnumKD(EnumResolver er, AnnotatedMethod factory) {
super(-1, er.getEnumClass());
_resolver = er;
_byNameResolver = er;
_factory = factory;
}

Expand All @@ -338,12 +346,26 @@ public Object _parse(String key, DeserializationContext ctxt) throws JsonMapping
ClassUtil.unwrapAndThrowAsIAE(e);
}
}
Enum<?> e = _resolver.findEnum(key);
EnumResolver res = ctxt.isEnabled(DeserializationFeature.READ_ENUMS_USING_TO_STRING)
? _getToStringResolver() : _byNameResolver;
Enum<?> e = res.findEnum(key);
if ((e == null) && !ctxt.getConfig().isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)) {
throw ctxt.weirdKeyException(_keyClass, key, "not one of values for Enum class");
throw ctxt.weirdKeyException(_keyClass, key, "not one of values excepted for Enum class: "
+res.getEnumIds());
}
return e;
}

private EnumResolver _getToStringResolver()
{
EnumResolver res = _byToStringResolver;
if (res == null) {
synchronized (this) {
res = EnumResolver.constructUnsafeUsingToString(_byNameResolver.getEnumClass());
}
}
return res;
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.fasterxml.jackson.databind.util;

import com.fasterxml.jackson.databind.AnnotationIntrospector;

import java.lang.reflect.Method;
import java.util.*;

/**
import com.fasterxml.jackson.databind.AnnotationIntrospector;

/**
* Helper class used to resolve String values (either JSON Object field
* names or regular String values) into Java Enum instances.
*/
Expand Down Expand Up @@ -62,7 +62,7 @@ public static EnumResolver constructUsingToString(Class<Enum<?>> enumCls)
map.put(e.toString(), e);
}
return new EnumResolver(enumCls, enumValues, map);
}
}

public static EnumResolver constructUsingMethod(Class<Enum<?>> enumCls,
Method accessor)
Expand Down Expand Up @@ -146,6 +146,13 @@ public List<Enum<?>> getEnums() {
}
return enums;
}

/**
* @since 2.7.3
*/
public Collection<String> getEnumIds() {
return _enumsById.keySet();
}

public Class<Enum<?>> getEnumClass() { return _enumClass; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Map;
import java.util.*;
import java.util.concurrent.TimeUnit;

import com.fasterxml.jackson.annotation.*;
Expand Down Expand Up @@ -167,6 +164,16 @@ public String toString() {
;
}

// [databind#1161]
enum Enum1161 {
A, B, C;

@Override
public String toString() {
return name().toLowerCase();
};
}

/*
/**********************************************************
/* Tests
Expand Down Expand Up @@ -481,4 +488,22 @@ public void testEnumWithJsonPropertyRename() throws Exception
assertSame(EnumWithPropertyAnno.B, result[0]);
assertSame(EnumWithPropertyAnno.A, result[1]);
}
}

// [databind#1161], unable to switch READ_ENUMS_USING_TO_STRING
public void testDeserWithToString1161() throws Exception
{
Enum1161 result = MAPPER.readerFor(Enum1161.class)
.readValue(quote("A"));
assertSame(Enum1161.A, result);

result = MAPPER.readerFor(Enum1161.class)
.with(DeserializationFeature.READ_ENUMS_USING_TO_STRING)
.readValue(quote("a"));
assertSame(Enum1161.A, result);

// and once again, going back to defaults
result = MAPPER.readerFor(Enum1161.class)
.without(DeserializationFeature.READ_ENUMS_USING_TO_STRING)
.readValue(quote("A"));
assertSame(Enum1161.A, result);
}}

0 comments on commit 493ba8d

Please sign in to comment.