Skip to content

Commit

Permalink
[6.1.0][dev] 更新 ObjectConverter 逻辑, 更新 Reflex 版本
Browse files Browse the repository at this point in the history
  • Loading branch information
Bkm016 committed Mar 31, 2024
1 parent 9ff423a commit c4e6d34
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 30 deletions.
4 changes: 2 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ subprojects {
compileOnly("com.google.guava:guava:21.0")
compileOnly("com.google.code.gson:gson:2.8.7")
compileOnly("org.apache.commons:commons-lang3:3.5")
compileOnly("org.tabooproject.reflex:reflex:1.0.19")
compileOnly("org.tabooproject.reflex:analyser:1.0.19")
compileOnly("org.tabooproject.reflex:reflex:1.0.22")
compileOnly("org.tabooproject.reflex:analyser:1.0.22")
}

java {
Expand Down
8 changes: 4 additions & 4 deletions common-reflex/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar

dependencies {
implementation("org.tabooproject.reflex:reflex:1.0.19")
implementation("org.tabooproject.reflex:analyser:1.0.19")
implementation("org.tabooproject.reflex:reflex:1.0.22")
implementation("org.tabooproject.reflex:analyser:1.0.22")
}

tasks {
withType<ShadowJar> {
dependencies {
include(dependency("org.tabooproject.reflex:reflex:1.0.19"))
include(dependency("org.tabooproject.reflex:analyser:1.0.19"))
include(dependency("org.tabooproject.reflex:reflex:1.0.22"))
include(dependency("org.tabooproject.reflex:analyser:1.0.22"))
}
relocate("org.taboooproject", "taboolib.library")
}
Expand Down
4 changes: 2 additions & 2 deletions common/src/main/java/taboolib/common/PrimitiveLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ public static void init() throws Throwable {
load(REPO_CENTRAL, i[0], i[1], i[2], IS_ISOLATED_MODE, true, rule());
}
// 加载反射模块
load(REPO_TABOOLIB, TABOOPROJECT_GROUP + ".reflex", "reflex", "1.0.19", IS_ISOLATED_MODE, true, rule());
load(REPO_TABOOLIB, TABOOPROJECT_GROUP + ".reflex", "analyser", "1.0.19", IS_ISOLATED_MODE, true, rule());
load(REPO_TABOOLIB, TABOOPROJECT_GROUP + ".reflex", "reflex", "1.0.22", IS_ISOLATED_MODE, true, rule());
load(REPO_TABOOLIB, TABOOPROJECT_GROUP + ".reflex", "analyser", "1.0.22", IS_ISOLATED_MODE, true, rule());
// 加载完整模块
loadAll();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
import com.electronwill.nightconfig.core.ConfigFormat;
import com.electronwill.nightconfig.core.EnumGetMethod;
import com.electronwill.nightconfig.core.UnmodifiableConfig;
import org.tabooproject.reflex.ClassMethod;
import org.tabooproject.reflex.Reflex;
import org.tabooproject.reflex.ReflexClass;
import org.tabooproject.reflex.UnsafeAccess;
import taboolib.module.configuration.ConvertResult;
import taboolib.module.configuration.InnerConverter;
import taboolib.module.configuration.UUIDConverter;

import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.*;
import java.util.function.Supplier;

/**
Expand Down Expand Up @@ -138,6 +141,9 @@ public <O> O toObject(UnmodifiableConfig config, Supplier<O> destinationSupplier
private void convertToConfig(Object object, Class<?> clazz, Config destination) {
// This loop walks through the class hierarchy, see clazz = clazz.getSuperclass(); at the end
while (clazz != Object.class) {
// 获取内置转换器
InnerConverter innerConverter = getInnerConverter(clazz);
// This loop walks through the fields of the class
for (Field field : clazz.getDeclaredFields()) {
// --- Checks modifiers ---
final int fieldModifiers = field.getModifiers();
Expand All @@ -158,13 +164,30 @@ private void convertToConfig(Object object, Class<?> clazz, Config destination)
} catch (IllegalAccessException e) {// Unexpected: setAccessible is called if needed
throw new ReflectionException("Unable to parse the field " + field, e);
}
AnnotationUtils.checkField(field, value);/* Checks that the value is conform to an
eventual @SpecSometing annotation */
Converter<Object, Object> converter = AnnotationUtils.getConverter(field);
// Checks that the value is conform to an eventual @SpecSometing annotation
AnnotationUtils.checkField(field, value);

// 自定义路径
List<String> path = AnnotationUtils.getPath(field);

// 内置转换器
if (innerConverter != null) {
Converter<Object, Object> ic = innerConverter.getConverter(field);
ConvertResult result = (ConvertResult) ic.convertToField(value);
if (result instanceof ConvertResult.Success) {
destination.set(path, ((ConvertResult.Success) result).getValue());
continue;
} else if (result instanceof ConvertResult.Failure) {
((ConvertResult.Failure) result).getException().printStackTrace();
continue;
}
}

// 自定义 @Converter
Converter<Object, Object> converter = getConverter(field);
if (converter != null) {
value = converter.convertFromField(value);
}
List<String> path = AnnotationUtils.getPath(field);
ConfigFormat<?> format = destination.configFormat();

// --- Writes the value to the configuration ---
Expand Down Expand Up @@ -216,6 +239,9 @@ private void convertToConfig(Object object, Class<?> clazz, Config destination)
private void convertToObject(UnmodifiableConfig config, Object object, Class<?> clazz) {
// This loop walks through the class hierarchy, see clazz = clazz.getSuperclass(); at the end
while (clazz != Object.class) {
// 获取内置转换器
InnerConverter innerConverter = getInnerConverter(clazz);
// This loop walks through the fields of the class
for (Field field : clazz.getDeclaredFields()) {
// --- Checks modifiers ---
final int fieldModifiers = field.getModifiers();
Expand All @@ -234,7 +260,22 @@ private void convertToObject(UnmodifiableConfig config, Object object, Class<?>
// --- Applies annotations ---
List<String> path = AnnotationUtils.getPath(field);
Object value = config.get(path);
Converter<Object, Object> converter = AnnotationUtils.getConverter(field);

// 内置转换器
if (innerConverter != null) {
Converter<Object, Object> ic = innerConverter.getConverter(field);
ConvertResult result = (ConvertResult) ic.convertToField(value);
if (result instanceof ConvertResult.Success) {
UnsafeAccess.INSTANCE.put(object, field, ((ConvertResult.Success) result).getValue());
continue;
} else if (result instanceof ConvertResult.Failure) {
((ConvertResult.Failure) result).getException().printStackTrace();
continue;
}
}

// 自定义 @Converter
Converter<Object, Object> converter = getConverter(field);
if (converter != null) {
value = converter.convertToField(value);
}
Expand All @@ -248,7 +289,6 @@ private void convertToObject(UnmodifiableConfig config, Object object, Class<?>
if (value instanceof UnmodifiableConfig && !(fieldType.isAssignableFrom(value.getClass()))) {
// --- Read as a sub-object ---
final UnmodifiableConfig cfg = (UnmodifiableConfig) value;

// Gets or creates the field and convert it (if null OR not preserved)
Object fieldValue = field.get(object);
if (fieldValue == null) {
Expand All @@ -258,7 +298,6 @@ private void convertToObject(UnmodifiableConfig config, Object object, Class<?>
} else if (!AnnotationUtils.mustPreserve(field, clazz)) {
convertToObject(cfg, fieldValue, field.getType());
}

} else if (value instanceof Collection && Collection.class.isAssignableFrom(fieldType)) {
// --- Reads as a collection, maybe a list of objects with conversion ---
final Collection<?> src = (Collection<?>) value;
Expand All @@ -268,33 +307,24 @@ private void convertToObject(UnmodifiableConfig config, Object object, Class<?>
final List<Class<?>> dstTypes = elementTypes(genericType);
final Class<?> dstBottomType = dstTypes.get(dstTypes.size() - 1);

if (srcBottomType == null
|| dstBottomType == null
|| dstBottomType.isAssignableFrom(srcBottomType)) {

if (srcBottomType == null || dstBottomType == null || dstBottomType.isAssignableFrom(srcBottomType)) {
// Simple list, no conversion needed
AnnotationUtils.checkField(field, value);
field.set(object, value);

} else {
// List of objects => the bottom elements need conversion

// Uses the current field value if there is one, or create a new list
Collection<Object> dst = (Collection<Object>) field.get(object);
if (dst == null) {
if (fieldType == ArrayList.class
|| fieldType.isInterface()
|| Modifier.isAbstract(fieldType.getModifiers())) {
if (fieldType == ArrayList.class || fieldType.isInterface() || Modifier.isAbstract(fieldType.getModifiers())) {
dst = new ArrayList<>(src.size());// allocates the right size
} else {
dst = (Collection<Object>) createInstance(fieldType);
}
field.set(object, dst);
}

// Converts the elements of the list
convertConfigsToObject(src, dst, dstTypes, 0);

// Applies the checks
AnnotationUtils.checkField(field, dst);
}
Expand Down Expand Up @@ -487,4 +517,33 @@ private <T> T createInstance(Class<T> tClass) {
throw new ReflectionException("Unable to create an instance of " + tClass, ex);
}
}

/**
* 获取字段的转换器
*/
private Converter getConverter(Field field) {
// 已知的包装类型
if (field.getType() == UUID.class) {
return new UUIDConverter();
}
Converter converter = AnnotationUtils.getConverter(field);
if (converter != null) return converter;
return null;
}

/**
* 获取内置转换器
*/
private InnerConverter getInnerConverter(Class<?> type) {
ReflexClass reflexClass = ReflexClass.Companion.of(type, true);
ClassMethod toField = reflexClass.getStructure().getMethodByTypeSilently("toField", Field.class, Object.class);
ClassMethod fromField = reflexClass.getStructure().getMethodByTypeSilently("fromField", Field.class, Object.class);
if (toField != null && toField.getResult().getInstance() != ConvertResult.class) {
throw new IllegalStateException("InnerConverter method must return ConvertResult");
}
if (fromField != null && fromField.getResult().getInstance() != ConvertResult.class) {
throw new IllegalStateException("InnerConverter method must return ConvertResult");
}
return new InnerConverter(toField, fromField);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package taboolib.module.configuration

/**
* TabooLib
* taboolib.module.configuration.ConvertResult
*
* @author 坏黑
* @since 2024/3/31 13:30
*/
sealed class ConvertResult(val isSuccessful: Boolean) {

/** 成功 */
class Success(val value: Any?) : ConvertResult(true)

/** 失败 */
class Failure(val exception: Throwable? = null) : ConvertResult(false)

/** 跳过 */
object Skip : ConvertResult(false)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package taboolib.module.configuration

import com.electronwill.nightconfig.core.conversion.Converter
import org.tabooproject.reflex.ClassMethod
import java.lang.reflect.Field

/**
* TabooLib
* taboolib.module.configuration.InnerConverter
*
* @author 坏黑
* @since 2024/3/31 13:37
*/
class InnerConverter(val toField: ClassMethod, val fromField: ClassMethod) {

fun getConverter(field: Field): Converter<Any, Any> {
return object : Converter<Any, Any> {

override fun convertToField(value: Any): Any {
return toField.invokeStatic(field, value)!!
}

override fun convertFromField(value: Any): Any {
return fromField.invokeStatic(field, value)!!
}
}
}
}

0 comments on commit c4e6d34

Please sign in to comment.