Skip to content

Instantly share code, notes, and snippets.

@dags-
Last active Mar 19, 2018
Embed
What would you like to do?
import com.google.common.reflect.TypeToken;
import java.lang.reflect.Modifier;
import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.objectmapping.ObjectMapper;
import ninja.leaping.configurate.objectmapping.ObjectMappingException;
import ninja.leaping.configurate.objectmapping.serialize.TypeSerializer;
import ninja.leaping.configurate.objectmapping.serialize.TypeSerializers;
/**
* A TypeSerializer for interfaces and abstract classes.
*
* The interface/abstract class should not be annotated with ConfigSerializable (this may cause configurate to use
* an ObjectMapping TypeSerializer instead of the SuperSerializer).
*
* The classes implementing the interface/abstract class should be annotated for serialization as normal.
*
* Just call SuperSerializer.register() before doing stuff with configs.
*/
public final class SuperSerializer implements TypeSerializer<Object> {
@Override
public Object deserialize(TypeToken<?> type, ConfigurationNode value) throws ObjectMappingException {
String className = value.getNode("__class__").getString();
if (className == null) {
throw new ObjectMappingException("No type information present");
}
Class<?> clazz;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new ObjectMappingException("Unknown class " + className, e);
}
if (!type.getRawType().isAssignableFrom(clazz)) {
throw new ObjectMappingException("Class " + clazz + " does not extend " + type.getRawType());
}
return value.getOptions().getObjectMapperFactory().getMapper(clazz).bindToNew().populate(value);
}
@Override
@SuppressWarnings("unchecked")
public void serialize(TypeToken<?> type, Object obj, ConfigurationNode value) throws ObjectMappingException {
// this is where configurate is going wrong, it uses the type token (the super-type) rather than the object's concrete type
Class<?> clazz = obj.getClass();
if (!type.getRawType().isAssignableFrom(clazz)) {
throw new ObjectMappingException("Class " + clazz + " does not extend " + type.getRawType());
}
((ObjectMapper<Object>) value.getOptions().getObjectMapperFactory().getMapper(clazz)).bind(obj).serialize(value);
value.getNode("__class__").setValue(clazz.getName());
}
/**
* Registers the SuperSerializer to the default TypeSerializerCollection.
* Call this once before doing any ObjectMapping/Serialization.
*/
public static void register() {
TypeSerializers.getDefaultSerializers().registerPredicate(
t -> t.getRawType().isInterface() || Modifier.isAbstract(t.getRawType().getModifiers()),
new SuperSerializer()
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment