From cdb3dce63a8367e15b9bd57fd389d9537c13205c Mon Sep 17 00:00:00 2001 From: redkale Date: Thu, 29 Jun 2023 10:46:39 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96LambdaFunction/LambdaSupplier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/redkale/util/LambdaFunction.java | 2 +- .../java/org/redkale/util/LambdaSupplier.java | 2 +- .../org/redkale/util/SerializedLambda.java | 298 ------------------ src/main/java/org/redkale/util/Utility.java | 41 +++ 4 files changed, 43 insertions(+), 300 deletions(-) delete mode 100644 src/main/java/org/redkale/util/SerializedLambda.java diff --git a/src/main/java/org/redkale/util/LambdaFunction.java b/src/main/java/org/redkale/util/LambdaFunction.java index e845e920b..185be4108 100644 --- a/src/main/java/org/redkale/util/LambdaFunction.java +++ b/src/main/java/org/redkale/util/LambdaFunction.java @@ -30,7 +30,7 @@ public interface LambdaFunction extends Function, Serializable { } public static String readColumn(LambdaFunction func) { - return SerializedLambda.readColumn(func); + return Utility.readFieldName(func); } } diff --git a/src/main/java/org/redkale/util/LambdaSupplier.java b/src/main/java/org/redkale/util/LambdaSupplier.java index f26d7205f..a1d2045db 100644 --- a/src/main/java/org/redkale/util/LambdaSupplier.java +++ b/src/main/java/org/redkale/util/LambdaSupplier.java @@ -21,6 +21,6 @@ import java.util.function.Supplier; public interface LambdaSupplier extends Supplier, Serializable { public static String readColumn(LambdaSupplier func) { - return SerializedLambda.readColumn(func); + return Utility.readFieldName(func); } } diff --git a/src/main/java/org/redkale/util/SerializedLambda.java b/src/main/java/org/redkale/util/SerializedLambda.java deleted file mode 100644 index 68d262cbf..000000000 --- a/src/main/java/org/redkale/util/SerializedLambda.java +++ /dev/null @@ -1,298 +0,0 @@ -/* - * - */ -package org.redkale.util; - -import java.io.*; -import java.lang.invoke.MethodHandleInfo; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -/** - * 完全复制java.lang.invoke.SerializedLambda类源码,必须保持字段信息一样 - * - *

- * 详情见: https://redkale.org - * - * @author zhangjx - * @since 2.8.0 - * - */ -public class SerializedLambda implements Serializable { - - private static final long serialVersionUID = 8025925345765570181L; - - /** - * The capturing class. - */ - private final Class capturingClass; - - /** - * The functional interface class. - */ - private final String functionalInterfaceClass; - - /** - * The functional interface method name. - */ - private final String functionalInterfaceMethodName; - - /** - * The functional interface method signature. - */ - private final String functionalInterfaceMethodSignature; - - /** - * The implementation class. - */ - private final String implClass; - - /** - * The implementation method name. - */ - private final String implMethodName; - - /** - * The implementation method signature. - */ - private final String implMethodSignature; - - /** - * The implementation method kind. - */ - private final int implMethodKind; - - /** - * The instantiated method type. - */ - private final String instantiatedMethodType; - - /** - * The captured arguments. - */ - @SuppressWarnings("serial") // Not statically typed as Serializable - private final Object[] capturedArgs; - - /** - * Create a {@code SerializedLambda} from the low-level information present - * at the lambda factory site. - * - * @param capturingClass The class in which the lambda expression appears - * @param functionalInterfaceClass Name, in slash-delimited form, of static - * type of the returned lambda object - * @param functionalInterfaceMethodName Name of the functional interface - * method for the present at the - * lambda factory site - * @param functionalInterfaceMethodSignature Signature of the functional - * interface method present at - * the lambda factory site - * @param implMethodKind Method handle kind for the implementation method - * @param implClass Name, in slash-delimited form, for the class holding - * the implementation method - * @param implMethodName Name of the implementation method - * @param implMethodSignature Signature of the implementation method - * @param instantiatedMethodType The signature of the primary functional - * interface method after type variables - * are substituted with their instantiation - * from the capture site - * @param capturedArgs The dynamic arguments to the lambda factory site, - * which represent variables captured by - * the lambda - */ - public SerializedLambda(Class capturingClass, - String functionalInterfaceClass, - String functionalInterfaceMethodName, - String functionalInterfaceMethodSignature, - int implMethodKind, - String implClass, - String implMethodName, - String implMethodSignature, - String instantiatedMethodType, - Object[] capturedArgs) { - this.capturingClass = capturingClass; - this.functionalInterfaceClass = functionalInterfaceClass; - this.functionalInterfaceMethodName = functionalInterfaceMethodName; - this.functionalInterfaceMethodSignature = functionalInterfaceMethodSignature; - this.implMethodKind = implMethodKind; - this.implClass = implClass; - this.implMethodName = implMethodName; - this.implMethodSignature = implMethodSignature; - this.instantiatedMethodType = instantiatedMethodType; - this.capturedArgs = Objects.requireNonNull(capturedArgs).clone(); - } - - /** - * Get the name of the class that captured this lambda. - * - * @return the name of the class that captured this lambda - */ - public String getCapturingClass() { - return capturingClass.getName().replace('.', '/'); - } - - /** - * Get the name of the invoked type to which this - * lambda has been converted - * - * @return the name of the functional interface class to which - * this lambda has been converted - */ - public String getFunctionalInterfaceClass() { - return functionalInterfaceClass; - } - - /** - * Get the name of the primary method for the functional interface - * to which this lambda has been converted. - * - * @return the name of the primary methods of the functional interface - */ - public String getFunctionalInterfaceMethodName() { - return functionalInterfaceMethodName; - } - - /** - * Get the signature of the primary method for the functional - * interface to which this lambda has been converted. - * - * @return the signature of the primary method of the functional - * interface - */ - public String getFunctionalInterfaceMethodSignature() { - return functionalInterfaceMethodSignature; - } - - /** - * Get the name of the class containing the implementation - * method. - * - * @return the name of the class containing the implementation - * method - */ - public String getImplClass() { - return implClass; - } - - /** - * Get the name of the implementation method. - * - * @return the name of the implementation method - */ - public String getImplMethodName() { - return implMethodName; - } - - /** - * Get the signature of the implementation method. - * - * @return the signature of the implementation method - */ - public String getImplMethodSignature() { - return implMethodSignature; - } - - /** - * Get the method handle kind (see {@link MethodHandleInfo}) of - * the implementation method. - * - * @return the method handle kind of the implementation method - */ - public int getImplMethodKind() { - return implMethodKind; - } - - /** - * Get the signature of the primary functional interface method - * after type variables are substituted with their instantiation - * from the capture site. - * - * @return the signature of the primary functional interface method - * after type variable processing - */ - public final String getInstantiatedMethodType() { - return instantiatedMethodType; - } - - /** - * Get the count of dynamic arguments to the lambda capture site. - * - * @return the count of dynamic arguments to the lambda capture site - */ - public int getCapturedArgCount() { - return capturedArgs.length; - } - - /** - * Get a dynamic argument to the lambda capture site. - * - * @param i the argument to capture - * - * @return a dynamic argument to the lambda capture site - */ - public Object getCapturedArg(int i) { - return capturedArgs[i]; - } - - @Override - public String toString() { - String implKind = MethodHandleInfo.referenceKindToString(implMethodKind); - return String.format("SerializedLambda[%s=%s, %s=%s.%s:%s, " - + "%s=%s %s.%s:%s, %s=%s, %s=%d]", - "capturingClass", capturingClass, - "functionalInterfaceMethod", functionalInterfaceClass, - functionalInterfaceMethodName, - functionalInterfaceMethodSignature, - "implementation", - implKind, - implClass, implMethodName, implMethodSignature, - "instantiatedMethodType", instantiatedMethodType, - "numCaptured", capturedArgs.length); - } - - private static final ConcurrentHashMap cache = new ConcurrentHashMap(); - - public static String readColumn(Serializable func) { - return readFieldName(readLambda(func).getImplMethodName()); - } - - public static SerializedLambda readLambda(Serializable func) { - if (!func.getClass().isSynthetic()) { //必须是Lambda表达式的合成类 - throw new RedkaleException("Not a synthetic lambda class"); - } - return cache.computeIfAbsent(func.getClass(), clazz -> { - try { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(out); - oos.writeObject(func); - ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray())) { - @Override - protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { - Class clazz = super.resolveClass(desc); - return clazz == java.lang.invoke.SerializedLambda.class ? SerializedLambda.class : clazz; - } - }; - return (SerializedLambda) in.readObject(); - } catch (Exception e) { - throw new RedkaleException(e); - } - }); - } - - public static String readFieldName(String methodName) { - String name; - if (methodName.startsWith("is")) { - name = methodName.substring(2); - } else if (methodName.startsWith("get") || methodName.startsWith("set")) { - name = methodName.substring(3); - } else { - name = methodName; - } - if (name.length() < 2) { - return name.toLowerCase(Locale.ENGLISH); - } else if (Character.isUpperCase(name.charAt(1))) { - return name; - } else { - return name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1); - } - } -} diff --git a/src/main/java/org/redkale/util/Utility.java b/src/main/java/org/redkale/util/Utility.java index c8a8a964c..9c01a3132 100644 --- a/src/main/java/org/redkale/util/Utility.java +++ b/src/main/java/org/redkale/util/Utility.java @@ -5,6 +5,7 @@ package org.redkale.util; import java.io.*; +import java.lang.invoke.*; import java.lang.reflect.*; import java.net.*; import java.net.http.HttpClient; @@ -46,6 +47,8 @@ public final class Utility { private static final int MAX_POW2 = 1 << 30; + private static final ConcurrentHashMap lambdaFieldNameCache = new ConcurrentHashMap(); + private static final Class JAVA_RECORD_CLASS; private static final SecureRandom random = new SecureRandom(); @@ -261,6 +264,44 @@ public final class Utility { return clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers()); } + public static String readFieldName(LambdaFunction func) { + return readLambdaFieldName(func); + } + + public static String readFieldName(LambdaSupplier func) { + return readLambdaFieldName(func); + } + + private static String readLambdaFieldName(Serializable func) { + if (!func.getClass().isSynthetic()) { //必须是Lambda表达式的合成类 + throw new RedkaleException("Not a synthetic lambda class"); + } + return lambdaFieldNameCache.computeIfAbsent(func.getClass(), clazz -> { + try { + MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(func.getClass(), MethodHandles.lookup()); + MethodHandle mh = lookup.findVirtual(func.getClass(), "writeReplace", MethodType.methodType(Object.class)); + String methodName = ((SerializedLambda) mh.invoke(func)).getImplMethodName(); + String name; + if (methodName.startsWith("is")) { + name = methodName.substring(2); + } else if (methodName.startsWith("get") || methodName.startsWith("set")) { + name = methodName.substring(3); + } else { + name = methodName; + } + if (name.length() < 2) { + return name.toLowerCase(Locale.ENGLISH); + } else if (Character.isUpperCase(name.charAt(1))) { + return name; + } else { + return name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1); + } + } catch (Throwable e) { + throw new RedkaleException(e); + } + }); + } + /** * @param value from which next positive power of two will be found. *