Merge pull request #119 from serj-lotutovici/sl/json_for_enums

Enable Json annotation for enum values.
This commit is contained in:
Jesse Wilson
2016-01-18 16:52:02 -05:00
2 changed files with 48 additions and 21 deletions

View File

@@ -21,6 +21,7 @@ import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@@ -52,7 +53,7 @@ final class StandardJsonAdapters {
Class<?> rawType = Types.getRawType(type); Class<?> rawType = Types.getRawType(type);
if (rawType.isEnum()) { if (rawType.isEnum()) {
//noinspection unchecked //noinspection unchecked
return enumAdapter((Class<? extends Enum>) rawType).nullSafe(); return new EnumJsonAdapter<>((Class<? extends Enum>) rawType).nullSafe();
} }
return null; return null;
} }
@@ -212,27 +213,46 @@ final class StandardJsonAdapters {
} }
}; };
static <T extends Enum<T>> JsonAdapter<T> enumAdapter(final Class<T> enumType) { static final class EnumJsonAdapter<T extends Enum<T>> extends JsonAdapter<T> {
return new JsonAdapter<T>() { private final Class<T> enumType;
@Override public T fromJson(JsonReader reader) throws IOException { private final Map<String, T> nameConstantMap = new LinkedHashMap<>();
String name = reader.nextString();
try { public EnumJsonAdapter(Class<T> enumType) {
return Enum.valueOf(enumType, name); this.enumType = enumType;
} catch (IllegalArgumentException e) { try {
throw new JsonDataException("Expected one of " T[] constants = enumType.getEnumConstants();
+ Arrays.toString(enumType.getEnumConstants()) + " but was " + name + " at path " for (T constant : constants) {
+ reader.getPath()); Json annotation = enumType.getField(constant.name()).getAnnotation(Json.class);
String name = annotation != null ? annotation.name() : constant.name();
nameConstantMap.put(name, constant);
}
} catch (NoSuchFieldException e) {
throw new AssertionError("Missing field in " + enumType.getName(), e);
}
}
@Override public T fromJson(JsonReader reader) throws IOException {
String name = reader.nextString();
T constant = nameConstantMap.get(name);
if (constant != null) return constant;
throw new JsonDataException("Expected one of "
+ nameConstantMap.keySet() + " but was " + name + " at path "
+ reader.getPath());
}
@Override public void toJson(JsonWriter writer, T value) throws IOException {
for (Map.Entry<String, T> entry : nameConstantMap.entrySet()) {
if (entry.getValue() == value) {
writer.value(entry.getKey());
break;
} }
} }
}
@Override public void toJson(JsonWriter writer, T value) throws IOException { @Override public String toString() {
writer.value(value.name()); return "JsonAdapter(" + enumType.getName() + ")";
} }
@Override public String toString() {
return "JsonAdapter(" + enumType.getName() + ")";
}
};
} }
/** /**

View File

@@ -672,6 +672,13 @@ public final class MoshiTest {
assertThat(adapter.toJson(Roshambo.PAPER)).isEqualTo("\"PAPER\""); assertThat(adapter.toJson(Roshambo.PAPER)).isEqualTo("\"PAPER\"");
} }
@Test public void annotatedEnum() throws Exception {
Moshi moshi = new Moshi.Builder().build();
JsonAdapter<Roshambo> adapter = moshi.adapter(Roshambo.class).lenient();
assertThat(adapter.fromJson("\"scr\"")).isEqualTo(Roshambo.SCISSORS);
assertThat(adapter.toJson(Roshambo.SCISSORS)).isEqualTo("\"scr\"");
}
@Test public void invalidEnum() throws Exception { @Test public void invalidEnum() throws Exception {
Moshi moshi = new Moshi.Builder().build(); Moshi moshi = new Moshi.Builder().build();
JsonAdapter<Roshambo> adapter = moshi.adapter(Roshambo.class).lenient(); JsonAdapter<Roshambo> adapter = moshi.adapter(Roshambo.class).lenient();
@@ -680,7 +687,7 @@ public final class MoshiTest {
fail(); fail();
} catch (JsonDataException expected) { } catch (JsonDataException expected) {
assertThat(expected).hasMessage( assertThat(expected).hasMessage(
"Expected one of [ROCK, PAPER, SCISSORS] but was SPOCK at path $"); "Expected one of [ROCK, PAPER, scr] but was SPOCK at path $");
} }
} }
@@ -930,7 +937,7 @@ public final class MoshiTest {
enum Roshambo { enum Roshambo {
ROCK, ROCK,
PAPER, PAPER,
SCISSORS @Json(name = "scr") SCISSORS
} }
@Retention(RUNTIME) @Retention(RUNTIME)