All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.featherfly.common.lang.LambdaUtils Maven / Gradle / Ivy


package cn.featherfly.common.lang;

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

import org.apache.commons.lang3.StringUtils;

import cn.featherfly.common.exception.ReflectException;
import cn.featherfly.common.exception.UnsupportedException;
import cn.featherfly.common.lang.function.SerializableConsumer;
import cn.featherfly.common.lang.function.SerializableSupplier;

/**
 * 

* LambdaUtils *

* . * * @author zhongj */ public class LambdaUtils { private static final Map CACHE_LAMBDA_INFO = new ConcurrentHashMap<>(8); // private static final Map CACHE_FIELD_NAME = new // ConcurrentHashMap<>(8); /** * The Class SerializedLambdaInfo. */ public static class SerializedLambdaInfo { private String methodName; private String methodDeclaredClassName; private String methodInstanceClassName; private String propertyName; private Class propertyType; private Method method; private SerializedLambda serializedLambda; /** * 返回propertyName. * * @return propertyName */ public String getPropertyName() { return propertyName; } /** * 返回methodName. * * @return methodName */ public String getMethodName() { return methodName; } /** * 返回methodDeclaredClassName. * * @return methodDeclaredClassName */ public String getMethodDeclaredClassName() { return methodDeclaredClassName; } /** * 返回methodInstanceClassName. * * @return methodInstanceClassName */ public String getMethodInstanceClassName() { return methodInstanceClassName; } /** * 返回serializedLambda. * * @return serializedLambda */ public SerializedLambda getSerializedLambda() { return serializedLambda; } /** * 返回method. * * @return method */ public Method getMethod() { return method; } /** * 返回propertyType * * @return propertyType */ public Class getPropertyType() { return propertyType; } /** * {@inheritDoc} */ @Override public String toString() { return "SerializedLambdaInfo [methodName=" + methodName + ", methodDeclaredClassName=" + methodDeclaredClassName + ", methodInstanceClassName=" + methodInstanceClassName + ", propertyName=" + propertyName + ", method=" + method + ", serializedLambda=" + serializedLambda + "]"; } } /** * The Class InstanceLambdaInfo. */ public static abstract class InstanceLambdaInfo { private SerializedLambdaInfo serializedLambdaInfo; private Object instance; /** * Instantiates a new instance lambda info. * * @param serializedLambdaInfo the serialized lambda info * @param instance the instance */ public InstanceLambdaInfo(SerializedLambdaInfo serializedLambdaInfo, Object instance) { super(); this.serializedLambdaInfo = serializedLambdaInfo; this.instance = instance; } /** * 返回serializedLambdaInfo. * * @return serializedLambdaInfo */ public SerializedLambdaInfo getSerializedLambdaInfo() { return serializedLambdaInfo; } /** * 返回instance. * * @return instance */ public Object getInstance() { return instance; } /** * {@inheritDoc} */ @Override public String toString() { return this.getClass().getSimpleName() + " [serializedLambdaInfo=" + serializedLambdaInfo + ", instance=" + instance + "]"; } } /** * The Class SerializableConsumerLambdaInfo. * * @param the generic type */ public static class SerializableConsumerLambdaInfo extends InstanceLambdaInfo implements Consumer { private Consumer consumer; private SerializableConsumerLambdaInfo(SerializedLambdaInfo serializedLambdaInfo, Consumer consumer) { super(serializedLambdaInfo, serializedLambdaInfo.getSerializedLambda().getCapturedArg(0)); this.consumer = consumer; } /** * {@inheritDoc} */ @Override public void accept(T t) { consumer.accept(t); } } /** * The Class SerializableSupplierLambdaInfo. * * @param the generic type */ public static class SerializableSupplierLambdaInfo extends InstanceLambdaInfo implements Supplier { private T value; private Supplier supplier; private boolean init; private SerializableSupplierLambdaInfo(SerializedLambdaInfo serializedLambdaInfo, Supplier supplier) { super(serializedLambdaInfo, serializedLambdaInfo.getSerializedLambda().getCapturedArg(0)); this.supplier = supplier; } /** * 返回value. * * @return value */ public T getValue() { if (!init) { value = get(); init = true; } return value; } /** * {@inheritDoc} */ @Override public String toString() { return this.getClass().getSimpleName() + " [value=" + getValue() + ", serializedLambdaInfo=" + getSerializedLambdaInfo() + ", instance=" + getInstance() + "]"; } /** * {@inheritDoc} */ @Override public T get() { return supplier.get(); } } /** * Gets the lambda info. * * @param lambda the lambda * @return the lambda info */ public static SerializedLambdaInfo getLambdaInfo(Serializable lambda) { SerializedLambda serializedLambda = getSerializedLambda(lambda); SerializedLambdaInfo info = CACHE_LAMBDA_INFO.get(serializedLambda); if (null != info) { return info; } SerializedLambdaInfo info2 = new SerializedLambdaInfo(); info2.serializedLambda = serializedLambda; info2.methodDeclaredClassName = serializedLambda.getImplClass().replaceAll("/", "."); info2.methodName = serializedLambda.getImplMethodName(); info2.propertyName = methodToPropertyName(info2.methodName); if (lambda instanceof Function || lambda instanceof BiConsumer || lambda instanceof BiFunction) { Class[] pts = getParamaeterTypes(serializedLambda.getImplMethodSignature()); info2.method = ClassUtils.getMethod(ClassUtils.forName(info2.methodDeclaredClassName), info2.methodName, pts); if (Lang.isEmpty(pts)) { info2.propertyType = info2.method.getReturnType(); } else { info2.propertyType = pts[0]; } if (serializedLambda.getCapturedArgCount() > 0) { info2.methodInstanceClassName = serializedLambda.getCapturedArg(0).getClass().getName(); } else { info2.methodInstanceClassName = StringUtils .substringBefore(serializedLambda.getInstantiatedMethodType(), ";").substring(2) .replaceAll("/", "."); } } else if (lambda instanceof Supplier) { Class obj = serializedLambda.getCapturedArg(0).getClass(); info2.methodInstanceClassName = obj.getName(); info2.method = ClassUtils.getMethod(ClassUtils.forName(info2.methodDeclaredClassName), info2.methodName, ArrayUtils.EMPTY_CLASS_ARRAY); info2.propertyType = info2.method.getReturnType(); } else if (lambda instanceof Consumer) { info2.methodInstanceClassName = serializedLambda.getCapturedArg(0).getClass().getName(); Class[] pts = getParamaeterTypes(serializedLambda.getImplMethodSignature()); info2.method = ClassUtils.getMethod(ClassUtils.forName(info2.methodDeclaredClassName), info2.methodName, pts); info2.propertyType = pts[0]; } else { throw new UnsupportedException("unsupported for " + lambda.getClass().getName()); } CACHE_LAMBDA_INFO.put(serializedLambda, info2); return info2; } // private static Class getPropertyType(String methodSignature) { // Class type = getReturnType(methodSignature); // if (type == Void.TYPE) { // Class[] types = getParamaeterTypes(methodSignature); // if (Lang.isNotEmpty(types)) { // type = types[0]; // } // } // return type; // } // private static Class getReturnType(String methodSignature) { // // ()Ljava/lang/Integer; // String str = StringUtils.substringAfterLast(methodSignature, ")"); // if (str.equals("V")) { // return Void.TYPE; // } else { // str = StringUtils.substringAfter(str, "L"); // return ClassUtils.forName(str.replaceAll("/", ".")); // } // } private static Class[] getParamaeterTypes(String methodSignature) { // "(Ljava/lang/String;)V" String str = StringUtils.substringAfter(methodSignature, "("); str = StringUtils.substringBefore(str, ")"); if (Lang.isEmpty(str)) { return ArrayUtils.EMPTY_CLASS_ARRAY; } List> types = new ArrayList<>(); for (int i = 0; i < str.length();) { char c = str.charAt(i); if (c == 'L') { int start = i + 1; for (int j = start; j < str.length(); j++) { char e = str.charAt(j); if (e == ';') { String type = str.substring(start, j); type = type.replaceAll("/", "."); types.add(ClassUtils.forName(type)); i = j; break; } } } else if (c == 'I') { types.add(Integer.TYPE); } else if (c == 'J') { types.add(Long.TYPE); } else if (c == 'F') { types.add(Float.TYPE); } else if (c == 'D') { types.add(Double.TYPE); } else if (c == 'Z') { types.add(Boolean.TYPE); } else if (c == 'B') { types.add(Byte.TYPE); } else if (c == 'S') { types.add(Short.TYPE); } else if (c == 'C') { types.add(Character.TYPE); } i++; } return types.toArray(new Class[types.size()]); } /** * Gets the serializable supplier lambda info. * * @param the generic type * @param lambda the lambda * @return the serializable supplier lambda info */ public static < T> SerializableSupplierLambdaInfo getSerializableSupplierLambdaInfo(SerializableSupplier lambda) { SerializedLambdaInfo info = getLambdaInfo(lambda); // Object value = BeanUtils.getProperty(info.getSerializedLambda().getCapturedArg(0), info.getPropertyName()); return new SerializableSupplierLambdaInfo<>(info, lambda); } /** * Gets the serializable supplier lambda info. * * @param the generic type * @param lambda the lambda * @return the serializable supplier lambda info */ public static < T> SerializableConsumerLambdaInfo getSerializableConsumerLambdaInfo(SerializableConsumer lambda) { SerializedLambdaInfo info = getLambdaInfo(lambda); return new SerializableConsumerLambdaInfo<>(info, lambda); } /** * Gets the serialized lambda. * * @param lambda the lambda * @return the serialized lambda */ public static SerializedLambda getSerializedLambda(Serializable lambda) { return computeSerializedLambda(lambda); } /** * Gets the lambda method. * * @param lambda the lambda * @return the lambda method */ public static Method getLambdaMethod(SerializedLambda lambda) { String className = lambda.getImplClass().replaceAll("/", "."); String methodName = lambda.getImplMethodName(); Method method = ClassUtils.findMethod(ClassUtils.forName(className), o -> lambda.getCapturedArgCount() == o.getParameterCount() && o.getName().equals(methodName)); return method; } /** * Gets the lambda method. * * @param lambda the lambda * @return the lambda method */ public static Method getLambdaMethod(Serializable lambda) { return getLambdaMethod(getSerializedLambda(lambda)); } /** * Gets the lambda method name. * * @param lambda the lambda * @return the lambda method name */ public static String getLambdaMethodName(Serializable lambda) { return getLambdaMethodName(computeSerializedLambda(lambda)); } /** * Gets the lambda method name. * * @param lambda the lambda * @return the lambda method name */ public static String getLambdaMethodName(SerializedLambda lambda) { return lambda.getImplMethodName(); } /** * Gets the lambda property name. * * @param lambda the lambda * @return the lambda property name */ public static String getLambdaPropertyName(Serializable lambda) { return getLambdaPropertyName(computeSerializedLambda(lambda)); } /** * Gets the lambda property name. * * @param lambda the lambda * @return the lambda property name */ public static String getLambdaPropertyName(SerializedLambda lambda) { return methodToPropertyName(getLambdaMethodName(lambda)); } private static SerializedLambda computeSerializedLambda(Serializable lambda) { try { Class cl = lambda.getClass(); Method m = cl.getDeclaredMethod("writeReplace"); m.setAccessible(true); Object replacement = m.invoke(lambda); if (!(replacement instanceof SerializedLambda)) { return null; // custom interface implementation } return (SerializedLambda) replacement; } catch (Exception e) { throw new ReflectException("get SerializedLambda fail", e); } } private static String methodToPropertyName(String methodName) { String name = null; if (methodName.startsWith("get")) { name = methodName.substring(3); } else if (methodName.startsWith("is")) { name = methodName.substring(2); } else if (methodName.startsWith("set")) { name = methodName.substring(3); } else { name = methodName; } if (name != null) { name = name.substring(0, 1).toLowerCase() + name.substring(1); } return name; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy