修复LambdaUtil对多参数且参数为包含数组的lambda的支持;优化clazz获取逻辑,直接从executable获取而不是反射

This commit is contained in:
achao 2022-08-18 15:54:49 +08:00 committed by VampireAchao
parent f536f4f47a
commit 6bccf59079
2 changed files with 30 additions and 18 deletions

View File

@ -1,7 +1,7 @@
package cn.hutool.core.lang.func; package cn.hutool.core.lang.func;
import cn.hutool.core.classloader.ClassLoaderUtil; 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.invoke.SerializedLambda;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
@ -30,34 +30,42 @@ public class LambdaInfo {
this.parameterTypes = method.getGenericParameterTypes(); this.parameterTypes = method.getGenericParameterTypes();
this.returnType = method.getGenericReturnType(); this.returnType = method.getGenericReturnType();
this.name = method.getName(); this.name = method.getName();
this.clazz = method.getDeclaringClass();
} else if (executable instanceof Constructor) { } else if (executable instanceof Constructor) {
final Constructor<?> constructor = (Constructor<?>) executable; final Constructor<?> constructor = (Constructor<?>) executable;
this.parameterTypes = constructor.getGenericParameterTypes(); this.parameterTypes = constructor.getGenericParameterTypes();
this.returnType = constructor.getDeclaringClass(); this.returnType = constructor.getDeclaringClass();
this.name = constructor.getName(); this.name = constructor.getName();
this.clazz = constructor.getDeclaringClass();
} else { } else {
throw new IllegalArgumentException("Unsupported executable type: " + executable.getClass()); throw new IllegalArgumentException("Unsupported executable type: " + executable.getClass());
} }
final int index = lambda.getInstantiatedMethodType().indexOf(";)"); final int index = lambda.getInstantiatedMethodType().indexOf(";)");
if (index > -1) { if (index > -1) {
final boolean isArray = lambda.getInstantiatedMethodType().startsWith("(["); final String className = lambda.getInstantiatedMethodType().substring(1, index + 1);
if (isArray) { final String[] instantiatedTypeNames = className.split(";");
try { final Type[] types = new Type[instantiatedTypeNames.length];
this.instantiatedTypes = new Type[]{Class.forName(lambda.getInstantiatedMethodType().replace("/", ".").substring(0, index).substring(1) + ";")}; for (int i = 0; i < instantiatedTypeNames.length; i++) {
} catch (final ClassNotFoundException e) { final boolean isArray = instantiatedTypeNames[i].startsWith(StrPool.BRACKET_START);
throw new IllegalStateException(e); if (isArray && !instantiatedTypeNames[i].endsWith(";")) {
} // 如果是数组需要以 ";" 结尾才能加载
} else { instantiatedTypeNames[i] += ";";
final String[] instantiatedTypeNames = lambda.getInstantiatedMethodType().substring(2, index).split(";L"); } else {
this.instantiatedTypes = new Type[instantiatedTypeNames.length]; if (instantiatedTypeNames[i].startsWith("L")) {
for (int i = 0; i < instantiatedTypeNames.length; i++) { // 如果以 "L" 开头删除 L
this.instantiatedTypes[i] = ClassLoaderUtil.loadClass(instantiatedTypeNames[i]); 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 { } else {
this.instantiatedTypes = new Type[0]; this.instantiatedTypes = new Type[0];
} }
this.clazz = (Class<?>) FieldUtil.getFieldValue(executable, "clazz");
this.executable = executable; this.executable = executable;
this.lambda = lambda; this.lambda = lambda;
} }

View File

@ -7,11 +7,9 @@ import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import java.io.Serializable; import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Stream; import java.util.stream.Stream;
@SuppressWarnings("unchecked")
public class LambdaUtilTest { public class LambdaUtilTest {
@Test @Test
@ -29,7 +27,7 @@ public class LambdaUtilTest {
} }
@Test @Test
public void resolveTest() { public <T> void resolveTest() {
Stream.<Runnable>of(() -> { Stream.<Runnable>of(() -> {
// 引用构造函数 // 引用构造函数
final Func0<MyTeacher> lambda = MyTeacher::new; final Func0<MyTeacher> lambda = MyTeacher::new;
@ -41,7 +39,7 @@ public class LambdaUtilTest {
final Func1<Integer, MyTeacher[]> lambda = MyTeacher[]::new; final Func1<Integer, MyTeacher[]> lambda = MyTeacher[]::new;
final LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda); final LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda);
Assert.assertEquals(int.class, lambdaInfo.getParameterTypes()[0]); 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; final Func0<String> lambda = MyTeacher::takeAge;
@ -80,6 +78,12 @@ public class LambdaUtilTest {
Assert.assertEquals(String.class, lambdaInfo.getParameterTypes()[4]); Assert.assertEquals(String.class, lambdaInfo.getParameterTypes()[4]);
Assert.assertEquals(void.class, lambdaInfo.getReturnType()); 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); }).forEach(Runnable::run);
} }