Skip to content

Commit

Permalink
ref[storage]: refactor lambda of storage
Browse files Browse the repository at this point in the history
  • Loading branch information
jaysunxiao committed Oct 21, 2023
1 parent 592523a commit a6fe28d
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 176 deletions.
60 changes: 43 additions & 17 deletions protocol/src/main/java/com/zfoo/protocol/util/FieldUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.zfoo.protocol.exception.RunException;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Locale;

/**
Expand Down Expand Up @@ -69,29 +70,54 @@ public static String fieldToSetMethod(Class<?> clazz, Field field) {
}
}

public static String methodToProperty(String name) {
if (name.startsWith("is")) {
name = name.substring(2);
} else if (name.startsWith("get") || name.startsWith("set")) {
name = name.substring(3);
public static String getMethodToField(Class<?> clazz, String methodName) {
try {
// 查看clazz时候真的有methodName方法
clazz.getDeclaredMethod(methodName);
} catch (NoSuchMethodException e) {
throw new RunException("clazz:[{}] has no getMethod:[{}]", clazz.getSimpleName(), methodName);
}

if (name.length() == 1 || name.length() > 1 && !Character.isUpperCase(name.charAt(1))) {
name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);
var fieldName = methodName;
if (clazz.isRecord()) {
try {
clazz.getDeclaredField(fieldName);
return fieldName;
} catch (NoSuchFieldException e) {
throw new RunException("record clazz:[{}] has no field:[{}]", clazz.getSimpleName(), fieldName);
}
}

return name;
}
// get method
fieldName = StringUtils.substringAfterFirst(methodName, "get");
try {
clazz.getDeclaredField(fieldName);
return fieldName;
} catch (NoSuchFieldException e) {
}

public static boolean isProperty(String name) {
return isGetter(name) || isSetter(name);
}
fieldName = StringUtils.uncapitalize(fieldName);
try {
clazz.getDeclaredField(fieldName);
return fieldName;
} catch (NoSuchFieldException e) {
}

public static boolean isGetter(String name) {
return name.startsWith("get") && name.length() > 3 || name.startsWith("is") && name.length() > 2;
}
// is method
fieldName = StringUtils.substringAfterFirst(methodName, "is");
try {
clazz.getDeclaredField(fieldName);
return fieldName;
} catch (NoSuchFieldException e) {
}

public static boolean isSetter(String name) {
return name.startsWith("set") && name.length() > 3;
fieldName = StringUtils.uncapitalize(fieldName);
try {
clazz.getDeclaredField(fieldName);
return fieldName;
} catch (NoSuchFieldException e) {
throw new RunException("clazz:[{}] has no field for getMethod:[{}]", clazz.getSimpleName(), methodName);
}
}

}
86 changes: 78 additions & 8 deletions storage/src/main/java/com/zfoo/storage/manager/StorageObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,28 @@
package com.zfoo.storage.manager;

import com.zfoo.protocol.collection.CollectionUtils;
import com.zfoo.protocol.util.AssertionUtils;
import com.zfoo.protocol.util.IOUtils;
import com.zfoo.protocol.util.ReflectionUtils;
import com.zfoo.protocol.util.StringUtils;
import com.zfoo.protocol.util.*;
import com.zfoo.storage.interpreter.ResourceInterpreter;
import com.zfoo.storage.model.IStorage;
import com.zfoo.storage.model.IdDef;
import com.zfoo.storage.model.IndexDef;
import com.zfoo.storage.util.LambdaUtils;
import com.zfoo.storage.util.function.Func1;
import com.zfoo.storage.util.lambda.*;
import org.springframework.lang.Nullable;
import org.springframework.util.ConcurrentReferenceHashMap;

import java.io.InputStream;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;

/**
* @author godotg
*/
public class StorageObject<K, V> implements IStorage<K, V> {
// all storage data
private Map<K, V> dataMap;
// 非唯一索引
protected Map<String, Map<Object, List<V>>> indexMap = new HashMap<>();
Expand All @@ -41,9 +44,11 @@ public class StorageObject<K, V> implements IStorage<K, V> {
protected Class<?> clazz;
protected IdDef idDef;
protected Map<String, IndexDef> indexDefMap;
// 当前配置表是否在当前项目中使用,没有被使用的会清除data数据,以达到节省内存的目的
// EN: unused configuration tables will clear data to save memory.
// CN: 没有被使用的配置表会清除data数据,以达到节省内存的目的
protected boolean recycle = true;

private ConcurrentReferenceHashMap<Func1<V, ?>, String> funcCaches = new ConcurrentReferenceHashMap<>();

public static StorageObject<?, ?> parse(InputStream inputStream, Class<?> resourceClazz, String suffix) {
var idDef = IdDef.valueOf(resourceClazz);
Expand Down Expand Up @@ -162,7 +167,7 @@ public Map<K, V> getData() {

@Override
public <INDEX> List<V> getIndexes(Func1<V, INDEX> func, INDEX index) {
String indexName = LambdaUtils.getFieldName(func);
String indexName = getMethodToField(func);
var indexValues = indexMap.get(indexName);
AssertionUtils.notNull(indexValues, "The index of [indexName:{}] does not exist in the static resource [resource:{}]", indexName, clazz.getSimpleName());
var values = indexValues.get(index);
Expand All @@ -175,7 +180,7 @@ public <INDEX> List<V> getIndexes(Func1<V, INDEX> func, INDEX index) {
@Nullable
@Override
public <INDEX> V getUniqueIndex(Func1<V, INDEX> func, INDEX index) {
String uniqueIndexName = LambdaUtils.getFieldName(func);
String uniqueIndexName = getMethodToField(func);
var indexValueMap = uniqueIndexMap.get(uniqueIndexName);
AssertionUtils.notNull(indexValueMap, "There is no a unique index for [uniqueIndexName:{}] in the static resource [resource:{}]", uniqueIndexName, clazz.getSimpleName());
var value = indexValueMap.get(index);
Expand Down Expand Up @@ -212,4 +217,69 @@ public int size() {
return dataMap.size();
}

private <INDEX> String getMethodToField(Func1<V, INDEX> func) {
var indexName = funcCaches.get(func);
if (indexName != null) {
return indexName;
}

// 1. IDEA 调试模式下 lambda 表达式是一个代理
if (func instanceof Proxy) {
try {
var lambda = new IdeaProxyLambdaMeta((Proxy) func);
indexName = FieldUtils.getMethodToField(clazz, lambda.getImplMethodName());
} catch (Exception e) {
}
}

// 2. 反射读取
if (indexName == null) {
try {
var method = func.getClass().getDeclaredMethod("writeReplace");
ReflectionUtils.makeAccessible(method);
var lambda = new ReflectLambdaMeta((java.lang.invoke.SerializedLambda) method.invoke(func));
indexName = FieldUtils.getMethodToField(clazz, lambda.getImplMethodName());
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
}
}

// 3. 反射失败使用序列化的方式读取
if (indexName == null) {
try {
var lambda = new ShadowLambdaMeta(SerializedLambda.extract(func));
indexName = FieldUtils.getMethodToField(clazz, lambda.getImplMethodName());
} catch (Exception e) {
}
}

// 4. 通过将func带入到dataMap中求解,适合GraalVM环境中
if (indexName == null) {
try {
var fields = clazz.getDeclaredFields();
Arrays.stream(fields).forEach(ReflectionUtils::makeAccessible);
for (var value : dataMap.values()) {
var r = func.call(value);
var valueFields = Arrays.stream(fields)
.map(it -> ReflectionUtils.getField(it, value))
.filter(it -> it.equals(r) && it.getClass() == r.getClass())
.toList();
// 如果只有一个能匹配到func的返回值则就是这个方法
if (valueFields.size() == 1) {
for (var field : fields) {
if (!ReflectionUtils.getField(field, value).equals(r)) {
continue;
}
indexName = field.getName();
break;
}
break;
}
}
} catch (Exception e) {
}
}

funcCaches.put(func, indexName);
return indexName;
}
}
68 changes: 0 additions & 68 deletions storage/src/main/java/com/zfoo/storage/util/LambdaUtils.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import com.zfoo.protocol.buffer.ByteBufUtils;
import com.zfoo.protocol.generate.GenerateOperation;
import com.zfoo.protocol.serializer.CodeLanguage;
import com.zfoo.protocol.util.FieldUtils;
import com.zfoo.protocol.util.FileUtils;
import com.zfoo.protocol.util.JsonUtils;
import com.zfoo.storage.anno.AliasFieldName;
Expand All @@ -27,8 +26,6 @@
import com.zfoo.storage.manager.StorageInt;
import com.zfoo.storage.manager.StorageManager;
import com.zfoo.storage.util.ExportUtils;
import com.zfoo.storage.util.LambdaUtils;
import com.zfoo.storage.util.function.Func1;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.UnpooledHeapByteBuf;
import org.junit.Ignore;
Expand Down Expand Up @@ -112,13 +109,6 @@ public void test() throws Exception {
var bytes = ByteBufUtils.readAllBytes(buffer);
FileUtils.writeInputStreamToFile(new File("D:/github/godot-bird/binary_data.cfg"), new ByteArrayInputStream(bytes));

Func1<StudentResource, Integer> ageFunc = StudentResource::age;
String methodName = LambdaUtils.extract(ageFunc).getImplMethodName();
String fieldName = FieldUtils.methodToProperty(methodName);
System.out.println(methodName);
System.out.println(fieldName);


//获取storage对象
var storage = storageManager.getStorage(StudentResource.class);
//获取唯一索引的对象
Expand Down
39 changes: 0 additions & 39 deletions storage/src/test/java/com/zfoo/storage/util/FieldUtilsTest.java

This file was deleted.

This file was deleted.

Loading

0 comments on commit a6fe28d

Please sign in to comment.