mirror of
https://github.com/CarmJos/EasyConfiguration.git
synced 2026-06-04 18:48:20 +08:00
feat(record): Support record type values adapter.
This commit is contained in:
@@ -0,0 +1,66 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>cc.carm.lib</groupId>
|
||||||
|
<artifactId>configured-parent</artifactId>
|
||||||
|
<version>4.1.6</version>
|
||||||
|
<relativePath>../../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>configured-feature-record</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>16</maven.compiler.source>
|
||||||
|
<maven.compiler.target>16</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cc.carm.lib</groupId>
|
||||||
|
<artifactId>configured-core</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cc.carm.lib</groupId>
|
||||||
|
<artifactId>configured-temp</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>16</source>
|
||||||
|
<target>16</target>
|
||||||
|
<encoding>UTF-8</encoding>
|
||||||
|
<compilerArgument>-parameters</compilerArgument>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
+108
@@ -0,0 +1,108 @@
|
|||||||
|
package cc.carm.lib.configured.adapter.record;
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.adapter.ValueAdapter;
|
||||||
|
import cc.carm.lib.configuration.adapter.ValueParser;
|
||||||
|
import cc.carm.lib.configuration.adapter.ValueSerializer;
|
||||||
|
import cc.carm.lib.configuration.adapter.ValueType;
|
||||||
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
|
import cc.carm.lib.configuration.source.section.ConfigureSection;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.RecordComponent;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class RecordAdapter<T extends Record> extends ValueAdapter<T> {
|
||||||
|
|
||||||
|
public static void register(ConfigurationHolder<?> holder) {
|
||||||
|
holder.adapters().register(of(Record.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <R extends Record> RecordAdapter<R> of(@NotNull Class<R> type) {
|
||||||
|
return of(ValueType.of(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <R extends Record> RecordAdapter<R> of(@NotNull ValueType<R> type) {
|
||||||
|
return new RecordAdapter<>(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordAdapter(@NotNull ValueType<T> type) {
|
||||||
|
super(type, serializer(type), parser(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <R extends Record> ValueSerializer<R> serializer(@NotNull ValueType<R> type) {
|
||||||
|
return (holder, type1, r) -> toMap(holder, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <R extends Record> ValueParser<R> parser(@NotNull ValueType<R> type) {
|
||||||
|
return (holder, valueType, value) -> {
|
||||||
|
if (!(value instanceof ConfigureSection section)) return null;
|
||||||
|
return fromMap(holder, type.getRawType(), section.asMap());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <R extends Record> Map<String, Object> toMap(
|
||||||
|
@NotNull ConfigurationHolder<?> holder, @NotNull R record
|
||||||
|
) throws Exception {
|
||||||
|
Map<String, Object> map = new LinkedHashMap<>();
|
||||||
|
Class<?> recordClass = record.getClass();
|
||||||
|
if (!recordClass.isRecord()) {
|
||||||
|
throw new IllegalArgumentException("Object is not a record");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
for (RecordComponent component : recordClass.getRecordComponents()) {
|
||||||
|
String name = component.getName();
|
||||||
|
Method accessor = component.getAccessor();
|
||||||
|
Object value = accessor.invoke(record);
|
||||||
|
map.put(name, serializeValue(holder, value));
|
||||||
|
}
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
|
throw new RuntimeException("Failed to convert record to map", e);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <R extends Record> R fromMap(
|
||||||
|
@NotNull ConfigurationHolder<?> holder,
|
||||||
|
@NotNull Class<R> type, @NotNull Map<String, Object> data
|
||||||
|
) throws Exception {
|
||||||
|
RecordComponent[] components = type.getRecordComponents();
|
||||||
|
Object[] args = new Object[components.length];
|
||||||
|
for (int i = 0; i < components.length; i++) {
|
||||||
|
RecordComponent component = components[i];
|
||||||
|
args[i] = parseValue(holder, component.getType(), data.get(component.getName()));
|
||||||
|
}
|
||||||
|
return createInstance(type, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static Object parseValue(ConfigurationHolder<?> holder, Class<?> targetType, Object value) throws Exception {
|
||||||
|
if (value == null) return null;
|
||||||
|
if (targetType.isRecord()) {
|
||||||
|
return fromMap(holder, targetType.asSubclass(Record.class), (Map<String, Object>) value);
|
||||||
|
}
|
||||||
|
return holder.deserialize(targetType, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Object serializeValue(ConfigurationHolder<?> holder, Object value) throws Exception {
|
||||||
|
if (value == null) return null;
|
||||||
|
if (value.getClass().isRecord()) {
|
||||||
|
return toMap(holder, (Record) value);
|
||||||
|
}
|
||||||
|
return holder.serialize(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> T createInstance(Class<T> t, Object[] args) throws Exception {
|
||||||
|
Class<?>[] paramTypes = Arrays.stream(t.getRecordComponents())
|
||||||
|
.map(RecordComponent::getType).toArray(Class[]::new);
|
||||||
|
Constructor<T> constructor = t.getDeclaredConstructor(paramTypes);
|
||||||
|
constructor.setAccessible(true); // Make sure the constructor is accessible
|
||||||
|
return constructor.newInstance(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
import cc.carm.lib.configuration.Configuration;
|
||||||
|
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||||
|
import cc.carm.lib.configuration.source.temp.TempConfigFactory;
|
||||||
|
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||||
|
import cc.carm.lib.configured.adapter.record.RecordAdapter;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class RecordTest {
|
||||||
|
|
||||||
|
interface Config extends Configuration {
|
||||||
|
|
||||||
|
ConfiguredValue<Device> VAL = ConfiguredValue.of(new Device(
|
||||||
|
"device1",
|
||||||
|
"My Device",
|
||||||
|
UUID.fromString("123e4567-e89b-12d3-a456-426614174000"),
|
||||||
|
new Chip("chip1", "SN123456")
|
||||||
|
));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
|
||||||
|
ConfigurationHolder<?> holder = TempConfigFactory.create().build();
|
||||||
|
RecordAdapter.register(holder);
|
||||||
|
holder.initialize(Config.class);
|
||||||
|
|
||||||
|
System.out.println("Device ID: " + Config.VAL.resolve().id());
|
||||||
|
System.out.println("Device Name: " + Config.VAL.resolve().name());
|
||||||
|
System.out.println("Device Serial: " + Config.VAL.resolve().serial());
|
||||||
|
System.out.println("Chip ID: " + Config.VAL.resolve().chip().id());
|
||||||
|
System.out.println("Chip Serial: " + Config.VAL.resolve().chip().serialNumber());
|
||||||
|
|
||||||
|
try {
|
||||||
|
holder.save();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
printMap(holder.config().asMap(), 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public record Device(String id, String name, UUID serial, Chip chip) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Chip(String id, String serialNumber) {
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printMap(Map<String, Object> map, int indent) {
|
||||||
|
String indentStr = " ".repeat(indent);
|
||||||
|
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||||
|
if (entry.getValue() instanceof Map<?, ?> subMap) {
|
||||||
|
System.out.println(indentStr + entry.getKey() + ":");
|
||||||
|
printMap((Map<String, Object>) subMap, indent + 2);
|
||||||
|
} else if (entry.getValue() instanceof List<?> subList) {
|
||||||
|
System.out.println(indentStr + entry.getKey() + ":");
|
||||||
|
for (Object item : subList) {
|
||||||
|
if (item instanceof Map<?, ?> itemMap) {
|
||||||
|
printMap((Map<String, Object>) itemMap, indent + 2);
|
||||||
|
} else {
|
||||||
|
System.out.println(indentStr + " - " + item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println(indentStr + entry.getKey() + ": " + entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user