1
mirror of https://github.com/CarmJos/EasyConfiguration.git synced 2026-06-04 10:38:19 +08:00

feat(adapter): Finished adapters registry

This commit is contained in:
2024-01-16 03:50:08 +08:00
parent d041828717
commit 2df33e3458
6 changed files with 163 additions and 51 deletions
@@ -3,27 +3,34 @@ package cc.carm.lib.configuration.adapter;
import cc.carm.lib.configuration.source.ConfigurationProvider;
import org.jetbrains.annotations.NotNull;
/**
* Value adapter, used to convert the value of the configuration file into the objects.
*
* @param <P> The type of the configuration provider.
* @param <B> The type of the base data
* @param <V> The type of the target value
*/
public abstract class ValueAdapter<P extends ConfigurationProvider, B, V> {
protected final Class<B> baseType;
protected final Class<V> valueType;
protected final Class<? super B> baseType;
protected final Class<? super V> valueType;
protected ValueAdapter(Class<B> baseType, Class<V> valueType) {
protected ValueAdapter(Class<? super B> baseType, Class<? super V> valueType) {
this.baseType = baseType;
this.valueType = valueType;
}
public Class<B> getBaseType() {
public Class<? super B> getBaseClass() {
return baseType;
}
public Class<V> getValueType() {
public Class<? super V> getValueClass() {
return valueType;
}
public abstract B serialize(@NotNull P provider, @NotNull V value) throws Exception;
public abstract V deserialize(@NotNull P provider, @NotNull B data) throws Exception;
public abstract V deserialize(@NotNull P provider, @NotNull Class<? extends V> clazz, @NotNull B data) throws Exception;
public boolean isAdaptedFrom(Class<?> clazz) {
return clazz.isAssignableFrom(valueType);
@@ -33,12 +40,18 @@ public abstract class ValueAdapter<P extends ConfigurationProvider, B, V> {
return isAdaptedFrom(object.getClass());
}
protected final V deserializeObject(P provider, Object data) throws Exception {
return deserialize(provider, this.baseType.cast(data));
public boolean isAdapterOf(Class<?> clazz) {
return valueType.isAssignableFrom(clazz);
}
@SuppressWarnings("unchecked")
protected final V deserializeObject(P provider, Class<?> valueClass, Object data) throws Exception {
return deserialize(provider, (Class<? extends V>) valueClass, (B) data);
}
@SuppressWarnings("unchecked")
protected final B serializeObject(P provider, Object value) throws Exception {
return serialize(provider, this.valueType.cast(value));
return serialize(provider, (V) value);
}
}
@@ -1,6 +1,6 @@
package cc.carm.lib.configuration.adapter;
import cc.carm.lib.configuration.adapter.primitive.PrimitiveAdapter;
import cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapters;
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import cc.carm.lib.configuration.source.ConfigurationProvider;
import org.jetbrains.annotations.NotNull;
@@ -18,7 +18,11 @@ public class ValueAdapterRegistry<P extends ConfigurationProvider> {
}
public void register(@NotNull ValueAdapter<P, ?, ?> adapter) {
adapters.put(adapter.valueType, adapter);
adapters.put(adapter.getValueClass(), adapter);
}
public <T> void register(Class<T> clazz, @NotNull ValueAdapter<P, ?, T> adapter) {
adapters.put(clazz, adapter);
}
public <B, V> void register(Class<B> baseClass, Class<V> valueClass,
@@ -31,7 +35,7 @@ public class ValueAdapterRegistry<P extends ConfigurationProvider> {
}
@Override
public V deserialize(@NotNull P provider, @NotNull B data) throws Exception {
public V deserialize(@NotNull P provider, @NotNull Class<? extends V> clazz, @NotNull B data) throws Exception {
return parser.parse(data);
}
});
@@ -46,17 +50,19 @@ public class ValueAdapterRegistry<P extends ConfigurationProvider> {
if (value == null) return null;
if (type == Object.class) return type.cast(value);
ValueAdapter<P, ?, ?> adapter = adapters.get(type);
ValueAdapter<P, ?, ?> adapter = getAdapter(type);
if (adapter == null) throw new RuntimeException("No adapter for type " + type.getName());
// CHECK IF VALUE IS ADAPTED FROM GIVEN VALUE'S TYPE
if (adapter.isAdaptedFrom(value)) return (T) adapter.deserializeObject(provider, value);
if (adapter.isAdaptedFrom(value)) {
return (T) adapter.deserializeObject(provider, type, value);
}
// OTHERWISE, WE NEED TO DESERIALIZE ONE BY ONE
Object baseValue = deserialize(adapter.getBaseType(), value);
Object baseValue = deserialize(adapter.getBaseClass(), value);
if (baseValue == null) return null; // Null check
return (T) adapter.deserializeObject(provider, baseValue);
return (T) adapter.deserializeObject(provider, type, baseValue);
}
public <T> Object serialize(T value) throws Exception {
@@ -66,7 +72,7 @@ public class ValueAdapterRegistry<P extends ConfigurationProvider> {
ValueAdapter<P, ?, ?> adapter = adapters.get(valueClass);
if (adapter == null) return value; // No adapters, try to return the original value
if (adapter instanceof PrimitiveAdapter) {
if (adapter instanceof PrimitiveAdapters) {
// If the value is adapted from a primitive type,
// we should serialize it into object, then return.
return adapter.serializeObject(provider, value);
@@ -76,5 +82,11 @@ public class ValueAdapterRegistry<P extends ConfigurationProvider> {
return serialize(adapter.serializeObject(provider, value));
}
public ValueAdapter<P, ?, ?> getAdapter(Class<?> clazz) {
ValueAdapter<P, ?, ?> byClass = adapters.get(clazz);
if (byClass != null) return byClass;
return adapters.values().stream().filter(adapter -> adapter.isAdapterOf(clazz)).findFirst().orElse(null);
}
}
@@ -1,30 +0,0 @@
package cc.carm.lib.configuration.adapter.primitive;
import cc.carm.lib.configuration.adapter.ValueAdapter;
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import cc.carm.lib.configuration.source.ConfigurationProvider;
import org.jetbrains.annotations.NotNull;
public abstract class PrimitiveAdapter<P extends ConfigurationProvider, T> extends ValueAdapter<P, Object, T> {
public static <P extends ConfigurationProvider, T> PrimitiveAdapter<P, T> of(@NotNull Class<T> clazz,
@NotNull ConfigDataFunction<Object, T> function) {
return new PrimitiveAdapter<P, T>(clazz) {
@Override
public T deserialize(@NotNull P provider, @NotNull Object data) throws Exception {
return function.parse(data);
}
};
}
protected PrimitiveAdapter(Class<T> valueType) {
super(Object.class, valueType);
}
@Override
public Object serialize(@NotNull P provider, @NotNull T value) throws Exception {
return value;
}
}
@@ -0,0 +1,24 @@
package cc.carm.lib.configuration.adapter.strandard;
import cc.carm.lib.configuration.adapter.ValueAdapter;
import cc.carm.lib.configuration.source.ConfigurationProvider;
import org.jetbrains.annotations.NotNull;
@SuppressWarnings({"unchecked", "rawtypes"})
public class EnumAdapter<P extends ConfigurationProvider> extends ValueAdapter<P, String, Enum> {
public EnumAdapter() {
super(String.class, Enum.class);
}
@Override
public String serialize(@NotNull P provider, @NotNull Enum value) throws Exception {
return value.name();
}
@Override
public Enum deserialize(@NotNull P provider, @NotNull Class<? extends Enum> clazz, @NotNull String data) throws Exception {
return Enum.valueOf(clazz, data);
}
}
@@ -0,0 +1,70 @@
package cc.carm.lib.configuration.adapter.strandard;
import cc.carm.lib.configuration.adapter.ValueAdapter;
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import cc.carm.lib.configuration.source.ConfigurationProvider;
import org.jetbrains.annotations.NotNull;
public abstract class PrimitiveAdapters<P extends ConfigurationProvider, T> extends ValueAdapter<P, Object, T> {
public static <P extends ConfigurationProvider> PrimitiveAdapters<P, String> ofString() {
return of(String.class, o -> o instanceof String ? (String) o : o.toString());
}
public static <P extends ConfigurationProvider> PrimitiveAdapters<P, Boolean> ofBoolean() {
return of(Boolean.class, o -> o instanceof Boolean ? (Boolean) o : Boolean.parseBoolean(o.toString()));
}
public static <P extends ConfigurationProvider> PrimitiveAdapters<P, Character> ofCharacter() {
return of(Character.class, o -> o instanceof Character ? (Character) o : o.toString().charAt(0));
}
public static <P extends ConfigurationProvider> PrimitiveAdapters<P, Integer> ofInteger() {
return ofNumber(Integer.class, Number::intValue, Integer::parseInt);
}
public static <P extends ConfigurationProvider> PrimitiveAdapters<P, Long> ofLong() {
return ofNumber(Long.class, Number::longValue, Long::parseLong);
}
public static <P extends ConfigurationProvider> PrimitiveAdapters<P, Double> ofDouble() {
return ofNumber(Double.class, Number::doubleValue, Double::parseDouble);
}
public static <P extends ConfigurationProvider> PrimitiveAdapters<P, Float> ofFloat() {
return ofNumber(Float.class, Number::floatValue, Float::parseFloat);
}
public static <P extends ConfigurationProvider> PrimitiveAdapters<P, Short> ofShort() {
return ofNumber(Short.class, Number::shortValue, Short::parseShort);
}
public static <P extends ConfigurationProvider> PrimitiveAdapters<P, Byte> ofByte() {
return ofNumber(Byte.class, Number::byteValue, Byte::parseByte);
}
protected PrimitiveAdapters(Class<T> valueType) {
super(Object.class, valueType);
}
@Override
public Object serialize(@NotNull P provider, @NotNull T value) throws Exception {
return value;
}
public static <P extends ConfigurationProvider, T> PrimitiveAdapters<P, T> of(@NotNull Class<T> clazz,
@NotNull ConfigDataFunction<Object, T> function) {
return new PrimitiveAdapters<P, T>(clazz) {
@Override
public T deserialize(@NotNull P provider, @NotNull Class<? extends T> clazz, @NotNull Object data) throws Exception {
return function.parse(data);
}
};
}
public static <P extends ConfigurationProvider, T extends Number> PrimitiveAdapters<P, T> ofNumber(@NotNull Class<T> numberClass,
@NotNull ConfigDataFunction<Number, T> castFunction,
@NotNull ConfigDataFunction<String, T> parseFunction) {
return of(numberClass, o -> o instanceof Number ? castFunction.parse((Number) o) : parseFunction.parse(o.toString()));
}
}
+27 -4
View File
@@ -1,5 +1,6 @@
import cc.carm.lib.configuration.adapter.ValueAdapterRegistry;
import cc.carm.lib.configuration.adapter.primitive.PrimitiveAdapter;
import cc.carm.lib.configuration.adapter.strandard.EnumAdapter;
import cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapters;
import cc.carm.lib.configuration.source.ConfigurationProvider;
import org.junit.Test;
@@ -12,9 +13,25 @@ public class AdaptTest {
public void test() throws Exception {
ValueAdapterRegistry<?> registry = new ValueAdapterRegistry<>(new ConfigurationProvider());
registry.register(PrimitiveAdapter.of(Long.class, data -> Long.parseLong(data.toString())));
registry.register(PrimitiveAdapter.of(Integer.class, data -> Integer.parseInt(data.toString())));
registry.register(PrimitiveAdapter.of(long.class, data -> Long.parseLong(data.toString())));
registry.register(Long.class, PrimitiveAdapters.ofLong());
registry.register(long.class, PrimitiveAdapters.ofLong());
registry.register(Integer.class, PrimitiveAdapters.ofInteger());
registry.register(int.class, PrimitiveAdapters.ofInteger());
registry.register(Double.class, PrimitiveAdapters.ofDouble());
registry.register(double.class, PrimitiveAdapters.ofDouble());
registry.register(Float.class, PrimitiveAdapters.ofFloat());
registry.register(float.class, PrimitiveAdapters.ofFloat());
registry.register(Short.class, PrimitiveAdapters.ofShort());
registry.register(short.class, PrimitiveAdapters.ofShort());
registry.register(Byte.class, PrimitiveAdapters.ofByte());
registry.register(byte.class, PrimitiveAdapters.ofByte());
registry.register(Character.class, PrimitiveAdapters.ofCharacter());
registry.register(char.class, PrimitiveAdapters.ofCharacter());
registry.register(Boolean.class, PrimitiveAdapters.ofBoolean());
registry.register(boolean.class, PrimitiveAdapters.ofBoolean());
registry.register(String.class, PrimitiveAdapters.ofString());
registry.register(new EnumAdapter<>());
registry.register(Long.class, Duration.class, Duration::ofSeconds, Duration::getSeconds);
registry.register(
Duration.class, LocalTime.class,
@@ -25,8 +42,14 @@ public class AdaptTest {
LocalTime v = registry.deserialize(LocalTime.class, "600");
Object d = registry.serialize(v);
System.out.println(v);
System.out.println(d);
System.out.println(registry.deserialize(TestEnum.class, "b"));
}
enum TestEnum {
A, b, C
}
}