diff --git a/src/main/java/com/io/yutian/aulib/AuLib.java b/src/main/java/com/io/yutian/aulib/AuLib.java index 9019284..226b684 100644 --- a/src/main/java/com/io/yutian/aulib/AuLib.java +++ b/src/main/java/com/io/yutian/aulib/AuLib.java @@ -16,8 +16,10 @@ public class AuLib extends JavaPlugin { Lang.registerLangFile(this); Lang.reload(this); + } + private void registerListeners() { new GuiHandlerListener(this); } diff --git a/src/main/java/com/io/yutian/aulib/exception/SerializeException.java b/src/main/java/com/io/yutian/aulib/exception/SerializeException.java new file mode 100644 index 0000000..b9478e7 --- /dev/null +++ b/src/main/java/com/io/yutian/aulib/exception/SerializeException.java @@ -0,0 +1,9 @@ +package com.io.yutian.aulib.exception; + +public class SerializeException extends RuntimeException { + + public SerializeException(Class clazz, Throwable cause) { + super(clazz.toString()); + } + +} diff --git a/src/main/java/com/io/yutian/aulib/serialize/ISerializable.java b/src/main/java/com/io/yutian/aulib/serialize/ISerializable.java new file mode 100644 index 0000000..b0ba42d --- /dev/null +++ b/src/main/java/com/io/yutian/aulib/serialize/ISerializable.java @@ -0,0 +1,11 @@ +package com.io.yutian.aulib.serialize; + +import org.json.JSONObject; + +public interface ISerializable { + + JSONObject serialize(); + + T deserialize(JSONObject jsonObject); + +} diff --git a/src/main/java/com/io/yutian/aulib/serialize/SerializeHelper.java b/src/main/java/com/io/yutian/aulib/serialize/SerializeHelper.java new file mode 100644 index 0000000..c7a1e65 --- /dev/null +++ b/src/main/java/com/io/yutian/aulib/serialize/SerializeHelper.java @@ -0,0 +1,186 @@ +package com.io.yutian.aulib.serialize; + +import com.io.yutian.aulib.exception.SerializeException; +import com.io.yutian.aulib.util.ReflectionUtil; +import org.json.JSONArray; +import org.json.JSONObject; +import sun.misc.Unsafe; + +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.*; + +public class SerializeHelper { + + private static Map, Serializer> serializers = new HashMap<>(); + + public static void registerSerializer(Class clazz, Serializer serializer) { + serializers.put(clazz, serializer); + } + + public static JSONObject serialize(T obj) throws SerializeException { + try { + JSONObject jsonObject = new JSONObject(); + Class clazz = obj.getClass(); + for (Field field : clazz.getDeclaredFields()) { + field.setAccessible(true); + if (field.isAnnotationPresent(SerializeIgnore.class)) { + continue; + } + Object value = field.get(obj); + Object serializeValue = serializeValue(value); + jsonObject.put(field.getName(), serializeValue); + } + return jsonObject; + } catch (Exception e) { + throw new SerializeException(obj.getClass(), e); + } + } + + public static T deserialize(Class clazz, JSONObject jsonObject) throws SerializeException { + try { + Unsafe unsafe = ReflectionUtil.getUnsafe(); + T instance = (T) unsafe.allocateInstance(clazz); + for (Field field : clazz.getDeclaredFields()) { + field.setAccessible(true); + if (field.isAnnotationPresent(SerializeIgnore.class)) { + continue; + } + String name = field.getName(); + if (name.equalsIgnoreCase("this$0")) { + continue; + } + if (!jsonObject.has(name)) { + continue; + } + Object value = jsonObject.get(name); + if (value == null) { + continue; + } + Object deserializeValue = deserializeValue(field, field.getType(), value); + field.set(instance, deserializeValue); + } + return instance; + } catch (Exception e) { + throw new SerializeException(clazz, e); + } + } + + private static Object deserializeValue(Field field, Class clazz0, Object value) throws SerializeException { + Class clazz = clazz0; + if (WRAPPER_TO_PRIMITIVE.containsKey(clazz)) { + clazz = WRAPPER_TO_PRIMITIVE.get(clazz); + } + if (serializers.containsKey(clazz)) { + Serializer serializer = serializers.get(clazz); + return serializer.deserialize(value); + } + if (ISerializable.class.isAssignableFrom(clazz)) { + ISerializable iSerializable = (ISerializable) value; + JSONObject jsonObject = (JSONObject) value; + return iSerializable.deserialize(jsonObject); + } else if (clazz.isPrimitive() || clazz.equals(String.class)) { + return value; + } else if (clazz.isEnum()) { + return Enum.valueOf((Class) clazz, (String) value); + } else if (clazz.isArray()) { + JSONArray jsonArray = (JSONArray) value; + int length = jsonArray.length(); + Object object = Array.newInstance(clazz.getComponentType(), length); + for (int i = 0; i < length; i++) { + Array.set(object, i, deserializeValue(field, clazz.getComponentType(), jsonArray.get(i))); + } + return object; + } else if (List.class.isAssignableFrom(clazz)) { + List list = new ArrayList(); + JSONArray jsonArray = (JSONArray) value; + Type genericType = field.getGenericType(); + Class elementType = (Class) ((ParameterizedType) genericType).getActualTypeArguments()[0]; + for (int i = 0; i < jsonArray.length(); i++) { + list.add(deserializeValue(field, elementType, jsonArray.get(i))); + } + return list; + } else if (Map.class.isAssignableFrom(clazz)) { + Map map = new HashMap(); + Type genericType = field.getGenericType(); + Class valueType = (Class) ((ParameterizedType) genericType).getActualTypeArguments()[1]; + JSONObject jsonObject = (JSONObject) value; + for (String key : jsonObject.keySet()) { + map.put(key, deserializeValue(field, valueType, jsonObject.get(key))); + } + return map; + } + return null; + } + + private static Object serializeValue(Object value) throws SerializeException { + Class clazz = value.getClass(); + if (WRAPPER_TO_PRIMITIVE.containsKey(clazz)) { + clazz = WRAPPER_TO_PRIMITIVE.get(clazz); + } + if (serializers.containsKey(clazz)) { + Serializer serializer = serializers.get(clazz); + return serializer.serialize(value); + } + if (ISerializable.class.isAssignableFrom(clazz)) { + ISerializable iSerializable = (ISerializable) value; + return iSerializable.serialize(); + } else if (clazz.isPrimitive() || clazz.equals(String.class)) { + return value; + } else if (clazz.isEnum()) { + return ((Enum) value).name(); + } else if (clazz.isArray()) { + Class elementType = clazz.getComponentType(); + JSONArray jsonArray = new JSONArray(); + int length = Array.getLength(value); + for (int i = 0; i < length; i++) { + Object element = Array.get(value, i); + jsonArray.put(serializeValue(element)); + } + return jsonArray; + } else if (List.class.isAssignableFrom(clazz)) { + List list = (List) value; + JSONArray jsonArray = new JSONArray(); + for (Object element : list) { + jsonArray.put(serializeValue(element)); + } + return jsonArray; + } else if (Map.class.isAssignableFrom(clazz)) { + Map map = (Map) value; + JSONObject jsonObject = new JSONObject(); + for (Object key : map.keySet()) { + jsonObject.put(key.toString(), serializeValue(map.get(key))); + } + return jsonObject; + } + return null; + } + + public static final Map, Class> WRAPPER_TO_PRIMITIVE = new HashMap<>(); + + static { + WRAPPER_TO_PRIMITIVE.put(Boolean.class, boolean.class); + WRAPPER_TO_PRIMITIVE.put(Byte.class, byte.class); + WRAPPER_TO_PRIMITIVE.put(Short.class, short.class); + WRAPPER_TO_PRIMITIVE.put(Character.class, char.class); + WRAPPER_TO_PRIMITIVE.put(Integer.class, int.class); + WRAPPER_TO_PRIMITIVE.put(Long.class, long.class); + WRAPPER_TO_PRIMITIVE.put(Float.class, float.class); + WRAPPER_TO_PRIMITIVE.put(Double.class, double.class); + + registerSerializer(UUID.class, new Serializer<>() { + @Override + public Object serialize(UUID value) { + return value.toString(); + } + + @Override + public UUID deserialize(Object value) { + return UUID.fromString((String) value); + } + }); + } + +} diff --git a/src/main/java/com/io/yutian/aulib/serialize/SerializeIgnore.java b/src/main/java/com/io/yutian/aulib/serialize/SerializeIgnore.java new file mode 100644 index 0000000..7274666 --- /dev/null +++ b/src/main/java/com/io/yutian/aulib/serialize/SerializeIgnore.java @@ -0,0 +1,11 @@ +package com.io.yutian.aulib.serialize; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface SerializeIgnore { +} diff --git a/src/main/java/com/io/yutian/aulib/serialize/Serializer.java b/src/main/java/com/io/yutian/aulib/serialize/Serializer.java new file mode 100644 index 0000000..c134414 --- /dev/null +++ b/src/main/java/com/io/yutian/aulib/serialize/Serializer.java @@ -0,0 +1,9 @@ +package com.io.yutian.aulib.serialize; + +public interface Serializer { + + V serialize(K value); + + K deserialize(V value); + +}