Skip to content

Commit

Permalink
Fix #677
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Jun 11, 2015
1 parent 44dea1f commit 707db7a
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 28 deletions.
2 changes: 2 additions & 0 deletions release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ Project: jackson-databind
#664: Add `DeserializationFeature.ACCEPT_FLOAT_AS_INT` to prevent coercion of floating point
numbers int `int`/`long`/`Integer`/`Long`
(requested by wenzis@github)
#677: Specifying `Enum` value serialization using `@JsonProperty`
(requested by Allen C, allenchen1154@github)
#679: Add `isEmpty()` implementation for `JsonNode` serializers
#688: Provide a means for an ObjectMapper to discover mixin annotation classes on demand
(requested by Laird N)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.fasterxml.jackson.databind.introspect;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;

import com.fasterxml.jackson.annotation.*;
Expand Down Expand Up @@ -57,8 +58,31 @@ public boolean isAnnotationBundle(Annotation ann) {
/**********************************************************
*/

// default impl is fine:
//public String findEnumValue(Enum<?> value) { return value.name(); }
/**
* Since 2.6, we have supported use of {@link JsonProperty} for specifying
* explicit serialized name
*/
@Override
public String findEnumValue(Enum<?> value)
{
// 11-Jun-2015, tatu: As per [databind#677], need to allow explicit naming.
// Unfortunately can not quite use standard AnnotatedClass here (due to various
// reasons, including odd representation JVM uses); has to do for now
try {
// We know that values are actually static fields with matching name so:
Field f = value.getClass().getField(value.name());
if (f != null) {
JsonProperty prop = f.getAnnotation(JsonProperty.class);
String n = prop.value();
if (n != null && !n.isEmpty()) {
return n;
}
}
} catch (Exception e) {
// no such field, or access; neither which we can do much about
}
return value.name();
}

/*
/**********************************************************
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ private LowerCaseEnum() { }
public String toString() { return name().toLowerCase(); }
}

// for [JACKSON-749]
protected enum EnumWithJsonValue {
A("foo"), B("bar");
private final String name;
Expand All @@ -92,13 +91,11 @@ private EnumWithJsonValue(String n) {
@Override
public String toString() { return name; }
}

// [JACKSON-810]

static class ClassWithEnumMapKey {
@JsonProperty Map<TestEnum, String> map;
@JsonProperty Map<TestEnum, String> map;
}

// [JACKSON-834]
protected enum TestEnumFor834
{
ENUM_A(1), ENUM_B(2), ENUM_C(3);
Expand Down Expand Up @@ -127,7 +124,7 @@ protected enum TestEnum324
}
}

// [Issue#745]
// [databind#745]
static class DelegatingDeserializers extends Deserializers.Base
{
@Override
Expand All @@ -145,7 +142,7 @@ public JsonDeserializer<?> findEnumDeserializer(final Class<?> type, final Deser
}
}

// [Issue#745]
// [databind#745]
static class DelegatingDeserializersModule extends SimpleModule
{
@Override
Expand All @@ -154,14 +151,29 @@ public void setupModule(final SetupContext context) {
}
}

// [databind#677]
static enum EnumWithPropertyAnno {
@JsonProperty("a")
A,

// For this value, force use of anonymous sub-class, to ensure things still work
@JsonProperty("b")
B {
@Override
public String toString() {
return "bb";
}
}
;
}

/*
/**********************************************************
/* Tests
/**********************************************************
*/

protected final ObjectMapper MAPPER = new ObjectMapper();


public void testSimple() throws Exception
{
Expand Down Expand Up @@ -226,15 +238,13 @@ public void testEnumMaps() throws Exception
new TypeReference<EnumMap<TestEnum,String>>() { });
assertEquals("value", value.get(TestEnum.OK));
}

// Test [JACKSON-214]

public void testSubclassedEnums() throws Exception
{
EnumWithSubClass value = MAPPER.readValue("\"A\"", EnumWithSubClass.class);
assertEquals(EnumWithSubClass.A, value);
}

// [JACKSON-193]
public void testCreatorEnums() throws Exception {
EnumWithCreator value = MAPPER.readValue("\"enumA\"", EnumWithCreator.class);
assertEquals(EnumWithCreator.A, value);
Expand All @@ -244,8 +254,7 @@ public void testCreatorEnumsFromBigDecimal() throws Exception {
EnumWithBDCreator value = MAPPER.readValue("\"8.0\"", EnumWithBDCreator.class);
assertEquals(EnumWithBDCreator.E8, value);
}

// [JACKSON-212]

public void testToStringEnums() throws Exception
{
// can't reuse global one due to reconfig
Expand All @@ -255,7 +264,6 @@ public void testToStringEnums() throws Exception
assertEquals(LowerCaseEnum.C, value);
}

// [JACKSON-212]
public void testToStringEnumMaps() throws Exception
{
// can't reuse global one due to reconfig
Expand All @@ -266,7 +274,6 @@ public void testToStringEnumMaps() throws Exception
assertEquals("value", value.get(LowerCaseEnum.A));
}

// [JACKSON-412], disallow use of numbers
public void testNumbersToEnums() throws Exception
{
// by default numbers are fine:
Expand All @@ -293,7 +300,6 @@ public void testNumbersToEnums() throws Exception
}
}

// [JACKSON-684], enums using index
public void testEnumsWithIndex() throws Exception
{
ObjectMapper m = new ObjectMapper();
Expand All @@ -303,8 +309,7 @@ public void testEnumsWithIndex() throws Exception
TestEnum result = m.readValue(json, TestEnum.class);
assertSame(TestEnum.RULES, result);
}

// [JACKSON-749]: @JsonValue should be considered as well

public void testEnumsWithJsonValue() throws Exception
{
// first, enum as is
Expand All @@ -329,8 +334,6 @@ public void testEnumsWithJsonValue() throws Exception
assertEquals(Integer.valueOf(13), map.get(EnumWithJsonValue.A));
}

// [JACKSON-756], next three tests

public void testEnumWithCreatorEnumMaps() throws Exception {
EnumMap<EnumWithCreator,String> value = MAPPER.readValue("{\"enumA\":\"value\"}",
new TypeReference<EnumMap<EnumWithCreator,String>>() {});
Expand Down Expand Up @@ -386,15 +389,14 @@ public void testDoNotAllowUnknownEnumValuesAsMapKeysWhenReadAsNullDisabled() thr
}
}

// [JACKSON-834]
public void testEnumsFromInts() throws Exception
{
Object ob = MAPPER.readValue("1 ", TestEnumFor834.class);
assertEquals(TestEnumFor834.class, ob.getClass());
assertSame(TestEnumFor834.ENUM_A, ob);
}

// [Issue#141]: allow mapping of empty String into null
// [databind#141]: allow mapping of empty String into null
public void testEnumsWithEmpty() throws Exception
{
final ObjectMapper mapper = new ObjectMapper();
Expand All @@ -413,7 +415,7 @@ public void testGenericEnumDeserialization() throws Exception
assertEquals(TestEnum.JACKSON, mapper.readValue(quote("jackson"), TestEnum.class));
}

// [Issue#324]
// [databind#324]
public void testExceptionFromCreator() throws Exception
{
try {
Expand All @@ -424,7 +426,7 @@ public void testExceptionFromCreator() throws Exception
}
}

// [Issue#381]
// [databind#381]
public void testUnwrappedEnum() throws Exception {
final ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS);
Expand All @@ -443,7 +445,7 @@ public void testUnwrappedEnumException() throws Exception {
}
}

// [Issue#149]: 'stringified' indexes for enums
// [databind#149]: 'stringified' indexes for enums
public void testIndexAsString() throws Exception
{
// first, regular index ought to work fine
Expand All @@ -455,7 +457,7 @@ public void testIndexAsString() throws Exception
assertSame(TestEnum.values()[1], en);
}

// [Issue#745]
// [databind#745]
public void testDeserializerForCreatorWithEnumMaps() throws Exception
{
final ObjectMapper mapper = new ObjectMapper();
Expand All @@ -464,4 +466,19 @@ public void testDeserializerForCreatorWithEnumMaps() throws Exception
new TypeReference<EnumMap<EnumWithCreator,String>>() {});
assertEquals("value", value.get(EnumWithCreator.A));
}

public void testEnumWithJsonPropertyRename() throws Exception
{
String json = MAPPER.writeValueAsString(new EnumWithPropertyAnno[] {
EnumWithPropertyAnno.B, EnumWithPropertyAnno.A
});
assertEquals("[\"b\",\"a\"]", json);

// and while not really proper place, let's also verify deser while we're at it
EnumWithPropertyAnno[] result = MAPPER.readValue(json, EnumWithPropertyAnno[].class);
assertNotNull(result);
assertEquals(2, result.length);
assertSame(EnumWithPropertyAnno.B, result[0]);
assertSame(EnumWithPropertyAnno.A, result[1]);
}
}

0 comments on commit 707db7a

Please sign in to comment.