diff --git a/orm/src/main/java/com/zfoo/orm/manager/OrmManager.java b/orm/src/main/java/com/zfoo/orm/manager/OrmManager.java index e7f1fb0a..ca876888 100644 --- a/orm/src/main/java/com/zfoo/orm/manager/OrmManager.java +++ b/orm/src/main/java/com/zfoo/orm/manager/OrmManager.java @@ -457,8 +457,8 @@ public class OrmManager implements IOrmManager { for (var field : filedList) { // entity必须包含属性的get和set方法 - ReflectionUtils.fieldToGetMethod(clazz, field); - ReflectionUtils.fieldToSetMethod(clazz, field); + FieldUtils.fieldToGetMethod(clazz, field); + FieldUtils.fieldToSetMethod(clazz, field); // 是一个基本类型变量 var fieldType = field.getType(); diff --git a/protocol/src/main/java/com/zfoo/protocol/registration/EnhanceUtils.java b/protocol/src/main/java/com/zfoo/protocol/registration/EnhanceUtils.java index d15ebfe5..df9fd7db 100644 --- a/protocol/src/main/java/com/zfoo/protocol/registration/EnhanceUtils.java +++ b/protocol/src/main/java/com/zfoo/protocol/registration/EnhanceUtils.java @@ -21,7 +21,7 @@ import com.zfoo.protocol.generate.GenerateProtocolFile; import com.zfoo.protocol.registration.field.IFieldRegistration; import com.zfoo.protocol.serializer.enhance.*; import com.zfoo.protocol.serializer.reflect.*; -import com.zfoo.protocol.util.ReflectionUtils; +import com.zfoo.protocol.util.FieldUtils; import com.zfoo.protocol.util.StringUtils; import io.netty.buffer.ByteBuf; import javassist.*; @@ -198,7 +198,7 @@ public abstract class EnhanceUtils { .writeObject(builder, StringUtils.format("packet.{}", field.getName()), field, fieldRegistration); } else { enhanceSerializer(fieldRegistration.serializer()) - .writeObject(builder, StringUtils.format("packet.{}()", ReflectionUtils.fieldToGetMethod(packetClazz, field)), field, fieldRegistration); + .writeObject(builder, StringUtils.format("packet.{}()", FieldUtils.fieldToGetMethod(packetClazz, field)), field, fieldRegistration); } } builder.append("}"); @@ -246,7 +246,7 @@ public abstract class EnhanceUtils { if (Modifier.isPublic(field.getModifiers())) { builder.append(StringUtils.format("packet.{}={};", field.getName(), readObject)); } else { - builder.append(StringUtils.format("packet.{}({});", ReflectionUtils.fieldToSetMethod(packetClazz, field), readObject)); + builder.append(StringUtils.format("packet.{}({});", FieldUtils.fieldToSetMethod(packetClazz, field), readObject)); } } } diff --git a/protocol/src/main/java/com/zfoo/protocol/util/FieldUtils.java b/protocol/src/main/java/com/zfoo/protocol/util/FieldUtils.java new file mode 100644 index 00000000..dad325e8 --- /dev/null +++ b/protocol/src/main/java/com/zfoo/protocol/util/FieldUtils.java @@ -0,0 +1,101 @@ +package com.zfoo.protocol.util; + +import com.zfoo.protocol.exception.RunException; + +import java.lang.reflect.Field; +import java.util.Locale; + +/** + * 属性工具类 + * + * @author veione + */ +public class FieldUtils { + + public static String fieldToGetMethod(Class clazz, Field field) { + var fieldName = field.getName(); + ReflectionUtils.assertIsStandardFieldName(field); + + var methodName = "get" + StringUtils.capitalize(fieldName); + + if (clazz.isRecord()) { + methodName = fieldName; + } + + try { + clazz.getDeclaredMethod(methodName); + return methodName; + } catch (NoSuchMethodException e) { + // java的get方法对boolean值有可能对应get或者is,所以尝试获取两种不同的get方法,当两种都获取不到才抛异常 + } + + // 如果属性名的第一个字母是小写且第二个字母大写,那么该属性名直接用作 getter/setter。例如属性名为uName,对应的方法是getuName/setuName。 + // 如果属性名以大写字母开头,属性名直接用作 getter/setter 方法中 get/set 的后部分。例如属性名为Name,对应的方法是getName/setName。 + methodName = "get" + fieldName; + try { + clazz.getDeclaredMethod(methodName); + return methodName; + } catch (NoSuchMethodException e) { + } + + methodName = "is" + StringUtils.capitalize(fieldName); + try { + clazz.getDeclaredMethod(methodName); + return methodName; + } catch (NoSuchMethodException e) { + throw new RunException("field:[{}] has no getMethod or isMethod in class:[{}]", field.getName(), clazz.getCanonicalName()); + } + } + + public static String fieldToSetMethod(Class clazz, Field field) { + var fieldName = field.getName(); + + ReflectionUtils.assertIsStandardFieldName(field); + + var methodName = "set" + StringUtils.capitalize(fieldName); + + if (clazz.isRecord()) { + return methodName; + } + + try { + clazz.getDeclaredMethod(methodName, field.getType()); + return methodName; + } catch (NoSuchMethodException e) { + } + + methodName = "set" + fieldName; + try { + clazz.getDeclaredMethod(methodName, field.getType()); + return methodName; + } catch (NoSuchMethodException e) { + throw new RunException("field:[{}] has no setMethod in class:[{}]", field.getName(), clazz.getCanonicalName()); + } + } + + 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); + } + + if (name.length() == 1 || name.length() > 1 && !Character.isUpperCase(name.charAt(1))) { + name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1); + } + + return name; + } + + public static boolean isProperty(String name) { + return isGetter(name) || isSetter(name); + } + + public static boolean isGetter(String name) { + return name.startsWith("get") && name.length() > 3 || name.startsWith("is") && name.length() > 2; + } + + public static boolean isSetter(String name) { + return name.startsWith("set") && name.length() > 3; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/util/ReflectionUtils.java b/protocol/src/main/java/com/zfoo/protocol/util/ReflectionUtils.java index 4cc8296b..96758069 100644 --- a/protocol/src/main/java/com/zfoo/protocol/util/ReflectionUtils.java +++ b/protocol/src/main/java/com/zfoo/protocol/util/ReflectionUtils.java @@ -320,67 +320,6 @@ public abstract class ReflectionUtils { .toList(); } - public static String fieldToGetMethod(Class clazz, Field field) { - var fieldName = field.getName(); - assertIsStandardFieldName(field); - - var methodName = "get" + StringUtils.capitalize(fieldName); - - if (clazz.isRecord()) { - methodName = fieldName; - } - - try { - clazz.getDeclaredMethod(methodName); - return methodName; - } catch (NoSuchMethodException e) { - // java的get方法对boolean值有可能对应get或者is,所以尝试获取两种不同的get方法,当两种都获取不到才抛异常 - } - - // 如果属性名的第一个字母是小写且第二个字母大写,那么该属性名直接用作 getter/setter。例如属性名为uName,对应的方法是getuName/setuName。 - // 如果属性名以大写字母开头,属性名直接用作 getter/setter 方法中 get/set 的后部分。例如属性名为Name,对应的方法是getName/setName。 - methodName = "get" + fieldName; - try { - clazz.getDeclaredMethod(methodName); - return methodName; - } catch (NoSuchMethodException e) { - } - - methodName = "is" + StringUtils.capitalize(fieldName); - try { - clazz.getDeclaredMethod(methodName); - return methodName; - } catch (NoSuchMethodException e) { - throw new RunException("field:[{}] has no getMethod or isMethod in class:[{}]", field.getName(), clazz.getCanonicalName()); - } - } - - public static String fieldToSetMethod(Class clazz, Field field) { - var fieldName = field.getName(); - - assertIsStandardFieldName(field); - - var methodName = "set" + StringUtils.capitalize(fieldName); - - if (clazz.isRecord()) { - return methodName; - } - - try { - clazz.getDeclaredMethod(methodName, field.getType()); - return methodName; - } catch (NoSuchMethodException e) { - } - - methodName = "set" + fieldName; - try { - clazz.getDeclaredMethod(methodName, field.getType()); - return methodName; - } catch (NoSuchMethodException e) { - throw new RunException("field:[{}] has no setMethod in class:[{}]", field.getName(), clazz.getCanonicalName()); - } - } - public static Constructor getConstructor(Class clazz) { try { return clazz.getDeclaredConstructor(); diff --git a/storage/src/main/java/com/zfoo/storage/manager/StorageManager.java b/storage/src/main/java/com/zfoo/storage/manager/StorageManager.java index dd510b07..1ed45794 100644 --- a/storage/src/main/java/com/zfoo/storage/manager/StorageManager.java +++ b/storage/src/main/java/com/zfoo/storage/manager/StorageManager.java @@ -17,6 +17,7 @@ import com.zfoo.protocol.collection.CollectionUtils; import com.zfoo.protocol.exception.ExceptionUtils; import com.zfoo.protocol.exception.RunException; import com.zfoo.protocol.util.ClassUtils; +import com.zfoo.protocol.util.FieldUtils; import com.zfoo.protocol.util.FileUtils; import com.zfoo.protocol.util.GraalVmUtils; import com.zfoo.protocol.util.ReflectionUtils; @@ -123,7 +124,7 @@ public class StorageManager implements IStorageManager { var setMethodName = StringUtils.EMPTY; try { - setMethodName = ReflectionUtils.fieldToSetMethod(clazz, field); + setMethodName = FieldUtils.fieldToSetMethod(clazz, field); } catch (Exception e) { // 没有setMethod是正确的 } diff --git a/storage/src/main/java/com/zfoo/storage/util/LambdaUtils.java b/storage/src/main/java/com/zfoo/storage/util/LambdaUtils.java index 92db7271..8733cd90 100644 --- a/storage/src/main/java/com/zfoo/storage/util/LambdaUtils.java +++ b/storage/src/main/java/com/zfoo/storage/util/LambdaUtils.java @@ -1,5 +1,6 @@ package com.zfoo.storage.util; +import com.zfoo.protocol.util.FieldUtils; import com.zfoo.protocol.util.ReflectionUtils; import com.zfoo.storage.util.function.Func1; import com.zfoo.storage.util.support.IdeaProxyLambdaMeta; @@ -7,6 +8,7 @@ import com.zfoo.storage.util.support.LambdaMeta; import com.zfoo.storage.util.support.ReflectLambdaMeta; import com.zfoo.storage.util.support.SerializedLambda; import com.zfoo.storage.util.support.ShadowLambdaMeta; +import org.springframework.util.ConcurrentReferenceHashMap; import java.io.Serializable; import java.lang.reflect.Method; @@ -15,19 +17,17 @@ import java.lang.reflect.Proxy; /** * @author veione * @version 1.0 - * @date 2023/9/12 */ public final class LambdaUtils { - private static final SimpleCache FUNC_CACHE = new SimpleCache<>(64); + private static final ConcurrentReferenceHashMap CACHE = new ConcurrentReferenceHashMap<>(64, 0.75F, 16, ConcurrentReferenceHashMap.ReferenceType.WEAK); /** * 该缓存可能会在任意不定的时间被清除 * * @param func 需要解析的 lambda 对象 - * @param 类型,被调用的 Function 对象的目标类型 * @return 返回解析后的结果 */ - public static LambdaMeta extract(Serializable func) { + public static LambdaMeta extract(Serializable func) { // 1. IDEA 调试模式下 lambda 表达式是一个代理 if (func instanceof Proxy) { return new IdeaProxyLambdaMeta((Proxy) func); @@ -75,7 +75,7 @@ public final class LambdaUtils { * @return 字段名称 */ public static String getFieldName(Func1 func) { - return PropertyNamer.methodToProperty(getMethodName(func)); + return FieldUtils.methodToProperty(getMethodName(func)); } /** @@ -85,7 +85,7 @@ public final class LambdaUtils { * @param func 需要解析的 lambda 对象 * @return 返回解析后的结果 */ - private static LambdaMeta _resolve(Serializable func) { - return FUNC_CACHE.get(func.getClass(), () -> extract(func)); + private static LambdaMeta _resolve(Serializable func) { + return CACHE.computeIfAbsent(func.getClass(), c -> extract(func)); } } diff --git a/storage/src/main/java/com/zfoo/storage/util/PropertyNamer.java b/storage/src/main/java/com/zfoo/storage/util/PropertyNamer.java deleted file mode 100644 index ccd9c02d..00000000 --- a/storage/src/main/java/com/zfoo/storage/util/PropertyNamer.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.zfoo.storage.util; - - -import java.util.Locale; - -/** - * Copy from ibatis framework. - * - * @author Clinton Begin - */ -public final class PropertyNamer { - - private PropertyNamer() { - // Prevent Instantiation of Static Class - } - - 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); - } - - if (name.length() == 1 || name.length() > 1 && !Character.isUpperCase(name.charAt(1))) { - name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1); - } - - return name; - } - - public static boolean isProperty(String name) { - return isGetter(name) || isSetter(name); - } - - public static boolean isGetter(String name) { - return name.startsWith("get") && name.length() > 3 || name.startsWith("is") && name.length() > 2; - } - - public static boolean isSetter(String name) { - return name.startsWith("set") && name.length() > 3; - } - -} diff --git a/storage/src/main/java/com/zfoo/storage/util/SimpleCache.java b/storage/src/main/java/com/zfoo/storage/util/SimpleCache.java deleted file mode 100644 index 22351c49..00000000 --- a/storage/src/main/java/com/zfoo/storage/util/SimpleCache.java +++ /dev/null @@ -1,172 +0,0 @@ -package com.zfoo.storage.util; - -import com.zfoo.storage.util.function.Func0; - -import java.io.Serializable; -import java.util.Iterator; -import java.util.Map; -import java.util.WeakHashMap; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.function.Predicate; - -/** - * 简单缓存,无超时实现,默认使用{@link WeakHashMap}实现缓存自动清理 - * - * @param 键类型 - * @param 值类型 - * @author Looly - */ -public class SimpleCache implements Iterable>, Serializable { - private static final long serialVersionUID = 1L; - - /** - * 池 - */ - private final Map cache; - // 乐观读写锁 - private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - /** - * 写的时候每个key一把锁,降低锁的粒度 - */ - protected final Map keyLockMap = new ConcurrentHashMap<>(); - - /** - * 构造,默认使用{@link WeakHashMap}实现缓存自动清理 - */ - public SimpleCache() { - this(32); - } - - public SimpleCache(int initialCapacity) { - this(new WeakHashMap<>(initialCapacity)); - } - - /** - * 构造 - *

- * 通过自定义Map初始化,可以自定义缓存实现。
- * 比如使用{@link WeakHashMap}则会自动清理key,使用HashMap则不会清理
- * 同时,传入的Map对象也可以自带初始化的键值对,防止在get时创建 - *

- * - * @param initMap 初始Map,用于定义Map类型 - */ - public SimpleCache(Map initMap) { - this.cache = initMap; - } - - /** - * 从缓存池中查找值 - * - * @param key 键 - * @return 值 - */ - public V get(K key) { - lock.readLock().lock(); - try { - return cache.get(key); - } finally { - lock.readLock().unlock(); - } - } - - /** - * 从缓存中获得对象,当对象不在缓存中或已经过期返回Func0回调产生的对象 - * - * @param key 键 - * @param supplier 如果不存在回调方法,用于生产值对象 - * @return 值对象 - */ - public V get(K key, Func0 supplier) { - return get(key, null, supplier); - } - - /** - * 从缓存中获得对象,当对象不在缓存中或已经过期返回Func0回调产生的对象 - * - * @param key 键 - * @param validPredicate 检查结果对象是否可用,如是否断开连接等 - * @param supplier 如果不存在回调方法或结果不可用,用于生产值对象 - * @return 值对象 - */ - public V get(K key, Predicate validPredicate, Func0 supplier) { - V v = get(key); - if (null == v && null != supplier) { - //每个key单独获取一把锁,降低锁的粒度提高并发能力,see pr#1385@Github - final Lock keyLock = keyLockMap.computeIfAbsent(key, k -> new ReentrantLock()); - keyLock.lock(); - try { - // 双重检查,防止在竞争锁的过程中已经有其它线程写入 - v = cache.get(key); - if (null == v || (null != validPredicate && false == validPredicate.test(v))) { - try { - v = supplier.call(); - } catch (Exception e) { - throw new RuntimeException(e); - } - put(key, v); - } - } finally { - keyLock.unlock(); - keyLockMap.remove(key); - } - } - - return v; - } - - /** - * 放入缓存 - * - * @param key 键 - * @param value 值 - * @return 值 - */ - public V put(K key, V value) { - // 独占写锁 - lock.writeLock().lock(); - try { - cache.put(key, value); - } finally { - lock.writeLock().unlock(); - } - return value; - } - - /** - * 移除缓存 - * - * @param key 键 - * @return 移除的值 - */ - public V remove(K key) { - // 独占写锁 - lock.writeLock().lock(); - try { - return cache.remove(key); - } finally { - lock.writeLock().unlock(); - } - } - - /** - * 清空缓存池 - */ - public void clear() { - // 独占写锁 - lock.writeLock().lock(); - try { - this.cache.clear(); - } finally { - lock.writeLock().unlock(); - } - } - - @Override - public Iterator> iterator() { - return this.cache.entrySet().iterator(); - } -} diff --git a/storage/src/main/resources/META-INF/native-image/serialization-config.json b/storage/src/main/resources/META-INF/native-image/serialization-config.json index 7912e89b..3c3f6e45 100644 --- a/storage/src/main/resources/META-INF/native-image/serialization-config.json +++ b/storage/src/main/resources/META-INF/native-image/serialization-config.json @@ -19,6 +19,21 @@ "lambdaCapturingTypes": [ { "name": "com.zfoo.storage.util.LambdaUtils" + }, + { + "name": "com.zfoo.storage.util.support.SerializedLambda" + }, + { + "name": "java.lang.invoke.SerializedLambda" + }, + { + "name": "com.zfoo.storage.util.function.Func" + }, + { + "name": "com.zfoo.storage.util.function.Func0" + }, + { + "name": "com.zfoo.storage.util.function.Func1" } ] } diff --git a/storage/src/test/java/com/zfoo/storage/TestPropertyNamer.java b/storage/src/test/java/com/zfoo/storage/TestFieldUtils.java similarity index 55% rename from storage/src/test/java/com/zfoo/storage/TestPropertyNamer.java rename to storage/src/test/java/com/zfoo/storage/TestFieldUtils.java index 5ff48294..f4849a23 100644 --- a/storage/src/test/java/com/zfoo/storage/TestPropertyNamer.java +++ b/storage/src/test/java/com/zfoo/storage/TestFieldUtils.java @@ -1,6 +1,6 @@ package com.zfoo.storage; -import com.zfoo.storage.util.PropertyNamer; +import com.zfoo.protocol.util.FieldUtils; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -9,20 +9,20 @@ import static org.junit.Assert.assertEquals; * @author veione * @version 1.0.0 */ -public class TestPropertyNamer { +public class TestFieldUtils { @Test public void testPropertyName() { //前三种主要用于普通的POJO,第四种用于是record类型,方法名就是属性名 - String getName = PropertyNamer.methodToProperty("getName"); + String getName = FieldUtils.methodToProperty("getName"); assertEquals(getName, "name"); - String setName = PropertyNamer.methodToProperty("setName"); + String setName = FieldUtils.methodToProperty("setName"); assertEquals(setName, "name"); - String isName = PropertyNamer.methodToProperty("isName"); + String isName = FieldUtils.methodToProperty("isName"); assertEquals(isName, "name"); - String name = PropertyNamer.methodToProperty("name"); + String name = FieldUtils.methodToProperty("name"); assertEquals(name, "name"); - name = PropertyNamer.methodToProperty("Name"); + name = FieldUtils.methodToProperty("Name"); assertEquals(name, "name"); } } diff --git a/storage/src/test/java/com/zfoo/storage/TestLambdaFunction.java b/storage/src/test/java/com/zfoo/storage/TestLambdaFunction.java new file mode 100644 index 00000000..3c85f029 --- /dev/null +++ b/storage/src/test/java/com/zfoo/storage/TestLambdaFunction.java @@ -0,0 +1,42 @@ +package com.zfoo.storage; + +import com.zfoo.storage.util.LambdaUtils; +import com.zfoo.storage.util.function.Func1; +import com.zfoo.storage.util.support.LambdaMeta; +import org.junit.Test; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.util.function.Function; + +/** + * @author veione + * @version 1.0.0 + */ +public class TestLambdaFunction { + //https://blog.csdn.net/iteye_19045/article/details/119299015 + @Test + public void testFuncSerialization() throws Exception { + Func1 func = StudentResource::name; + Object object = getObject(func); + System.out.println(object); + + Class clazz = func.getClass(); + Method writeReplace = clazz.getDeclaredMethod("writeReplace"); + System.out.println(writeReplace); + + LambdaMeta meta = LambdaUtils.extract(func); + System.out.println(meta); + + Function func2 = StudentResource::name; + Method method = func2.getClass().getDeclaredMethod("writeReplace"); + object = method.invoke(func2); + System.out.println(object); + } + + private static Object getObject(Serializable func) throws Exception { + Method method = func.getClass().getDeclaredMethod("writeReplace"); + Object object = method.invoke(func); + return object; + } +} diff --git a/storage/src/test/java/com/zfoo/storage/export/ExportBinaryTesting.java b/storage/src/test/java/com/zfoo/storage/export/ExportBinaryTesting.java index 0f541916..b7ba5df4 100644 --- a/storage/src/test/java/com/zfoo/storage/export/ExportBinaryTesting.java +++ b/storage/src/test/java/com/zfoo/storage/export/ExportBinaryTesting.java @@ -16,6 +16,7 @@ import com.zfoo.protocol.ProtocolManager; 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; @@ -27,7 +28,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.PropertyNamer; import com.zfoo.storage.util.function.Func1; import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.UnpooledHeapByteBuf; @@ -114,7 +114,7 @@ public class ExportBinaryTesting { Func1 ageFunc = StudentResource::age; String methodName = LambdaUtils.extract(ageFunc).getImplMethodName(); - String fieldName = PropertyNamer.methodToProperty(methodName); + String fieldName = FieldUtils.methodToProperty(methodName); System.out.println(methodName); System.out.println(fieldName);