From bb259374e4d3178e4aa6b4ba9472728ecba9cd75 Mon Sep 17 00:00:00 2001 From: Olof Larsson Date: Wed, 13 Nov 2013 10:48:07 +0100 Subject: [PATCH] Added comments and fixed indentation for ModdedEnumTypeAdapter. --- src/com/massivecraft/mcore/MCore.java | 2 +- .../mcore/adapter/ModdedEnumTypeAdapter.java | 113 +++++++++++------- 2 files changed, 70 insertions(+), 45 deletions(-) diff --git a/src/com/massivecraft/mcore/MCore.java b/src/com/massivecraft/mcore/MCore.java index 89eca6b8..5446ad11 100644 --- a/src/com/massivecraft/mcore/MCore.java +++ b/src/com/massivecraft/mcore/MCore.java @@ -84,7 +84,7 @@ public class MCore extends MPlugin .registerTypeAdapter(Inventory.class, InventoryAdapter.get()) .registerTypeAdapter(PlayerInventory.class, PlayerInventoryAdapter.get()) .registerTypeAdapter(PS.class, PSAdapter.get()) - .registerTypeAdapterFactory(ModdedEnumTypeAdapter.ENUM_FACTORY); + .registerTypeAdapterFactory(ModdedEnumTypeAdapter.ENUM_FACTORY); } public static String getServerId() { return ConfServer.serverid; } diff --git a/src/com/massivecraft/mcore/adapter/ModdedEnumTypeAdapter.java b/src/com/massivecraft/mcore/adapter/ModdedEnumTypeAdapter.java index f26b569e..a619b4d8 100644 --- a/src/com/massivecraft/mcore/adapter/ModdedEnumTypeAdapter.java +++ b/src/com/massivecraft/mcore/adapter/ModdedEnumTypeAdapter.java @@ -13,52 +13,77 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; +/** + * This type adapter and factory handles modified Java Enums. + * It's based upon: https://github.com/MassiveCraft/mcore/blob/91f9ec7c0c7d9a11a35db905be520f5cf6b6743e/src/com/massivecraft/mcore/xlib/gson/internal/bind/TypeAdapters.java#L670 + * The only change is the try-catch around the annotation code. + * + * https://github.com/MassiveCraft/mcore/pull/62 + * + * # Problem + * The problem that was occurring is Forge modifies Vanilla Minecraft Enums + * (see https://github.com/MinecraftForge/MinecraftForge/blob/master/common/net/minecraftforge/common/EnumHelper.java) + * the way that it modifies the Enum is pure Java hackery modifying $VALUES on the underlying Enum. + * This will update the calls to Class.getEnumContants but won't update any fields on the Enum. + * So when the built-in Gson EnumTypeAdaper tries to see if any SerializedName annotations are on the fields of the Enum, + * it can't find a field with the new names and throws an exception. + * + * # Reasoning + * There is really not any way that we could put any fix in on the MCPC+ side since we can't add fields to Java enums at runtime. + * + * # Solution + * This ModdedEnumTypeAdapter is basically just a straight copy of the built-in one, + * but ignores when it can't find the field/annotation (which is the desired behavior in this case anyways). + * I tested this with Factions on the latest MCPC+ release and it resolves the issue that was logged. + * Hopefully this will reduce the number of people opening issues on both sides. + * If you have any questions, feel free to hit me up on IRC. + * + * @author OniBait + */ public final class ModdedEnumTypeAdapter> extends TypeAdapter { - private final Map nameToConstant = new HashMap(); - private final Map constantToName = new HashMap(); + private final Map nameToConstant = new HashMap(); + private final Map constantToName = new HashMap(); - public ModdedEnumTypeAdapter(Class classOfT) { - for (T constant : classOfT.getEnumConstants()) { - String name = constant.name(); - // Ignore when the field can't be found since modified enums won't have it - // which is fine, since it wouldn't have an annotation anyway (how could it?) - try { - SerializedName annotation = classOfT.getField(name).getAnnotation(SerializedName.class); - if (annotation != null) { - name = annotation.value(); - } - } catch (NoSuchFieldException ex) {} - nameToConstant.put(name, constant); - constantToName.put(constant, name); - } - } - public T read(JsonReader in) throws IOException { - if (in.peek() == JsonToken.NULL) { - in.nextNull(); - return null; - } - return nameToConstant.get(in.nextString()); - } + public ModdedEnumTypeAdapter(Class classOfT) { + for (T constant : classOfT.getEnumConstants()) { + String name = constant.name(); + try { // MCore - Ignore when the field can't be found since modified enums won't have it. + SerializedName annotation = classOfT.getField(name).getAnnotation(SerializedName.class); + if (annotation != null) { + name = annotation.value(); + } + } catch (NoSuchFieldException ex) {} // MCore + nameToConstant.put(name, constant); + constantToName.put(constant, name); + } + } + 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 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 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 ModdedEnumTypeAdapter(rawType); - } - }; - } -} \ No newline at end of file + 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 ModdedEnumTypeAdapter(rawType); + } + }; + } +}