Fix Mson event database bug.

This commit is contained in:
Olof Larsson 2016-05-31 11:36:16 +02:00
parent 982c8de90f
commit cbf50c5741
No known key found for this signature in database
GPG Key ID: BBEF14F97DA52474
7 changed files with 247 additions and 101 deletions

View File

@ -17,11 +17,11 @@ public class AdapterLowercaseEnum<T extends Enum<T>> implements JsonDeserializer
// FIELDS // FIELDS
// -------------------------------------------- // // -------------------------------------------- //
protected final Class<T> clazz; private final Class<T> clazz;
public Class<T> getClazz() { return this.clazz; } public Class<T> getClazz() { return this.clazz; }
// -------------------------------------------- // // -------------------------------------------- //
// INSTANCE & CONSTRUCT // INSTANCE
// -------------------------------------------- // // -------------------------------------------- //
public static <T extends Enum<T>> AdapterLowercaseEnum<T> get(Class<T> clazz) public static <T extends Enum<T>> AdapterLowercaseEnum<T> get(Class<T> clazz)
@ -29,10 +29,14 @@ public class AdapterLowercaseEnum<T extends Enum<T>> implements JsonDeserializer
return new AdapterLowercaseEnum<T>(clazz); return new AdapterLowercaseEnum<T>(clazz);
} }
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public AdapterLowercaseEnum(Class<T> clazz) public AdapterLowercaseEnum(Class<T> clazz)
{ {
if (clazz == null) throw new IllegalArgumentException("passed clazz param is null"); if (clazz == null) throw new IllegalArgumentException("clazz is null");
if ( ! clazz.isEnum()) throw new IllegalArgumentException("passed clazz param must be an enum"); if ( ! clazz.isEnum()) throw new IllegalArgumentException("clazz is not enum");
this.clazz = clazz; this.clazz = clazz;
} }
@ -43,65 +47,76 @@ public class AdapterLowercaseEnum<T extends Enum<T>> implements JsonDeserializer
@Override @Override
public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context)
{ {
// Null
if (src == null) return JsonNull.INSTANCE; if (src == null) return JsonNull.INSTANCE;
return new JsonPrimitive(src.name().toLowerCase());
String comparable = this.getComparable(src);
return new JsonPrimitive(comparable);
} }
@Override @Override
public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{ {
// Null
if (json == null) return null; if (json == null) return null;
T value = getEnumValueFrom(json); if (json.equals(JsonNull.INSTANCE)) return null;
return value;
T ret = this.getEnumValueFrom(json);
return ret;
} }
// -------------------------------------------- // // -------------------------------------------- //
// UTIL // GET ENUM VALUE FROM
// -------------------------------------------- // // -------------------------------------------- //
public T getEnumValueFrom(JsonElement json) public T getEnumValueFrom(JsonElement json)
{ {
return getEnumValueFrom(json.toString()); String string = this.getComparable(json);
return this.getEnumValueFrom(string);
} }
public T getEnumValueFrom(String str) public T getEnumValueFrom(String string)
{ {
return getEnumValueFrom(str, clazz); string = this.getComparable(string);
for (T value : this.getEnumValues())
{
String comparable = this.getComparable(value);
if (comparable.equals(string)) return value;
}
return null;
} }
public static <T> T[] getEnumValues(Class<T> clazz) // -------------------------------------------- //
// GET ENUM VALUES
// -------------------------------------------- //
public T[] getEnumValues()
{ {
if (clazz == null) throw new IllegalArgumentException("passed clazz param is null"); Class<T> clazz = this.getClazz();
if ( ! clazz.isEnum()) throw new IllegalArgumentException("passed clazz param must be an enum");
T[] ret = clazz.getEnumConstants(); T[] ret = clazz.getEnumConstants();
if (ret == null) throw new RuntimeException("failed to retrieve enum constants at runtime");
return ret; return ret;
} }
public static String getComparable(Enum<?> value) // -------------------------------------------- //
// GET COMPARABLE
// -------------------------------------------- //
public String getComparable(Enum<?> value)
{ {
if (value == null) return null; if (value == null) return null;
return getComparable(value.name()); return this.getComparable(value.name());
} }
public static String getComparable(String string) public String getComparable(JsonElement json)
{
if (json == null) return null;
return this.getComparable(json.getAsString());
}
public String getComparable(String string)
{ {
if (string == null) return null; if (string == null) return null;
return string.toLowerCase(); return string.toLowerCase();
} }
public static<T extends Enum<T>> T getEnumValueFrom(String str, Class<T> clazz)
{
str = getComparable(str);
for (T value : getEnumValues(clazz))
{
if (getComparable(value).equals(str)) return value;
}
return null;
}
} }

View File

@ -6,7 +6,6 @@ import com.massivecraft.massivecore.mson.Mson;
import com.massivecraft.massivecore.xlib.gson.JsonDeserializationContext; import com.massivecraft.massivecore.xlib.gson.JsonDeserializationContext;
import com.massivecraft.massivecore.xlib.gson.JsonDeserializer; import com.massivecraft.massivecore.xlib.gson.JsonDeserializer;
import com.massivecraft.massivecore.xlib.gson.JsonElement; import com.massivecraft.massivecore.xlib.gson.JsonElement;
import com.massivecraft.massivecore.xlib.gson.JsonNull;
import com.massivecraft.massivecore.xlib.gson.JsonParseException; import com.massivecraft.massivecore.xlib.gson.JsonParseException;
import com.massivecraft.massivecore.xlib.gson.JsonSerializationContext; import com.massivecraft.massivecore.xlib.gson.JsonSerializationContext;
import com.massivecraft.massivecore.xlib.gson.JsonSerializer; import com.massivecraft.massivecore.xlib.gson.JsonSerializer;
@ -27,8 +26,7 @@ public class AdapterMson implements JsonDeserializer<Mson>, JsonSerializer<Mson>
@Override @Override
public JsonElement serialize(Mson src, Type typeOfSrc, JsonSerializationContext context) public JsonElement serialize(Mson src, Type typeOfSrc, JsonSerializationContext context)
{ {
if (src == null) return JsonNull.INSTANCE; return Mson.toJson(src);
return src.toJson();
} }
@Override @Override

View File

@ -2,7 +2,6 @@ package com.massivecraft.massivecore.adapter;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import com.massivecraft.massivecore.mson.Mson;
import com.massivecraft.massivecore.mson.MsonEvent; import com.massivecraft.massivecore.mson.MsonEvent;
import com.massivecraft.massivecore.xlib.gson.JsonDeserializationContext; import com.massivecraft.massivecore.xlib.gson.JsonDeserializationContext;
import com.massivecraft.massivecore.xlib.gson.JsonDeserializer; import com.massivecraft.massivecore.xlib.gson.JsonDeserializer;
@ -27,13 +26,13 @@ public class AdapterMsonEvent implements JsonDeserializer<MsonEvent>, JsonSerial
@Override @Override
public JsonElement serialize(MsonEvent src, Type typeOfSrc, JsonSerializationContext context) public JsonElement serialize(MsonEvent src, Type typeOfSrc, JsonSerializationContext context)
{ {
return Mson.GSON.toJsonTree(src); return MsonEvent.toJson(src);
} }
@Override @Override
public MsonEvent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException public MsonEvent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{ {
return Mson.GSON.fromJson(json, MsonEvent.class); return MsonEvent.fromJson(json);
} }
} }

View File

@ -0,0 +1,41 @@
package com.massivecraft.massivecore.adapter;
import java.lang.reflect.Type;
import com.massivecraft.massivecore.mson.Mson;
import com.massivecraft.massivecore.mson.MsonEvent;
import com.massivecraft.massivecore.xlib.gson.JsonDeserializationContext;
import com.massivecraft.massivecore.xlib.gson.JsonDeserializer;
import com.massivecraft.massivecore.xlib.gson.JsonElement;
import com.massivecraft.massivecore.xlib.gson.JsonParseException;
import com.massivecraft.massivecore.xlib.gson.JsonSerializationContext;
import com.massivecraft.massivecore.xlib.gson.JsonSerializer;
public class AdapterMsonEventFix implements JsonDeserializer<MsonEvent>, JsonSerializer<MsonEvent>
{
// -------------------------------------------- //
// INSTANCE & CONSTRUCT
// -------------------------------------------- //
private static final AdapterMsonEventFix i = new AdapterMsonEventFix();
public static AdapterMsonEventFix get() { return i; }
// -------------------------------------------- //
// OVERRIDE
// -------------------------------------------- //
@Override
public JsonElement serialize(MsonEvent src, Type typeOfSrc, JsonSerializationContext context)
{
return Mson.getGson(false).toJsonTree(src);
}
@Override
public MsonEvent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
MsonEvent ret = Mson.getGson(false).fromJson(json, MsonEvent.class);
ret.repair();
return ret;
}
}

View File

@ -17,6 +17,7 @@ import org.bukkit.inventory.ItemStack;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.massivecraft.massivecore.adapter.AdapterLowercaseEnum; import com.massivecraft.massivecore.adapter.AdapterLowercaseEnum;
import com.massivecraft.massivecore.adapter.AdapterMsonEventFix;
import com.massivecraft.massivecore.collections.MassiveList; import com.massivecraft.massivecore.collections.MassiveList;
import com.massivecraft.massivecore.command.MassiveCommand; import com.massivecraft.massivecore.command.MassiveCommand;
import com.massivecraft.massivecore.mixin.MixinMessage; import com.massivecraft.massivecore.mixin.MixinMessage;
@ -26,6 +27,7 @@ import com.massivecraft.massivecore.util.Txt;
import com.massivecraft.massivecore.xlib.gson.Gson; import com.massivecraft.massivecore.xlib.gson.Gson;
import com.massivecraft.massivecore.xlib.gson.GsonBuilder; import com.massivecraft.massivecore.xlib.gson.GsonBuilder;
import com.massivecraft.massivecore.xlib.gson.JsonElement; import com.massivecraft.massivecore.xlib.gson.JsonElement;
import com.massivecraft.massivecore.xlib.gson.JsonNull;
import com.massivecraft.massivecore.xlib.gson.JsonPrimitive; import com.massivecraft.massivecore.xlib.gson.JsonPrimitive;
public class Mson implements Serializable public class Mson implements Serializable
@ -34,34 +36,60 @@ public class Mson implements Serializable
// CONSTANTS: TECHY // CONSTANTS: TECHY
// -------------------------------------------- // // -------------------------------------------- //
private static final long serialVersionUID = 1L; private static final transient long serialVersionUID = 1L;
public static final Pattern PARSE_PREFIX = Pattern.compile("\u00A7"); public static final transient Pattern PATTERN_PARSE_PREFIX = Pattern.compile("\u00A7");
public static final AdapterLowercaseEnum<ChatColor> ADAPTER_LOWERCASE_CHAT_COLOR = AdapterLowercaseEnum.get(ChatColor.class); public static final transient AdapterLowercaseEnum<ChatColor> ADAPTER_LOWERCASE_CHAT_COLOR = AdapterLowercaseEnum.get(ChatColor.class);
public static final AdapterLowercaseEnum<MsonEventAction> ADAPTER_LOWERCASE_MSON_EVENT_ACTION = AdapterLowercaseEnum.get(MsonEventAction.class); public static final transient AdapterLowercaseEnum<MsonEventAction> ADAPTER_LOWERCASE_MSON_EVENT_ACTION = AdapterLowercaseEnum.get(MsonEventAction.class);
// -------------------------------------------- // // -------------------------------------------- //
// CONSTANTS: REUSABLE MSONS // CONSTANTS: REUSABLE MSONS
// -------------------------------------------- // // -------------------------------------------- //
public static final Mson SPACE = mson(" "); public static final transient Mson SPACE = mson(" ");
public static final Mson EMPTY = mson(""); public static final transient Mson EMPTY = mson("");
public static final Mson NEWLINE = mson("\n"); public static final transient Mson NEWLINE = mson("\n");
public static final Mson DOT = mson("."); public static final transient Mson DOT = mson(".");
// -------------------------------------------- // // -------------------------------------------- //
// GSON // GSON
// -------------------------------------------- // // -------------------------------------------- //
// We need two different Gson instances that chain into each other.
// The external one contains repairs and preprocessors.
// The internal one is free from repairs and preprocessors.
// This way we can avoid stack overflows.
public static final Gson GSON; private static transient Gson GSON_EXTERNAL = null;
private static transient Gson GSON_INTERNAL = null;
static public static Gson getGson(boolean external)
{
Gson ret = (external ? GSON_EXTERNAL : GSON_INTERNAL);
if (ret == null)
{
ret = createGson(external);
if (external)
{
GSON_EXTERNAL = ret;
}
else
{
GSON_INTERNAL = ret;
}
}
return ret;
}
private static Gson createGson(boolean external)
{ {
GsonBuilder builder = new GsonBuilder(); GsonBuilder builder = new GsonBuilder();
builder.disableHtmlEscaping(); builder.disableHtmlEscaping();
if (external) builder.registerTypeAdapter(MsonEvent.class, AdapterMsonEventFix.get());
builder.registerTypeAdapter(MsonEventAction.class, ADAPTER_LOWERCASE_MSON_EVENT_ACTION); builder.registerTypeAdapter(MsonEventAction.class, ADAPTER_LOWERCASE_MSON_EVENT_ACTION);
builder.registerTypeAdapter(ChatColor.class, ADAPTER_LOWERCASE_CHAT_COLOR); builder.registerTypeAdapter(ChatColor.class, ADAPTER_LOWERCASE_CHAT_COLOR);
// For some unknown reason, the different chat colors // For some unknown reason, the different chat colors
@ -77,7 +105,7 @@ public class Mson implements Serializable
builder.registerTypeAdapter(color.getClass(), ADAPTER_LOWERCASE_CHAT_COLOR); builder.registerTypeAdapter(color.getClass(), ADAPTER_LOWERCASE_CHAT_COLOR);
} }
GSON = builder.create(); return builder.create();
} }
// -------------------------------------------- // // -------------------------------------------- //
@ -578,7 +606,7 @@ public class Mson implements Serializable
message = ensureStartsWithColorCode(message); message = ensureStartsWithColorCode(message);
// We split at color/format change. // We split at color/format change.
String[] parts = PARSE_PREFIX.split(message); String[] parts = PATTERN_PARSE_PREFIX.split(message);
// Since we start with a color, the first element will be empty. // Since we start with a color, the first element will be empty.
// We don't want that empty element. // We don't want that empty element.
@ -1195,8 +1223,15 @@ public class Mson implements Serializable
public JsonElement toJson() public JsonElement toJson()
{ {
return GSON.toJsonTree(this); return toJson(this);
} }
public static JsonElement toJson(Mson mson)
{
if (mson == null) return JsonNull.INSTANCE;
return getGson(true).toJsonTree(mson);
}
public static Mson fromJson(JsonElement json) public static Mson fromJson(JsonElement json)
{ {
// Escape the null. // Escape the null.
@ -1214,7 +1249,18 @@ public class Mson implements Serializable
// Just a normal mson. // Just a normal mson.
if (json.isJsonObject()) if (json.isJsonObject())
{ {
return GSON.fromJson(json, Mson.class); Mson ret = getGson(true).fromJson(json, Mson.class);
// TODO: Temporary Repair
MsonEvent event;
event = ret.getEvent(MsonEventType.CLICK);
if (event != null) event.repair();
event = ret.getEvent(MsonEventType.HOVER);
if (event != null) event.repair();
return ret;
} }
// Something is horribly wrong. // Something is horribly wrong.
@ -1294,42 +1340,40 @@ public class Mson implements Serializable
@Override @Override
public int hashCode() public int hashCode()
{ {
final int prime = 31; return Objects.hash(
int result = 1; this.text,
result = prime * result + Objects.hashCode(this.text); this.color,
result = prime * result + Objects.hashCode(this.color); this.bold,
result = prime * result + Objects.hashCode(this.bold); this.italic,
result = prime * result + Objects.hashCode(this.italic); this.underlined,
result = prime * result + Objects.hashCode(this.obfuscated); this.strikethrough,
result = prime * result + Objects.hashCode(this.strikethrough); this.obfuscated,
result = prime * result + Objects.hashCode(this.underlined); this.clickEvent,
result = prime * result + Objects.hashCode(this.clickEvent); this.hoverEvent,
result = prime * result + Objects.hashCode(this.hoverEvent); this.insertion,
result = prime * result + Objects.hashCode(this.insertion); this.extra
result = prime * result + Objects.hashCode(this.extra); );
return result;
} }
@Override @Override
public boolean equals(Object obj) public boolean equals(Object object)
{ {
if (this == obj) return true; if (this == object) return true;
if ( ! (obj instanceof Mson)) return false; if ( ! (object instanceof Mson)) return false;
Mson that = (Mson) obj; Mson that = (Mson)object;
return MUtil.equals(
if ( ! MUtil.equals(this.text, that.text)) return false; this.text, that.text,
if ( ! MUtil.equals(this.color, that.color)) return false; this.color, that.color,
if ( ! MUtil.equals(this.bold, that.bold)) return false; this.bold, that.bold,
if ( ! MUtil.equals(this.italic, that.italic)) return false; this.italic, that.italic,
if ( ! MUtil.equals(this.obfuscated, that.obfuscated)) return false; this.underlined, that.underlined,
if ( ! MUtil.equals(this.strikethrough, that.strikethrough)) return false; this.strikethrough, that.strikethrough,
if ( ! MUtil.equals(this.underlined, that.underlined)) return false; this.obfuscated, that.obfuscated,
if ( ! MUtil.equals(this.clickEvent, that.clickEvent)) return false; this.clickEvent, that.clickEvent,
if ( ! MUtil.equals(this.hoverEvent, that.hoverEvent)) return false; this.hoverEvent, that.hoverEvent,
if ( ! MUtil.equals(this.insertion, that.insertion)) return false; this.insertion, that.insertion,
if ( ! MUtil.equals(this.extra, that.extra)) return false; this.extra, that.extra
);
return true;
} }
} }

View File

@ -10,6 +10,7 @@ import com.massivecraft.massivecore.command.MassiveCommand;
import com.massivecraft.massivecore.nms.NmsItemStackTooltip; import com.massivecraft.massivecore.nms.NmsItemStackTooltip;
import com.massivecraft.massivecore.util.MUtil; import com.massivecraft.massivecore.util.MUtil;
import com.massivecraft.massivecore.util.Txt; import com.massivecraft.massivecore.util.Txt;
import com.massivecraft.massivecore.xlib.gson.JsonElement;
public final class MsonEvent implements Serializable public final class MsonEvent implements Serializable
{ {
@ -23,12 +24,42 @@ public final class MsonEvent implements Serializable
// FIELDS // FIELDS
// -------------------------------------------- // // -------------------------------------------- //
private final MsonEventAction action; // TODO: should be final. only temporairly mutable for repairs.
private MsonEventAction action;
public MsonEventAction getAction() { return this.action; } public MsonEventAction getAction() { return this.action; }
// TODO: should be final. only temporairly mutable for repairs.
@Deprecated
public void setAction(MsonEventAction action) { this.action = action;}
private final String value; private final String value;
public String getValue() { return this.value; } public String getValue() { return this.value; }
// -------------------------------------------- //
// REPAIR
// -------------------------------------------- //
// TODO: Remove this soon.
public void repair()
{
MsonEventAction action = this.getAction();
if (action != null) return;
String value = this.getValue();
if (value == null) return;
action = guessAction(value);
this.setAction(action);
}
private static MsonEventAction guessAction(String value)
{
if (value.startsWith("{id:")) return MsonEventAction.SHOW_ITEM;
if (value.startsWith("/")) return MsonEventAction.SUGGEST_COMMAND;
if (value.startsWith("http")) return MsonEventAction.OPEN_URL;
return MsonEventAction.SHOW_TEXT;
}
// -------------------------------------------- // // -------------------------------------------- //
// CONSTRUCT // CONSTRUCT
// -------------------------------------------- // // -------------------------------------------- //
@ -38,6 +69,12 @@ public final class MsonEvent implements Serializable
this.action = action; this.action = action;
this.value = value; this.value = value;
} }
// NoArg Constructor for GSON
protected MsonEvent()
{
this(null, null);
}
// -------------------------------------------- // // -------------------------------------------- //
// TOOLTIP // TOOLTIP
@ -136,6 +173,20 @@ public final class MsonEvent implements Serializable
// -------------------------------------------- // // -------------------------------------------- //
public MsonEventType getType() { return this.getAction().getType(); } public MsonEventType getType() { return this.getAction().getType(); }
// -------------------------------------------- //
// JSON
// -------------------------------------------- //
public static MsonEvent fromJson(JsonElement json)
{
return Mson.getGson(true).fromJson(json, MsonEvent.class);
}
public static JsonElement toJson(MsonEvent event)
{
return Mson.getGson(true).toJsonTree(event);
}
// -------------------------------------------- // // -------------------------------------------- //
// EQUALS AND HASHCODE // EQUALS AND HASHCODE
@ -144,24 +195,22 @@ public final class MsonEvent implements Serializable
@Override @Override
public int hashCode() public int hashCode()
{ {
final int prime = 31; return Objects.hash(
int result = 1; this.action,
result = prime * result + Objects.hashCode(action); this.value
result = prime * result + Objects.hashCode(value); );
return result;
} }
@Override @Override
public boolean equals(Object obj) public boolean equals(Object object)
{ {
if (this == obj) return true; if (this == object) return true;
if ( ! (obj instanceof MsonEvent)) return false; if ( ! (object instanceof MsonEvent)) return false;
MsonEvent that = (MsonEvent) obj; MsonEvent that = (MsonEvent) object;
return MUtil.equals(
if ( ! MUtil.equals(this.action, that.action)) return false; this.action, that.action,
if ( ! MUtil.equals(this.value, that.value)) return false; this.value, that.value
);
return true;
} }
} }

View File

@ -27,7 +27,7 @@ public class Test
public static Mson mson; public static Mson mson;
public static void test() public static void test()
{ {
mson = mson("hello"); mson = mson("hello");
test("ofString"); test("ofString");