This commit is contained in:
Looly 2023-05-05 12:03:34 +08:00
parent 6b86ca2e5d
commit cbd74d4df9
7 changed files with 110 additions and 138 deletions

View File

@ -18,9 +18,9 @@ import org.dromara.hutool.core.exception.HutoolException;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.lang.Opt;
import org.dromara.hutool.core.map.WeakConcurrentMap;
import org.dromara.hutool.core.reflect.ClassDescUtil;
import org.dromara.hutool.core.reflect.MethodUtil;
import org.dromara.hutool.core.reflect.ModifierUtil;
import org.dromara.hutool.core.reflect.ReflectUtil;
import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
@ -98,7 +98,7 @@ public class LambdaUtil {
final Class<?> implClass = ClassLoaderUtil.loadClass(serializedLambda.getImplClass(), true);
if ("<init>".equals(methodName)) {
for (final Constructor<?> constructor : implClass.getDeclaredConstructors()) {
if (ReflectUtil.getDescriptor(constructor).equals(serializedLambda.getImplMethodSignature())) {
if (ClassDescUtil.getDesc(constructor, false).equals(serializedLambda.getImplMethodSignature())) {
return new LambdaInfo(constructor, serializedLambda);
}
}
@ -106,7 +106,7 @@ public class LambdaUtil {
final Method[] methods = MethodUtil.getMethods(implClass);
for (final Method method : methods) {
if (method.getName().equals(methodName)
&& ReflectUtil.getDescriptor(method).equals(serializedLambda.getImplMethodSignature())) {
&& ClassDescUtil.getDesc(method, false).equals(serializedLambda.getImplMethodSignature())) {
return new LambdaInfo(method, serializedLambda);
}
}

View File

@ -167,14 +167,21 @@ public class ClassDescUtil {
}
/**
* 获取类描述
* 获取类描述这是编译成class文件后的二进制名称
* <pre>{@code
* boolean[].class => "[Z"
* Object.class => "Ljava/lang/Object;"
* getDesc(boolean.class) // Z
* getDesc(Boolean.class) // Ljava/lang/Boolean;
* getDesc(double[][][].class) // [[[D
* getDesc(int.class) // I
* getDesc(Integer.class) // Ljava/lang/Integer;
* }</pre>
*
* @param c class.
* @return desc.
*
* @author VampireAchao
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html">jvm定义的Field Descriptors字段描述</a>
* @see <a href="https://vampireAchao.gitee.io/2022/06/07/%E7%B1%BB%E5%9E%8B%E6%8F%8F%E8%BF%B0%E7%AC%A6/">关于类型描述符的博客</a>
*/
public static String getDesc(Class<?> c) {
final StringBuilder ret = new StringBuilder();
@ -199,22 +206,35 @@ public class ClassDescUtil {
/**
* 获取方法或构造描述<br>
* 方法
* 方法appendName为{@code true}
* <pre>{@code
* int do(int arg1) => "do(I)I"
* void do(String arg1,boolean arg2) => "do(Ljava/lang/String;Z)V"
* int do(int arg1) => "do(I)I"
* void do(String arg1,boolean arg2) => "do(Ljava/lang/String;Z)V"
* }</pre>
* 构造
* <pre>
* "()V", "(Ljava/lang/String;I)V"
* </pre>
* <pre>{@code
* "()V", "(Ljava/lang/String;I)V"
* }</pre>
*
* <p>当appendName为{@code false}</p>
* <pre>{@code
* getDesc(Object.class.getMethod("hashCode")) // ()I
* getDesc(Object.class.getMethod("toString")) // ()Ljava/lang/String;
* getDesc(Object.class.getMethod("equals", Object.class)) // (Ljava/lang/Object;)Z
* getDesc(ArrayUtil.class.getMethod("isEmpty", Object[].class)) // "([Ljava/lang/Object;)Z"
* }</pre>
*
* @param methodOrConstructor 方法或构造
* @param appendName 是否包含方法名称
* @return 描述
*
* @author VampireAchao
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html">jvm定义的Field Descriptors字段描述</a>
* @see <a href="https://vampireAchao.gitee.io/2022/06/07/%E7%B1%BB%E5%9E%8B%E6%8F%8F%E8%BF%B0%E7%AC%A6/">关于类型描述符的博客</a>
*/
public static String getDesc(final Executable methodOrConstructor) {
public static String getDesc(final Executable methodOrConstructor, final boolean appendName) {
final StringBuilder ret = new StringBuilder();
if (methodOrConstructor instanceof Method) {
if (appendName && methodOrConstructor instanceof Method) {
ret.append(methodOrConstructor.getName());
}
ret.append('(');

View File

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

View File

@ -113,7 +113,7 @@ public class KClassUtil {
final Object[] parameterValues = getParameterValues(constructor, valueProvider);
try {
return (T) KCallable.call(constructor, parameterValues);
} catch (RuntimeException e) {
} catch (final RuntimeException e) {
exception = e;
}
}

View File

@ -12,38 +12,74 @@
package org.dromara.hutool.core.spi;
import org.dromara.hutool.core.exception.ExceptionUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.exception.HutoolException;
/**
* SPI异常
*
* @author looly
*/
public class SPIException extends RuntimeException {
public class SPIException extends HutoolException {
private static final long serialVersionUID = 1L;
public SPIException(final Throwable cause) {
super(ExceptionUtil.getMessage(cause), cause);
/**
* 构造
*
* @param e 异常
*/
public SPIException(final Throwable e) {
super(e);
}
/**
* 构造
*
* @param message 消息
*/
public SPIException(final String message) {
super(message);
}
/**
* 构造
*
* @param messageTemplate 消息模板
* @param params 参数
*/
public SPIException(final String messageTemplate, final Object... params) {
super(StrUtil.format(messageTemplate, params));
super(messageTemplate, params);
}
/**
* 构造
*
* @param message 消息
* @param cause 被包装的子异常
*/
public SPIException(final String message, final Throwable cause) {
super(message, cause);
}
/**
* 构造
*
* @param message 消息
* @param cause 被包装的子异常
* @param enableSuppression 是否启用抑制
* @param writableStackTrace 堆栈跟踪是否应该是可写的
*/
public SPIException(final String message, final Throwable cause, final boolean enableSuppression, final boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
/**
* 构造
*
* @param cause 被包装的子异常
* @param messageTemplate 消息模板
* @param params 参数
*/
public SPIException(final Throwable cause, final String messageTemplate, final Object... params) {
super(StrUtil.format(messageTemplate, params), cause);
super(cause, messageTemplate, params);
}
}

View File

@ -12,8 +12,12 @@
package org.dromara.hutool.core.reflect;
import lombok.SneakyThrows;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
@ -78,4 +82,32 @@ public class ClassDescTest {
assertEquals("[[Ljava/lang/Object;",
ClassDescUtil.nameToDesc(ClassDescUtil.getName(Object[][].class)));
}
@Test
@SneakyThrows
public void testGetDescriptor() {
// methods
Assertions.assertEquals("()I", ClassDescUtil.getDesc(
Object.class.getMethod("hashCode"), false));
Assertions.assertEquals("()Ljava/lang/String;", ClassDescUtil.getDesc(
Object.class.getMethod("toString"), false));
Assertions.assertEquals("(Ljava/lang/Object;)Z", ClassDescUtil.getDesc(
Object.class.getMethod("equals", Object.class), false));
Assertions.assertEquals("(II)I", ClassDescUtil.getDesc(
Integer.class.getDeclaredMethod("compare", int.class, int.class), false));
Assertions.assertEquals("([Ljava/lang/Object;)Ljava/util/List;", ClassDescUtil.getDesc(
Arrays.class.getMethod("asList", Object[].class), false));
Assertions.assertEquals("()V", ClassDescUtil.getDesc(
Object.class.getConstructor(), false));
// clazz
Assertions.assertEquals("Z", ClassDescUtil.getDesc(boolean.class));
Assertions.assertEquals("Ljava/lang/Boolean;", ClassDescUtil.getDesc(Boolean.class));
Assertions.assertEquals("[[[D", ClassDescUtil.getDesc(double[][][].class));
Assertions.assertEquals("I", ClassDescUtil.getDesc(int.class));
Assertions.assertEquals("Ljava/lang/Integer;", ClassDescUtil.getDesc(Integer.class));
Assertions.assertEquals("V", ClassDescUtil.getDesc(void.class));
Assertions.assertEquals("Ljava/lang/Void;", ClassDescUtil.getDesc(Void.class));
Assertions.assertEquals("Ljava/lang/Object;", ClassDescUtil.getDesc(Object.class));
}
}

View File

@ -111,25 +111,4 @@ public class ReflectUtilTest {
}
}
@Test
@SneakyThrows
public void testGetDescriptor() {
// methods
Assertions.assertEquals("()I", ReflectUtil.getDescriptor(Object.class.getMethod("hashCode")));
Assertions.assertEquals("()Ljava/lang/String;", ReflectUtil.getDescriptor(Object.class.getMethod("toString")));
Assertions.assertEquals("(Ljava/lang/Object;)Z", ReflectUtil.getDescriptor(Object.class.getMethod("equals", Object.class)));
Assertions.assertEquals("(II)I", ReflectUtil.getDescriptor(Integer.class.getDeclaredMethod("compare", int.class, int.class)));
Assertions.assertEquals("([Ljava/lang/Object;)Ljava/util/List;", ReflectUtil.getDescriptor(Arrays.class.getMethod("asList", Object[].class)));
Assertions.assertEquals("()V", ReflectUtil.getDescriptor(Object.class.getConstructor()));
// clazz
Assertions.assertEquals("Z", ReflectUtil.getDescriptor(boolean.class));
Assertions.assertEquals("Ljava/lang/Boolean;", ReflectUtil.getDescriptor(Boolean.class));
Assertions.assertEquals("[[[D", ReflectUtil.getDescriptor(double[][][].class));
Assertions.assertEquals("I", ReflectUtil.getDescriptor(int.class));
Assertions.assertEquals("Ljava/lang/Integer;", ReflectUtil.getDescriptor(Integer.class));
Assertions.assertEquals("V", ReflectUtil.getDescriptor(void.class));
Assertions.assertEquals("Ljava/lang/Void;", ReflectUtil.getDescriptor(Void.class));
Assertions.assertEquals("Ljava/lang/Object;", ReflectUtil.getDescriptor(Object.class));
}
}