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
// -------------------------------------------- //
protected final Class<T> clazz;
private final Class<T> clazz;
public Class<T> getClazz() { return this.clazz; }
// -------------------------------------------- //
// INSTANCE & CONSTRUCT
// INSTANCE
// -------------------------------------------- //
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);
}
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public AdapterLowercaseEnum(Class<T> clazz)
{
if (clazz == null) throw new IllegalArgumentException("passed clazz param is null");
if ( ! clazz.isEnum()) throw new IllegalArgumentException("passed clazz param must be an enum");
if (clazz == null) throw new IllegalArgumentException("clazz is null");
if ( ! clazz.isEnum()) throw new IllegalArgumentException("clazz is not enum");
this.clazz = clazz;
}
@ -43,65 +47,76 @@ public class AdapterLowercaseEnum<T extends Enum<T>> implements JsonDeserializer
@Override
public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context)
{
// Null
if (src == null) return JsonNull.INSTANCE;
return new JsonPrimitive(src.name().toLowerCase());
String comparable = this.getComparable(src);
return new JsonPrimitive(comparable);
}
@Override
public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
{
// Null
if (json == null) return null;
T value = getEnumValueFrom(json);
return value;
if (json.equals(JsonNull.INSTANCE)) return null;
T ret = this.getEnumValueFrom(json);
return ret;
}
// -------------------------------------------- //
// UTIL
// GET ENUM VALUE FROM
// -------------------------------------------- //
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");
if ( ! clazz.isEnum()) throw new IllegalArgumentException("passed clazz param must be an enum");
Class<T> clazz = this.getClazz();
T[] ret = clazz.getEnumConstants();
if (ret == null) throw new RuntimeException("failed to retrieve enum constants at runtime");
return ret;
}
public static String getComparable(Enum<?> value)
// -------------------------------------------- //
// GET COMPARABLE
// -------------------------------------------- //
public String getComparable(Enum<?> value)
{
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;
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.JsonDeserializer;
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.JsonSerializationContext;
import com.massivecraft.massivecore.xlib.gson.JsonSerializer;
@ -27,8 +26,7 @@ public class AdapterMson implements JsonDeserializer<Mson>, JsonSerializer<Mson>
@Override
public JsonElement serialize(Mson src, Type typeOfSrc, JsonSerializationContext context)
{
if (src == null) return JsonNull.INSTANCE;
return src.toJson();
return Mson.toJson(src);
}
@Override

View File

@ -2,7 +2,6 @@ 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;
@ -27,13 +26,13 @@ public class AdapterMsonEvent implements JsonDeserializer<MsonEvent>, JsonSerial
@Override
public JsonElement serialize(MsonEvent src, Type typeOfSrc, JsonSerializationContext context)
{
return Mson.GSON.toJsonTree(src);
return MsonEvent.toJson(src);
}
@Override
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.massivecraft.massivecore.adapter.AdapterLowercaseEnum;
import com.massivecraft.massivecore.adapter.AdapterMsonEventFix;
import com.massivecraft.massivecore.collections.MassiveList;
import com.massivecraft.massivecore.command.MassiveCommand;
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.GsonBuilder;
import com.massivecraft.massivecore.xlib.gson.JsonElement;
import com.massivecraft.massivecore.xlib.gson.JsonNull;
import com.massivecraft.massivecore.xlib.gson.JsonPrimitive;
public class Mson implements Serializable
@ -34,34 +36,60 @@ public class Mson implements Serializable
// 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 AdapterLowercaseEnum<MsonEventAction> ADAPTER_LOWERCASE_MSON_EVENT_ACTION = AdapterLowercaseEnum.get(MsonEventAction.class);
public static final transient AdapterLowercaseEnum<ChatColor> ADAPTER_LOWERCASE_CHAT_COLOR = AdapterLowercaseEnum.get(ChatColor.class);
public static final transient AdapterLowercaseEnum<MsonEventAction> ADAPTER_LOWERCASE_MSON_EVENT_ACTION = AdapterLowercaseEnum.get(MsonEventAction.class);
// -------------------------------------------- //
// CONSTANTS: REUSABLE MSONS
// -------------------------------------------- //
public static final Mson SPACE = mson(" ");
public static final Mson EMPTY = mson("");
public static final Mson NEWLINE = mson("\n");
public static final Mson DOT = mson(".");
public static final transient Mson SPACE = mson(" ");
public static final transient Mson EMPTY = mson("");
public static final transient Mson NEWLINE = mson("\n");
public static final transient Mson DOT = mson(".");
// -------------------------------------------- //
// 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();
builder.disableHtmlEscaping();
if (external) builder.registerTypeAdapter(MsonEvent.class, AdapterMsonEventFix.get());
builder.registerTypeAdapter(MsonEventAction.class, ADAPTER_LOWERCASE_MSON_EVENT_ACTION);
builder.registerTypeAdapter(ChatColor.class, ADAPTER_LOWERCASE_CHAT_COLOR);
// 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);
}
GSON = builder.create();
return builder.create();
}
// -------------------------------------------- //
@ -578,7 +606,7 @@ public class Mson implements Serializable
message = ensureStartsWithColorCode(message);
// 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.
// We don't want that empty element.
@ -1195,8 +1223,15 @@ public class Mson implements Serializable
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)
{
// Escape the null.
@ -1214,7 +1249,18 @@ public class Mson implements Serializable
// Just a normal mson.
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.
@ -1294,42 +1340,40 @@ public class Mson implements Serializable
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + Objects.hashCode(this.text);
result = prime * result + Objects.hashCode(this.color);
result = prime * result + Objects.hashCode(this.bold);
result = prime * result + Objects.hashCode(this.italic);
result = prime * result + Objects.hashCode(this.obfuscated);
result = prime * result + Objects.hashCode(this.strikethrough);
result = prime * result + Objects.hashCode(this.underlined);
result = prime * result + Objects.hashCode(this.clickEvent);
result = prime * result + Objects.hashCode(this.hoverEvent);
result = prime * result + Objects.hashCode(this.insertion);
result = prime * result + Objects.hashCode(this.extra);
return result;
return Objects.hash(
this.text,
this.color,
this.bold,
this.italic,
this.underlined,
this.strikethrough,
this.obfuscated,
this.clickEvent,
this.hoverEvent,
this.insertion,
this.extra
);
}
@Override
public boolean equals(Object obj)
public boolean equals(Object object)
{
if (this == obj) return true;
if ( ! (obj instanceof Mson)) return false;
Mson that = (Mson) obj;
if ( ! MUtil.equals(this.text, that.text)) return false;
if ( ! MUtil.equals(this.color, that.color)) return false;
if ( ! MUtil.equals(this.bold, that.bold)) return false;
if ( ! MUtil.equals(this.italic, that.italic)) return false;
if ( ! MUtil.equals(this.obfuscated, that.obfuscated)) return false;
if ( ! MUtil.equals(this.strikethrough, that.strikethrough)) return false;
if ( ! MUtil.equals(this.underlined, that.underlined)) return false;
if ( ! MUtil.equals(this.clickEvent, that.clickEvent)) return false;
if ( ! MUtil.equals(this.hoverEvent, that.hoverEvent)) return false;
if ( ! MUtil.equals(this.insertion, that.insertion)) return false;
if ( ! MUtil.equals(this.extra, that.extra)) return false;
return true;
if (this == object) return true;
if ( ! (object instanceof Mson)) return false;
Mson that = (Mson)object;
return MUtil.equals(
this.text, that.text,
this.color, that.color,
this.bold, that.bold,
this.italic, that.italic,
this.underlined, that.underlined,
this.strikethrough, that.strikethrough,
this.obfuscated, that.obfuscated,
this.clickEvent, that.clickEvent,
this.hoverEvent, that.hoverEvent,
this.insertion, that.insertion,
this.extra, that.extra
);
}
}

View File

@ -10,6 +10,7 @@ import com.massivecraft.massivecore.command.MassiveCommand;
import com.massivecraft.massivecore.nms.NmsItemStackTooltip;
import com.massivecraft.massivecore.util.MUtil;
import com.massivecraft.massivecore.util.Txt;
import com.massivecraft.massivecore.xlib.gson.JsonElement;
public final class MsonEvent implements Serializable
{
@ -23,12 +24,42 @@ public final class MsonEvent implements Serializable
// FIELDS
// -------------------------------------------- //
private final MsonEventAction action;
// TODO: should be final. only temporairly mutable for repairs.
private MsonEventAction 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;
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
// -------------------------------------------- //
@ -38,6 +69,12 @@ public final class MsonEvent implements Serializable
this.action = action;
this.value = value;
}
// NoArg Constructor for GSON
protected MsonEvent()
{
this(null, null);
}
// -------------------------------------------- //
// TOOLTIP
@ -136,6 +173,20 @@ public final class MsonEvent implements Serializable
// -------------------------------------------- //
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
@ -144,24 +195,22 @@ public final class MsonEvent implements Serializable
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + Objects.hashCode(action);
result = prime * result + Objects.hashCode(value);
return result;
return Objects.hash(
this.action,
this.value
);
}
@Override
public boolean equals(Object obj)
public boolean equals(Object object)
{
if (this == obj) return true;
if ( ! (obj instanceof MsonEvent)) return false;
MsonEvent that = (MsonEvent) obj;
if ( ! MUtil.equals(this.action, that.action)) return false;
if ( ! MUtil.equals(this.value, that.value)) return false;
return true;
if (this == object) return true;
if ( ! (object instanceof MsonEvent)) return false;
MsonEvent that = (MsonEvent) object;
return MUtil.equals(
this.action, that.action,
this.value, that.value
);
}
}

View File

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