mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
完善LambdaUtil
This commit is contained in:
parent
ccc71cd61a
commit
d5174b6b64
@ -17,7 +17,7 @@ import java.lang.reflect.Type;
|
||||
*/
|
||||
public class LambdaInfo {
|
||||
|
||||
private Type instantiatedType;
|
||||
private final Type[] instantiatedTypes;
|
||||
private final Type[] parameterTypes;
|
||||
private final Type returnType;
|
||||
private final String name;
|
||||
@ -41,15 +41,21 @@ public class LambdaInfo {
|
||||
}
|
||||
int index = lambda.getInstantiatedMethodType().indexOf(";)");
|
||||
if (index > -1) {
|
||||
this.instantiatedType = ClassLoaderUtil.loadClass(StrUtil.sub(lambda.getInstantiatedMethodType(), 2, index));
|
||||
String[] instantiatedTypeNames = StrUtil.sub(lambda.getInstantiatedMethodType(), 2, index).split(";L");
|
||||
this.instantiatedTypes = new Type[instantiatedTypeNames.length];
|
||||
for (int i = 0; i < instantiatedTypeNames.length; i++) {
|
||||
this.instantiatedTypes[i] = ClassLoaderUtil.loadClass(instantiatedTypeNames[i]);
|
||||
}
|
||||
} else {
|
||||
instantiatedTypes = new Type[0];
|
||||
}
|
||||
this.clazz = (Class<?>) FieldUtil.getFieldValue(executable, "clazz");
|
||||
this.executable = executable;
|
||||
this.lambda = lambda;
|
||||
}
|
||||
|
||||
public Type getInstantiatedType() {
|
||||
return instantiatedType;
|
||||
public Type[] getInstantiatedTypes() {
|
||||
return instantiatedTypes;
|
||||
}
|
||||
|
||||
public Type[] getParameterTypes() {
|
||||
|
@ -60,7 +60,7 @@ public class LambdaUtil {
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <R> Class<R> getRealClass(final Serializable func) {
|
||||
LambdaInfo lambdaInfo = resolve(func);
|
||||
return (Class<R>) Opt.of(lambdaInfo).map(LambdaInfo::getInstantiatedType).orElseGet(lambdaInfo::getClazz);
|
||||
return (Class<R>) Opt.of(lambdaInfo).map(LambdaInfo::getInstantiatedTypes).filter(types -> types.length != 0).map(types -> types[types.length - 1]).orElseGet(lambdaInfo::getClazz);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -131,12 +131,11 @@ public class LambdaUtil {
|
||||
//region Private methods
|
||||
|
||||
/**
|
||||
* 解析lambda表达式,加了缓存。
|
||||
* 该缓存可能会在任意不定的时间被清除。
|
||||
* 解析lambda表达式,没加缓存
|
||||
*
|
||||
* <p>
|
||||
* 通过反射调用实现序列化接口函数对象的writeReplace方法,从而拿到{@link SerializedLambda}<br>
|
||||
* 该对象中包含了lambda表达式的所有信息。
|
||||
* 该对象中包含了lambda表达式的大部分信息。
|
||||
* </p>
|
||||
*
|
||||
* @param func 需要解析的 lambda 对象
|
||||
@ -147,11 +146,11 @@ public class LambdaUtil {
|
||||
return (SerializedLambda) func;
|
||||
}
|
||||
if (func instanceof Proxy) {
|
||||
throw new UtilException("not support proxy, just for now");
|
||||
throw new IllegalArgumentException("not support proxy, just for now");
|
||||
}
|
||||
final Class<? extends Serializable> clazz = func.getClass();
|
||||
if (!clazz.isSynthetic()) {
|
||||
throw new UtilException("Not a lambda expression: " + clazz.getName());
|
||||
throw new IllegalArgumentException("Not a lambda expression: " + clazz.getName());
|
||||
}
|
||||
final Object serLambda = MethodUtil.invoke(func, "writeReplace");
|
||||
if (Objects.nonNull(serLambda) && serLambda instanceof SerializedLambda) {
|
||||
|
@ -6,7 +6,9 @@ import lombok.EqualsAndHashCode;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -14,13 +16,15 @@ public class LambdaUtilTest {
|
||||
|
||||
@Test
|
||||
public void getMethodNameTest() {
|
||||
final String methodName = LambdaUtil.getMethodName(MyTeacher::getAge);
|
||||
Func1<MyTeacher, String> lambda = MyTeacher::getAge;
|
||||
final String methodName = LambdaUtil.getMethodName(lambda);
|
||||
Assert.assertEquals("getAge", methodName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFieldNameTest() {
|
||||
final String fieldName = LambdaUtil.getFieldName(MyTeacher::getAge);
|
||||
Func1<MyTeacher, String> lambda = MyTeacher::getAge;
|
||||
final String fieldName = LambdaUtil.getFieldName(lambda);
|
||||
Assert.assertEquals("age", fieldName);
|
||||
}
|
||||
|
||||
@ -40,20 +44,45 @@ public class LambdaUtilTest {
|
||||
Assert.assertEquals(MyTeacher.class, ((Class<Array>) lambdaInfo.getReturnType()).getComponentType());
|
||||
}, () -> {
|
||||
// 引用静态方法
|
||||
Func0<String> noArgsStaticMethod = MyTeacher::takeAge;
|
||||
LambdaInfo lambdaInfo = LambdaUtil.resolve(noArgsStaticMethod);
|
||||
Func0<String> lambda = MyTeacher::takeAge;
|
||||
LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda);
|
||||
Assert.assertEquals(0, lambdaInfo.getParameterTypes().length);
|
||||
Assert.assertEquals(String.class, lambdaInfo.getReturnType());
|
||||
}, () -> {
|
||||
// 引用特定对象的实例方法
|
||||
Func0<String> instantiated = new MyTeacher()::getAge;
|
||||
LambdaInfo lambdaInfo = LambdaUtil.resolve(instantiated);
|
||||
Func0<String> lambda = new MyTeacher()::getAge;
|
||||
LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda);
|
||||
Assert.assertEquals(0, lambdaInfo.getParameterTypes().length);
|
||||
Assert.assertEquals(String.class, lambdaInfo.getReturnType());
|
||||
}, () -> {
|
||||
// 引用特定类型的任意对象的实例方法
|
||||
Func1<MyTeacher, String> annoInstantiated = MyTeacher::getAge;
|
||||
LambdaInfo lambdaInfo = LambdaUtil.resolve(annoInstantiated);
|
||||
Func1<MyTeacher, String> lambda = MyTeacher::getAge;
|
||||
LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda);
|
||||
Assert.assertEquals(0, lambdaInfo.getParameterTypes().length);
|
||||
Assert.assertEquals(String.class, lambdaInfo.getReturnType());
|
||||
}, () -> {
|
||||
// 最最重要的!!!
|
||||
Character character = '0';
|
||||
Integer integer = 0;
|
||||
SerThiCons<Object, Boolean, String> lambda = (obj, bool, str) -> {
|
||||
Objects.nonNull(character);
|
||||
Objects.nonNull(integer);
|
||||
};
|
||||
LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda);
|
||||
// 获取闭包使用的参数类型
|
||||
Assert.assertEquals(Character.class, lambdaInfo.getParameterTypes()[0]);
|
||||
Assert.assertEquals(Integer.class, lambdaInfo.getParameterTypes()[1]);
|
||||
// 最后几个是原有lambda的参数类型
|
||||
Assert.assertEquals(Object.class, lambdaInfo.getParameterTypes()[2]);
|
||||
Assert.assertEquals(Boolean.class, lambdaInfo.getParameterTypes()[3]);
|
||||
Assert.assertEquals(String.class, lambdaInfo.getParameterTypes()[4]);
|
||||
|
||||
Assert.assertEquals(void.class, lambdaInfo.getReturnType());
|
||||
}).forEach(Runnable::run);
|
||||
|
||||
}
|
||||
|
||||
interface SerThiCons<P1, P2, P3> extends Consumer3<P1, P2, P3>, Serializable {
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Loading…
x
Reference in New Issue
Block a user