package pluginbase.config.serializers; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import pluginbase.config.SerializableConfig; import pluginbase.config.annotation.NoTypeKey; import pluginbase.config.annotation.SerializableAs; import pluginbase.config.field.Field; import pluginbase.config.field.FieldMap; import pluginbase.config.field.FieldMapper; import pluginbase.config.field.PropertyVetoException; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; class DefaultSerializer implements Serializer<Object> { @Nullable @Override public Object serialize(@Nullable Object object, @NotNull SerializerSet serializerSet) throws IllegalArgumentException { if (object == null) { return null; } FieldMap fieldMap = FieldMapper.getFieldMap(object.getClass()); Map<String, Object> serializedMap = new LinkedHashMap<>(fieldMap.size() + 1); if (!(object.getClass().isAnnotationPresent(NoTypeKey.class) && Modifier.isFinal(object.getClass().getModifiers()))) { serializedMap.put(SerializableConfig.SERIALIZED_TYPE_KEY, getAlias(object.getClass())); } for (Field field : fieldMap) { if (field.isPersistable()) { serializedMap.put(field.getName(), serializeField(object, field, serializerSet)); } } return serializedMap; } @NotNull private String getAlias(@NotNull Class clazz) { SerializableAs alias = (SerializableAs) clazz.getAnnotation(SerializableAs.class); if ((alias != null) && (alias.value() != null)) { return alias.value(); } return clazz.getName(); } @Nullable @SuppressWarnings("unchecked") protected Object serializeField(@NotNull Object object, @NotNull Field field, @NotNull SerializerSet serializerSet) { Object value = field.getValue(object); if (value == null) { return null; } return field.getSerializer(serializerSet).serialize(value, serializerSet); } @Nullable @Override public Object deserialize(@Nullable Object serialized, @NotNull Class wantedType, @NotNull SerializerSet serializerSet) throws IllegalArgumentException { if (serialized == null) { return null; } if (wantedType.isAssignableFrom(serialized.getClass())) { // Already deserialized return serialized; } if (!(serialized instanceof Map)) { throw new IllegalArgumentException("Serialized value must be a map to be deserialized as an object"); } Map data = (Map) serialized; Object typeInstance; if (wantedType.isEnum()) { Object name = data.get("name"); if (name != null) { try { typeInstance = Enum.valueOf(wantedType, name.toString()); } catch (IllegalArgumentException e) { typeInstance = Enum.valueOf(wantedType, name.toString().toUpperCase());; } } else { throw new IllegalArgumentException("The serialized enum does not contain a name which is required for deserialization"); } } else if (Modifier.isFinal(wantedType.getModifiers())) { typeInstance = InstanceUtil.createInstance(wantedType); } else { Class clazz = SerializableConfig.getClassFromSerializedData(data); if (clazz != null) { typeInstance = InstanceUtil.createInstance(clazz); } else { try { typeInstance = InstanceUtil.createInstance(wantedType); } catch (RuntimeException e) { throw new IllegalArgumentException("The serialized form does not contain enough information to deserialize", e); } } } return deserializeToObject(data, typeInstance, serializerSet); } protected static Collection<?> deserializeCollection(@NotNull Field field, @NotNull Collection<?> data, @NotNull Class asClass, @NotNull SerializerSet serializerSet) { Collection collection = CollectionSerializer.createCollection(asClass, data.size()); for (Object object : data) { Class collectionType = field.getCollectionType(); if (collectionType != null && !collectionType.equals(Object.class)) { collection.add(SerializableConfig.deserializeAs(object, field.getCollectionType(), serializerSet)); } else { collection.add(SerializableConfig.deserialize(object, serializerSet)); } } return collection; } protected static Map<?, ?> deserializeMap(@NotNull Field field, @NotNull Map<?, ?> data, @NotNull Class asClass, @NotNull SerializerSet serializerSet) { Map map = MapSerializer.createMap(asClass, data.size()); for (Map.Entry entry : data.entrySet()) { Class mapType = field.getMapType(); if (mapType != null && !mapType.equals(Object.class)) { map.put(SerializableConfig.deserialize(entry.getKey(), serializerSet), SerializableConfig.deserializeAs(entry.getValue(), mapType, serializerSet)); } else { map.put(SerializableConfig.deserialize(entry.getKey(), serializerSet), SerializableConfig.deserialize(entry.getValue(), serializerSet)); } } return map; } protected static Object deserializeFieldAs(@NotNull Field field, @NotNull Object data, @NotNull Class asClass, @NotNull SerializerSet serializerSet) { try { return field.getSerializer(serializerSet).deserialize(data, asClass, serializerSet); } catch (Exception e) { throw new RuntimeException("Exception while deserializing field '" + field + "' as class '" + asClass + "'", e); } } }