@@ -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.")) {
|
||||
|
||||
Reference in New Issue
Block a user