mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
修复LambdaUtil对多参数且参数为包含数组的lambda的支持;优化clazz获取逻辑,直接从executable获取而不是反射
This commit is contained in:
parent
f536f4f47a
commit
6bccf59079
@ -1,7 +1,7 @@
|
||||
package cn.hutool.core.lang.func;
|
||||
|
||||
import cn.hutool.core.classloader.ClassLoaderUtil;
|
||||
import cn.hutool.core.reflect.FieldUtil;
|
||||
import cn.hutool.core.text.StrPool;
|
||||
|
||||
import java.lang.invoke.SerializedLambda;
|
||||
import java.lang.reflect.Constructor;
|
||||
@ -30,34 +30,42 @@ public class LambdaInfo {
|
||||
this.parameterTypes = method.getGenericParameterTypes();
|
||||
this.returnType = method.getGenericReturnType();
|
||||
this.name = method.getName();
|
||||
this.clazz = method.getDeclaringClass();
|
||||
} else if (executable instanceof Constructor) {
|
||||
final Constructor<?> constructor = (Constructor<?>) executable;
|
||||
this.parameterTypes = constructor.getGenericParameterTypes();
|
||||
this.returnType = constructor.getDeclaringClass();
|
||||
this.name = constructor.getName();
|
||||
this.clazz = constructor.getDeclaringClass();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported executable type: " + executable.getClass());
|
||||
}
|
||||
final int index = lambda.getInstantiatedMethodType().indexOf(";)");
|
||||
if (index > -1) {
|
||||
final boolean isArray = lambda.getInstantiatedMethodType().startsWith("([");
|
||||
if (isArray) {
|
||||
try {
|
||||
this.instantiatedTypes = new Type[]{Class.forName(lambda.getInstantiatedMethodType().replace("/", ".").substring(0, index).substring(1) + ";")};
|
||||
} catch (final ClassNotFoundException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
} else {
|
||||
final String[] instantiatedTypeNames = lambda.getInstantiatedMethodType().substring(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]);
|
||||
final String className = lambda.getInstantiatedMethodType().substring(1, index + 1);
|
||||
final String[] instantiatedTypeNames = className.split(";");
|
||||
final Type[] types = new Type[instantiatedTypeNames.length];
|
||||
for (int i = 0; i < instantiatedTypeNames.length; i++) {
|
||||
final boolean isArray = instantiatedTypeNames[i].startsWith(StrPool.BRACKET_START);
|
||||
if (isArray && !instantiatedTypeNames[i].endsWith(";")) {
|
||||
// 如果是数组,需要以 ";" 结尾才能加载
|
||||
instantiatedTypeNames[i] += ";";
|
||||
} else {
|
||||
if (instantiatedTypeNames[i].startsWith("L")) {
|
||||
// 如果以 "L" 开头,删除 L
|
||||
instantiatedTypeNames[i] = instantiatedTypeNames[i].substring(1);
|
||||
}
|
||||
if (instantiatedTypeNames[i].endsWith(";")) {
|
||||
// 如果以 ";" 结尾,删除 ";"
|
||||
instantiatedTypeNames[i] = instantiatedTypeNames[i].substring(0, instantiatedTypeNames[i].length() - 1);
|
||||
}
|
||||
}
|
||||
types[i] = ClassLoaderUtil.loadClass(instantiatedTypeNames[i]);
|
||||
}
|
||||
this.instantiatedTypes = types;
|
||||
} else {
|
||||
this.instantiatedTypes = new Type[0];
|
||||
}
|
||||
this.clazz = (Class<?>) FieldUtil.getFieldValue(executable, "clazz");
|
||||
this.executable = executable;
|
||||
this.lambda = lambda;
|
||||
}
|
||||
|
@ -7,11 +7,9 @@ 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")
|
||||
public class LambdaUtilTest {
|
||||
|
||||
@Test
|
||||
@ -29,7 +27,7 @@ public class LambdaUtilTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveTest() {
|
||||
public <T> void resolveTest() {
|
||||
Stream.<Runnable>of(() -> {
|
||||
// 引用构造函数
|
||||
final Func0<MyTeacher> lambda = MyTeacher::new;
|
||||
@ -41,7 +39,7 @@ public class LambdaUtilTest {
|
||||
final Func1<Integer, MyTeacher[]> lambda = MyTeacher[]::new;
|
||||
final LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda);
|
||||
Assert.assertEquals(int.class, lambdaInfo.getParameterTypes()[0]);
|
||||
Assert.assertEquals(MyTeacher.class, ((Class<Array>) lambdaInfo.getReturnType()).getComponentType());
|
||||
Assert.assertEquals(MyTeacher[].class, lambdaInfo.getReturnType());
|
||||
}, () -> {
|
||||
// 引用静态方法
|
||||
final Func0<String> lambda = MyTeacher::takeAge;
|
||||
@ -80,6 +78,12 @@ public class LambdaUtilTest {
|
||||
Assert.assertEquals(String.class, lambdaInfo.getParameterTypes()[4]);
|
||||
|
||||
Assert.assertEquals(void.class, lambdaInfo.getReturnType());
|
||||
}, () -> {
|
||||
// 一些特殊的lambda
|
||||
Assert.assertEquals("T[]", LambdaUtil.<Func<Object, Stream<?>>>resolve(Stream::of).getParameterTypes()[0].getTypeName());
|
||||
Assert.assertEquals(MyTeacher[][].class, LambdaUtil.<Func1<Integer, MyTeacher[][]>>resolve(MyTeacher[][]::new).getReturnType());
|
||||
Assert.assertEquals(Integer[][][].class, LambdaUtil.<VoidFunc1<Integer[][][]>>resolve(a -> {}).getParameterTypes()[0]);
|
||||
Assert.assertEquals(Integer[][][].class, LambdaUtil.resolve((Serializable & Consumer3<Integer[][][], Integer[][], Integer>) (a, b, c) -> {}).getParameterTypes()[0]);
|
||||
}).forEach(Runnable::run);
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user