From 81fc0297368fd2080502d69d8f5c78e986ca1b70 Mon Sep 17 00:00:00 2001 From: Byteflux Date: Mon, 20 Oct 2014 04:31:11 -0700 Subject: [PATCH] Support modded enums in gson using custom EnumTypeAdapter. Resolves carbon breaking materials in issue #90. --- .../java/com/massivecraft/factions/P.java | 3 +- .../factions/util/EnumTypeAdapter.java | 66 +++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/massivecraft/factions/util/EnumTypeAdapter.java diff --git a/src/main/java/com/massivecraft/factions/P.java b/src/main/java/com/massivecraft/factions/P.java index aca2beba..da853226 100644 --- a/src/main/java/com/massivecraft/factions/P.java +++ b/src/main/java/com/massivecraft/factions/P.java @@ -8,6 +8,7 @@ import com.massivecraft.factions.integration.Worldguard; import com.massivecraft.factions.listeners.*; import com.massivecraft.factions.struct.ChatMode; import com.massivecraft.factions.util.AutoLeaveTask; +import com.massivecraft.factions.util.EnumTypeAdapter; import com.massivecraft.factions.util.LazyLocation; import com.massivecraft.factions.util.MapFLocToStringSetTypeAdapter; import com.massivecraft.factions.util.MyLocationTypeAdapter; @@ -124,7 +125,7 @@ public class P extends MPlugin { public GsonBuilder getGsonBuilder() { Type mapFLocToStringSetType = new TypeToken>>() {}.getType(); - return new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().excludeFieldsWithModifiers(Modifier.TRANSIENT, Modifier.VOLATILE).registerTypeAdapter(LazyLocation.class, new MyLocationTypeAdapter()).registerTypeAdapter(mapFLocToStringSetType, new MapFLocToStringSetTypeAdapter()); + return new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().excludeFieldsWithModifiers(Modifier.TRANSIENT, Modifier.VOLATILE).registerTypeAdapter(LazyLocation.class, new MyLocationTypeAdapter()).registerTypeAdapter(mapFLocToStringSetType, new MapFLocToStringSetTypeAdapter()).registerTypeAdapterFactory(EnumTypeAdapter.ENUM_FACTORY); } @Override diff --git a/src/main/java/com/massivecraft/factions/util/EnumTypeAdapter.java b/src/main/java/com/massivecraft/factions/util/EnumTypeAdapter.java new file mode 100644 index 00000000..8e22f3ab --- /dev/null +++ b/src/main/java/com/massivecraft/factions/util/EnumTypeAdapter.java @@ -0,0 +1,66 @@ +package com.massivecraft.factions.util; + +import org.bukkit.craftbukkit.libs.com.google.gson.Gson; +import org.bukkit.craftbukkit.libs.com.google.gson.TypeAdapter; +import org.bukkit.craftbukkit.libs.com.google.gson.TypeAdapterFactory; +import org.bukkit.craftbukkit.libs.com.google.gson.annotations.SerializedName; +import org.bukkit.craftbukkit.libs.com.google.gson.reflect.TypeToken; +import org.bukkit.craftbukkit.libs.com.google.gson.stream.JsonReader; +import org.bukkit.craftbukkit.libs.com.google.gson.stream.JsonToken; +import org.bukkit.craftbukkit.libs.com.google.gson.stream.JsonWriter; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public final class EnumTypeAdapter> extends TypeAdapter { + + private final Map nameToConstant = new HashMap(); + private final Map constantToName = new HashMap(); + + public EnumTypeAdapter(Class classOfT) { + try { + for (T constant : classOfT.getEnumConstants()) { + String name = constant.name(); + SerializedName annotation = classOfT.getField(name).getAnnotation(SerializedName.class); + if (annotation != null) { + name = annotation.value(); + } + nameToConstant.put(name, constant); + constantToName.put(constant, name); + } + } catch (NoSuchFieldException e) { + // ignore since it could be a modified enum + } + } + public T read(JsonReader in) throws IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + return nameToConstant.get(in.nextString()); + } + + public void write(JsonWriter out, T value) throws IOException { + out.value(value == null ? null : constantToName.get(value)); + } + + public static final TypeAdapterFactory ENUM_FACTORY = newEnumTypeHierarchyFactory(); + + public static TypeAdapterFactory newEnumTypeHierarchyFactory() { + return new TypeAdapterFactory() { + @SuppressWarnings({"rawtypes", "unchecked"}) + public TypeAdapter create(Gson gson, TypeToken typeToken) { + Class rawType = typeToken.getRawType(); + if (!Enum.class.isAssignableFrom(rawType) || rawType == Enum.class) { + return null; + } + if (!rawType.isEnum()) { + rawType = rawType.getSuperclass(); // handle anonymous subclasses + } + return (TypeAdapter) new EnumTypeAdapter(rawType); + } + }; + } + +}