forked from public-mirrors/ConfigLib
Add top-level saving/loading support for Records
Records can now be saved and loaded directly using one of the several methods available. Also, the TypeSerializer has been refactored.dev
parent
a2153106b5
commit
e5028e6199
@ -1,51 +1,89 @@
|
|||||||
package de.exlll.configlib;
|
package de.exlll.configlib;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static de.exlll.configlib.Validator.requireNonNull;
|
import static de.exlll.configlib.Validator.requireNonNull;
|
||||||
|
|
||||||
abstract class TypeSerializer<T, P> implements Serializer<T, Map<?, ?>> {
|
sealed abstract class TypeSerializer<T, TC extends TypeComponent<?>>
|
||||||
|
implements Serializer<T, Map<?, ?>>
|
||||||
|
permits ConfigurationSerializer, RecordSerializer {
|
||||||
protected final Class<T> type;
|
protected final Class<T> type;
|
||||||
protected final ConfigurationProperties properties;
|
protected final ConfigurationProperties properties;
|
||||||
|
protected final NameFormatter formatter;
|
||||||
protected final Map<String, Serializer<?, ?>> serializers;
|
protected final Map<String, Serializer<?, ?>> serializers;
|
||||||
|
|
||||||
protected TypeSerializer(Class<T> type, ConfigurationProperties properties) {
|
protected TypeSerializer(Class<T> type, ConfigurationProperties properties) {
|
||||||
this.type = requireNonNull(type, "type");
|
this.type = requireNonNull(type, "type");
|
||||||
this.properties = requireNonNull(properties, "configuration properties");
|
this.properties = requireNonNull(properties, "configuration properties");
|
||||||
|
this.formatter = properties.getNameFormatter();
|
||||||
this.serializers = new SerializerMapper(type, properties).buildSerializerMap();
|
this.serializers = new SerializerMapper(type, properties).buildSerializerMap();
|
||||||
requireSerializableParts();
|
requireSerializableComponents();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final Object serialize(String partName, Object value) {
|
static <T> TypeSerializer<T, ?> newSerializerFor(
|
||||||
|
Class<T> type,
|
||||||
|
ConfigurationProperties properties
|
||||||
|
) {
|
||||||
|
return type.isRecord()
|
||||||
|
? new RecordSerializer<>(type, properties)
|
||||||
|
: new ConfigurationSerializer<>(type, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final Map<?, ?> serialize(T element) {
|
||||||
|
final Map<String, Object> result = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
for (final TC component : components()) {
|
||||||
|
final Object componentValue = component.componentValue(element);
|
||||||
|
|
||||||
|
if ((componentValue == null) && !properties.outputNulls())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
final Object serializedValue = serialize(component, componentValue);
|
||||||
|
final String formattedName = formatter.format(component.componentName());
|
||||||
|
result.put(formattedName, serializedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final Object serialize(TC component, Object value) {
|
||||||
// The following cast won't cause a ClassCastException because the serializers
|
// The following cast won't cause a ClassCastException because the serializers
|
||||||
// are selected based on the part type.
|
// are selected based on the component type.
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
final var serializer = (Serializer<Object, Object>) serializers.get(partName);
|
final var serializer = (Serializer<Object, Object>)
|
||||||
|
serializers.get(component.componentName());
|
||||||
return (value != null) ? serializer.serialize(value) : null;
|
return (value != null) ? serializer.serialize(value) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final Object deserialize(P part, String partName, Object value) {
|
protected final Object deserialize(TC component, Object value) {
|
||||||
// This unchecked cast leads to an exception if the type of the object which
|
// This unchecked cast leads to an exception if the type of the object which
|
||||||
// is deserialized is not a subtype of the type the deserializer expects.
|
// is deserialized is not a subtype of the type the deserializer expects.
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
final var serializer = (Serializer<Object, Object>) serializers.get(partName);
|
final var serializer = (Serializer<Object, Object>)
|
||||||
|
serializers.get(component.componentName());
|
||||||
|
|
||||||
final Object deserialized;
|
final Object deserialized;
|
||||||
try {
|
try {
|
||||||
deserialized = serializer.deserialize(value);
|
deserialized = serializer.deserialize(value);
|
||||||
} catch (ClassCastException e) {
|
} catch (ClassCastException e) {
|
||||||
String msg = baseDeserializeExceptionMessage(part, value) + "\n" +
|
String msg = baseDeserializeExceptionMessage(component, value) + "\n" +
|
||||||
"The type of the object to be deserialized does not " +
|
"The type of the object to be deserialized does not " +
|
||||||
"match the type the deserializer expects.";
|
"match the type the deserializer expects.";
|
||||||
throw new ConfigurationException(msg, e);
|
throw new ConfigurationException(msg, e);
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
String msg = baseDeserializeExceptionMessage(part, value);
|
String msg = baseDeserializeExceptionMessage(component, value);
|
||||||
throw new ConfigurationException(msg, e);
|
throw new ConfigurationException(msg, e);
|
||||||
}
|
}
|
||||||
return deserialized;
|
return deserialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void requireSerializableParts();
|
protected abstract void requireSerializableComponents();
|
||||||
|
|
||||||
|
protected abstract String baseDeserializeExceptionMessage(TC component, Object value);
|
||||||
|
|
||||||
|
protected abstract Iterable<TC> components();
|
||||||
|
|
||||||
protected abstract String baseDeserializeExceptionMessage(P part, Object value);
|
abstract T newDefaultInstance();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue