!644 新增ReflectUtil.getDescriptor获取单个class的描述符重载,完善测试用例和注释信息

Merge pull request !644 from 阿超/v6-dev
This commit is contained in:
Looly 2022-06-08 00:46:18 +00:00 committed by Gitee
commit a7dcd4ce98
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
2 changed files with 65 additions and 56 deletions

View File

@ -33,7 +33,8 @@ public class ReflectUtil {
* *
* @param executable 可执行的反射对象 * @param executable 可执行的反射对象
* @return 描述符 * @return 描述符
* 参考<a href="https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html">jvm定义的Field Descriptors字段描述</a> * @link <a href="https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html">jvm定义的Field Descriptors字段描述</a>
* @link <a href="https://public static class.gitee.io/2022/06/07/%E7%B1%BB%E5%9E%8B%E6%8F%8F%E8%BF%B0%E7%AC%A6/">关于类型描述符的博客</a>
* <p></p> * <p></p>
* <ul> * <ul>
* <li>{@code ReflectUtil.getDescriptor(Object.class.getMethod("hashCode")) // "()I"}</li> * <li>{@code ReflectUtil.getDescriptor(Object.class.getMethod("hashCode")) // "()I"}</li>
@ -42,21 +43,18 @@ public class ReflectUtil {
* <li>{@code ReflectUtil.getDescriptor(ReflectUtil.class.getDeclaredMethod("appendDescriptor", Class.clas, StringBuilder.class)) // "(Ljava/lang/Class;Ljava/lang/StringBuilder;)V"}</li> * <li>{@code ReflectUtil.getDescriptor(ReflectUtil.class.getDeclaredMethod("appendDescriptor", Class.clas, StringBuilder.class)) // "(Ljava/lang/Class;Ljava/lang/StringBuilder;)V"}</li>
* <li>{@code ReflectUtil.getDescriptor(ArrayUtil.class.getMethod("isEmpty", Object[].class)) // "([Ljava/lang/Object;)Z"}</li> * <li>{@code ReflectUtil.getDescriptor(ArrayUtil.class.getMethod("isEmpty", Object[].class)) // "([Ljava/lang/Object;)Z"}</li>
* </ul> * </ul>
* * @author VampireAchao
* Object.class.getMethod("hashCode")
*/ */
public static String getDescriptor(Executable executable) { public static String getDescriptor(Executable executable) {
StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append('('); stringBuilder.append('(');
Class<?>[] parameters = executable.getParameterTypes(); Class<?>[] parameters = executable.getParameterTypes();
for (Class<?> parameter : parameters) { for (Class<?> parameter : parameters) {
appendDescriptor(parameter, stringBuilder); stringBuilder.append(getDescriptor(parameter));
} }
if (executable instanceof Method) { if (executable instanceof Method) {
Method method = (Method) executable; Method method = (Method) executable;
stringBuilder.append(')'); return stringBuilder.append(')').append(getDescriptor(method.getReturnType())).toString();
appendDescriptor(method.getReturnType(), stringBuilder);
return stringBuilder.toString();
} else if (executable instanceof Constructor) { } else if (executable instanceof Constructor) {
return stringBuilder.append(")V").toString(); return stringBuilder.append(")V").toString();
} }
@ -64,65 +62,63 @@ public class ReflectUtil {
} }
/** /**
* 拼接描述符 * 获取类型描述符这是编译成class文件后的二进制名称
* *
* @param clazz * @param clazz
* @param stringBuilder 描述符
* @link <a href="https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html">jvm定义的Field Descriptors字段描述</a> * @link <a href="https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html">jvm定义的Field Descriptors字段描述</a>
* @link <a href="https://public static class.gitee.io/2022/06/07/%E7%B1%BB%E5%9E%8B%E6%8F%8F%E8%BF%B0%E7%AC%A6/">关于类型描述符的博客</a>
* <p></p>
* <ul>
* <li>{@code ReflectUtil.getDescriptor(boolean.class) "Z"}</li>
* <li>{@code ReflectUtil.getDescriptor(Boolean.class) "Ljava/lang/Boolean;"}</li>
* <li>{@code ReflectUtil.getDescriptor(double[][][].class) "[[[D"}</li>
* <li>{@code ReflectUtil.getDescriptor(int.class) "I"}</li>
* <li>{@code ReflectUtil.getDescriptor(Integer.class) "Ljava/lang/Integer;"}</li>
* </ul>
* @author VampireAchao
*/ */
private static void appendDescriptor(Class<?> clazz, StringBuilder stringBuilder) { public static String getDescriptor(Class<?> clazz) {
StringBuilder stringBuilder = new StringBuilder();
Class<?> currentClass; Class<?> currentClass;
for (currentClass = clazz; for (currentClass = clazz;
currentClass.isArray(); currentClass.isArray();
currentClass = currentClass.getComponentType()) { currentClass = currentClass.getComponentType()) {
// 如果当前是数组描述符
stringBuilder.append('['); stringBuilder.append('[');
} }
if (currentClass.isPrimitive()) { if (currentClass.isPrimitive()) {
stringBuilder.append(getDescriptorChar(currentClass)); // 只有下面九种基础数据类型以及数组才有独立的描述符
} else { final char descriptor;
stringBuilder.append('L').append(currentClass.getName().replace('.', '/')).append(';'); // see sun.invoke.util.Wrapper
} // These must be in the order defined for widening primitive conversions in JLS 5.1.2
}
/**
* 获取单个描述符
*
* @param currentClass 当前类
* @return 描述符
*/
private static char getDescriptorChar(Class<?> currentClass) {
if (currentClass == boolean.class) { if (currentClass == boolean.class) {
return 'Z'; descriptor = 'Z';
} } else if (currentClass == byte.class) {
if ( currentClass == byte.class) { descriptor = 'B';
return 'B'; } else if (currentClass == short.class) {
} descriptor = 'S';
if (currentClass == short.class) { } else if (currentClass == char.class) {
return 'S'; descriptor = 'C';
} } else if (currentClass == int.class) {
if (currentClass == char.class) { descriptor = 'I';
return 'C'; } else if (currentClass == long.class) {
} descriptor = 'J';
if (currentClass == int.class) { } else if (currentClass == float.class) {
return 'I'; descriptor = 'F';
} } else if (currentClass == double.class) {
if (currentClass == long.class) { descriptor = 'D';
return 'J'; } else if (currentClass == void.class) {
} // VOID must be the last type, since it is "assignable" from any other type:
if (currentClass == float.class) { descriptor = 'V';
return 'F'; } else {
}
if (currentClass == double.class) {
return 'D';
}
if (currentClass == Object.class) {
return 'L';
}
if (currentClass == void.class) {
return 'V';
}
throw new AssertionError(); throw new AssertionError();
} }
stringBuilder.append(descriptor);
} else {
// 否则一律是 "L"+类名.replace('.', '/')+";"格式的对象类型
stringBuilder.append('L').append(currentClass.getName().replace('.', '/')).append(';');
}
return stringBuilder.toString();
}
} }

View File

@ -1,11 +1,13 @@
package cn.hutool.core.reflect; package cn.hutool.core.reflect;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil;
import lombok.Data; import lombok.Data;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import org.junit.Test; import org.junit.Test;
import java.util.Arrays;
import java.util.Collection;
/** /**
* 反射工具类单元测试 * 反射工具类单元测试
* *
@ -113,10 +115,21 @@ public class ReflectUtilTest {
@Test @Test
@SneakyThrows @SneakyThrows
public void testGetDescriptor() { public void testGetDescriptor() {
// methods
Assert.equals("()I", ReflectUtil.getDescriptor(Object.class.getMethod("hashCode"))); Assert.equals("()I", ReflectUtil.getDescriptor(Object.class.getMethod("hashCode")));
Assert.equals("()Ljava/lang/String;", ReflectUtil.getDescriptor(Object.class.getMethod("toString"))); Assert.equals("()Ljava/lang/String;", ReflectUtil.getDescriptor(Object.class.getMethod("toString")));
Assert.equals("(Ljava/lang/Object;)Z", ReflectUtil.getDescriptor(Object.class.getMethod("equals", Object.class))); Assert.equals("(Ljava/lang/Object;)Z", ReflectUtil.getDescriptor(Object.class.getMethod("equals", Object.class)));
Assert.equals("(Ljava/lang/Class;Ljava/lang/StringBuilder;)V", ReflectUtil.getDescriptor(ReflectUtil.class.getDeclaredMethod("appendDescriptor", Class.class, StringBuilder.class))); Assert.equals("(II)I", ReflectUtil.getDescriptor(Integer.class.getDeclaredMethod("compare", int.class, int.class)));
Assert.equals("([Ljava/lang/Object;)Z", ReflectUtil.getDescriptor(ArrayUtil.class.getMethod("isEmpty", Object[].class))); Assert.equals("([Ljava/lang/Object;)Ljava/util/List;", ReflectUtil.getDescriptor(Arrays.class.getMethod("asList", Object[].class)));
Assert.equals("()V", ReflectUtil.getDescriptor(Object.class.getConstructor()));
// clazz
Assert.equals("Z", ReflectUtil.getDescriptor(boolean.class));
Assert.equals("Ljava/lang/Boolean;", ReflectUtil.getDescriptor(Boolean.class));
Assert.equals("[[[D", ReflectUtil.getDescriptor(double[][][].class));
Assert.equals("I", ReflectUtil.getDescriptor(int.class));
Assert.equals("Ljava/lang/Integer;", ReflectUtil.getDescriptor(Integer.class));
Assert.equals("V", ReflectUtil.getDescriptor(void.class));
Assert.equals("Ljava/lang/Void;", ReflectUtil.getDescriptor(Void.class));
Assert.equals("Ljava/lang/Object;", ReflectUtil.getDescriptor(Object.class));
} }
} }