v0.1.0
CI/CD / build-deploy (pull_request) Successful in 10s

This commit is contained in:
Timi
2026-10-01 19:47:58 +08:00
parent 62f35bdb78
commit 0609cca382
9 changed files with 287 additions and 27 deletions
@@ -2,8 +2,8 @@ package com.imyeyu.config;
import com.imyeyu.io.IO;
import com.imyeyu.io.IOSize;
import com.imyeyu.java.bean.timi.TimiCode;
import com.imyeyu.java.bean.timi.TimiException;
import com.imyeyu.java.bean.ActionException;
import com.imyeyu.java.bean.ResultCode;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
@@ -13,11 +13,15 @@ import org.yaml.snakeyaml.representer.Representer;
import java.io.File;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 配置加载器 - SnakeYAML 封装
@@ -68,7 +72,7 @@ public class ConfigLoader<T> {
try {
IO.resourceToDisk(getClass(), srcPath, distPath);
} catch (Exception e) {
throw new TimiException(TimiCode.ERROR, "load default config error", e);
throw new ActionException(ResultCode.ERROR, "load default config error", e);
}
}
@@ -119,7 +123,7 @@ public class ConfigLoader<T> {
value = (T) raw;
return value;
} catch (Exception e) {
throw new TimiException(TimiCode.ERROR, "load config error: " + file.getAbsolutePath(), e);
throw new ActionException(ResultCode.ERROR, "load config error: " + file.getAbsolutePath(), e);
}
}
@@ -133,7 +137,7 @@ public class ConfigLoader<T> {
IO.toFile(file, yamlContent);
} catch (Exception e) {
throw new TimiException(TimiCode.ERROR, "dump config error: " + file.getAbsolutePath(), e);
throw new ActionException(ResultCode.ERROR, "dump config error: " + file.getAbsolutePath(), e);
}
}
@@ -155,7 +159,7 @@ public class ConfigLoader<T> {
applyMapToObject(map, instance);
return instance;
} catch (Exception e) {
throw new TimiException(TimiCode.ERROR, "map to bean error: " + targetClass.getName(), e);
throw new ActionException(ResultCode.ERROR, "map to bean error: " + targetClass.getName(), e);
}
}
@@ -187,30 +191,81 @@ public class ConfigLoader<T> {
}
private Object convertFieldValue(Field field, Object rawValue) {
Object preparedRawValue = convertTypeValue(field.getGenericType(), rawValue);
BaseConverter<?, ?> converter = converters.get(field.getType());
if (converter != null) {
return converter.deserialize0(field, rawValue);
return converter.deserialize0(field, preparedRawValue);
}
if (rawValue == null) {
if (preparedRawValue == null) {
return null;
}
Class<?> fieldType = field.getType();
if (fieldType.isEnum()) {
return toEnumValue(fieldType, rawValue.toString());
if (fieldType.isInstance(preparedRawValue)) {
return preparedRawValue;
}
if (fieldType.isArray() && rawValue instanceof Iterable<?> rawIterable) {
if (fieldType.isEnum()) {
return toEnumValue(fieldType, preparedRawValue.toString());
}
if (fieldType.isArray() && preparedRawValue instanceof Iterable<?> rawIterable) {
return toArrayValue(fieldType.getComponentType(), rawIterable);
}
if (rawValue instanceof Map<?, ?> rawMap && shouldMapToBean(fieldType)) {
if (preparedRawValue instanceof Map<?, ?> rawMap && shouldMapToBean(fieldType)) {
return mapToBean(rawMap, fieldType);
}
return convertScalarValue(fieldType, rawValue);
return convertScalarValue(fieldType, preparedRawValue);
}
private Object convertTypeValue(Type targetType, Object rawValue) {
if (rawValue == null) {
return null;
}
if (targetType instanceof ParameterizedType pt) {
return convertParameterizedValue(pt, rawValue);
}
if (targetType instanceof Class<?> targetClass) {
return convertClassValue(targetClass, rawValue);
}
return rawValue;
}
private Object convertParameterizedValue(ParameterizedType targetType, Object rawValue) {
Type rawType = targetType.getRawType();
if (!(rawType instanceof Class<?> rawClass)) {
return rawValue;
}
if (Iterable.class.isAssignableFrom(rawClass) && rawValue instanceof Iterable<?> rawIterable) {
return toCollectionValue(rawClass, targetType.getActualTypeArguments()[0], rawIterable);
}
if (Map.class.isAssignableFrom(rawClass) && rawValue instanceof Map<?, ?> rawMap) {
Type[] actualTypeArguments = targetType.getActualTypeArguments();
return toMapValue(actualTypeArguments[0], actualTypeArguments[1], rawMap);
}
return convertClassValue(rawClass, rawValue);
}
private Object convertClassValue(Class<?> targetClass, Object rawValue) {
if (rawValue == null) {
return null;
}
if (targetClass.isInstance(rawValue)) {
return rawValue;
}
if (targetClass.isEnum()) {
return toEnumValue(targetClass, rawValue.toString());
}
if (targetClass.isArray() && rawValue instanceof Iterable<?> rawIterable) {
return toArrayValue(targetClass.getComponentType(), rawIterable);
}
if (rawValue instanceof Map<?, ?> rawMap && shouldMapToBean(targetClass)) {
return mapToBean(rawMap, targetClass);
}
return convertScalarValue(targetClass, rawValue);
}
private Object toArrayValue(Class<?> componentType, Iterable<?> rawIterable) {
List<Object> values = new ArrayList<>();
for (Object rawElement : rawIterable) {
values.add(convertArrayElement(componentType, rawElement));
values.add(convertTypeValue(componentType, rawElement));
}
Object array = Array.newInstance(componentType, values.size());
for (int i = 0; i < values.size(); i++) {
@@ -219,17 +274,29 @@ public class ConfigLoader<T> {
return array;
}
private Object convertArrayElement(Class<?> componentType, Object rawElement) {
if (rawElement == null) {
return null;
private Object toCollectionValue(Class<?> collectionType, Type elementType, Iterable<?> rawIterable) {
if (Set.class.isAssignableFrom(collectionType)) {
Set<Object> values = new LinkedHashSet<>();
for (Object rawElement : rawIterable) {
values.add(convertTypeValue(elementType, rawElement));
}
return values;
}
if (componentType.isEnum()) {
return toEnumValue(componentType, rawElement.toString());
List<Object> values = new ArrayList<>();
for (Object rawElement : rawIterable) {
values.add(convertTypeValue(elementType, rawElement));
}
if (rawElement instanceof Map<?, ?> rawMap && shouldMapToBean(componentType)) {
return mapToBean(rawMap, componentType);
return values;
}
private Map<Object, Object> toMapValue(Type keyType, Type valueType, Map<?, ?> rawMap) {
Map<Object, Object> result = new LinkedHashMap<>();
for (Map.Entry<?, ?> entry : rawMap.entrySet()) {
Object key = convertTypeValue(keyType, entry.getKey());
Object value = convertTypeValue(valueType, entry.getValue());
result.put(key, value);
}
return convertScalarValue(componentType, rawElement);
return result;
}
private boolean shouldMapToBean(Class<?> fieldType) {
@@ -297,10 +364,13 @@ public class ConfigLoader<T> {
if (field != null) {
BaseConverter<?, ?> converter = converters.get(field.getType());
if (converter != null) {
return converter.serialize0(field, value);
return toYamlValue(null, converter.serialize0(field, value));
}
}
if (value == null) {
if (field != null && field.getType() == String.class) {
return "";
}
return null;
}
Class<?> valueType = value.getClass();
@@ -350,7 +420,7 @@ public class ConfigLoader<T> {
}
return result;
} catch (Exception e) {
throw new TimiException(TimiCode.ERROR, "converter error on dump", e);
throw new ActionException(ResultCode.ERROR, "converter error on dump", e);
}
}
@@ -6,6 +6,8 @@ import org.yaml.snakeyaml.nodes.NodeTuple;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.representer.Representer;
import java.util.Set;
/**
* 自定义 Representer - SnakeYAML 序列化增强
* <ul>
@@ -40,7 +42,7 @@ public class ConfigRepresenter extends Representer {
}
@Override
protected org.yaml.snakeyaml.nodes.MappingNode representJavaBean(java.util.Set<Property> properties, Object javaBean) {
protected org.yaml.snakeyaml.nodes.MappingNode representJavaBean(Set<Property> properties, Object javaBean) {
Class<?> clazz = javaBean.getClass();
// 对于非 Java 标准库的类,使用 MAP 标签而不是类名标签
if (!clazz.getName().startsWith("java.") && !clazz.getName().startsWith("javax.")) {