This commit is contained in:
Looly 2023-04-15 15:52:38 +08:00
parent 2c3eac6046
commit a280ff0918
3 changed files with 126 additions and 36 deletions

View File

@ -136,22 +136,21 @@ public class ClassDescUtil {
* @throws UtilException 类没有找到
*/
public static Class<?> descToClass(String desc, final boolean isInitialized, final ClassLoader cl) throws UtilException {
Assert.notNull(desc, "Name must not be null");
final char firstChar = desc.charAt(0);
final Class<?> clazz = PRIMITIVE_CLASS_DESC_MAP.getKey(firstChar);
if (null != clazz) {
return clazz;
}
switch (firstChar) {
case 'L':
// "Ljava/lang/Object;" ==> "java.lang.Object"
desc = desc.substring(1, desc.length() - 1).replace('/', '.');
break;
case '[':
// "[[Ljava/lang/Object;" ==> "[[Ljava.lang.Object;"
desc = desc.replace(CharUtil.SLASH, CharUtil.DOT);
break;
default:
throw new UtilException("Class not found for : " + desc);
// 去除尾部多余的".""/"
desc = StrUtil.trim(desc, StrTrimer.TrimMode.SUFFIX, (c) ->
CharUtil.SLASH == c || CharUtil.DOT == c);
if ('L' == firstChar) {
// 正常类的描述中需要去掉L;包装的修饰
// "Ljava/lang/Object;" ==> "java.lang.Object"
desc = desc.substring(1, desc.length() - 1);
}
return ClassUtil.forName(desc, isInitialized, cl);
@ -226,28 +225,62 @@ public class ClassDescUtil {
}
/**
* 获取code base
* 获得类名称<br>
* 数组输出xxx[]形式其它类调用{@link Class#getName()}
*
* @param clazz
* @return code base
* <pre>{@code
* java.lang.Object[][].class => "java.lang.Object[][]"
* }</pre>
*
* @param c
* @return 类名称
*/
public static String getCodeBase(final Class<?> clazz) {
if (clazz == null) {
return null;
public static String getName(Class<?> c) {
if (c.isArray()) {
final StringBuilder sb = new StringBuilder();
do {
sb.append("[]");
c = c.getComponentType();
}
while (c.isArray());
return c.getName() + sb;
}
final ProtectionDomain domain = clazz.getProtectionDomain();
if (domain == null) {
return null;
return c.getName();
}
/**
* 获取构造或方法的名称表示<br>
* 构造
* <pre>
* "()", "(java.lang.String,int)"
* </pre>
*
* 方法
* <pre>
* "void do(int)", "void do()", "int do(java.lang.String,boolean)"
* </pre>
*
* @param executable 方法或构造
* @return 名称
*/
public static String getName(final Executable executable) {
final StringBuilder ret = new StringBuilder("(");
if(executable instanceof Method){
ret.append(getName(((Method) executable).getReturnType())).append(CharUtil.SPACE);
}
final CodeSource source = domain.getCodeSource();
if (source == null) {
return null;
// 参数
final Class<?>[] parameterTypes = executable.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
if (i > 0) {
ret.append(',');
}
ret.append(getName(parameterTypes[i]));
}
final URL location = source.getLocation();
if (location == null) {
return null;
}
return location.getFile();
ret.append(')');
return ret.toString();
}
/**
@ -269,6 +302,7 @@ public class ClassDescUtil {
int c = 0;
final int index = name.indexOf('[');
if (index > 0) {
// c是[]对个数如String[][]则表示二维数组c的值是2获得desc结果就是[[LString;
c = (name.length() - index) / 2;
name = name.substring(0, index);
}
@ -284,7 +318,7 @@ public class ClassDescUtil {
// 原始类型数组根据name获取其描述
sb.append(PRIMITIVE_CLASS_DESC_MAP.get(clazz).charValue());
} else {
// 对象数组
// 对象数组必须转换为desc形式
// "java.lang.Object" ==> "Ljava.lang.Object;"
sb.append('L').append(name).append(';');
}
@ -296,7 +330,7 @@ public class ClassDescUtil {
}
}
return ClassUtil.forName(name.replace(CharUtil.SLASH, CharUtil.DOT), isInitialized, cl);
return ClassUtil.forName(name, isInitialized, cl);
}
/**
@ -326,7 +360,6 @@ public class ClassDescUtil {
// 原始类型数组根据name获取其描述
sb.append(PRIMITIVE_CLASS_DESC_MAP.get(clazz).charValue());
} else {
// 对象数组
// "java.lang.Object" ==> "Ljava.lang.Object;"
sb.append('L').append(name.replace(CharUtil.DOT, CharUtil.SLASH)).append(';');
}
@ -363,4 +396,29 @@ public class ClassDescUtil {
}
return sb.toString();
}
/**
* 获取code base
*
* @param clazz
* @return code base
*/
public static String getCodeBase(final Class<?> clazz) {
if (clazz == null) {
return null;
}
final ProtectionDomain domain = clazz.getProtectionDomain();
if (domain == null) {
return null;
}
final CodeSource source = domain.getCodeSource();
if (source == null) {
return null;
}
final URL location = source.getLocation();
if (location == null) {
return null;
}
return location.getFile();
}
}

View File

@ -736,7 +736,11 @@ public class ClassUtil {
}
/**
* 加载指定名称的类
* 加载指定名称的类支持
* <ul>
* <li>替换"/""."</li>
* <li>自动查找内部类如java.lang.Thread.State =java.lang.Thread$State</li>
* </ul>
*
* @param name 类名
* @param isInitialized 是否初始化
@ -744,10 +748,11 @@ public class ClassUtil {
* @return 指定名称对应的类如果不存在类返回{@code null
* @link Class#forName(String, boolean, ClassLoader)}
*/
public static Class<?> forName(final String name, final boolean isInitialized, ClassLoader loader) {
public static Class<?> forName(String name, final boolean isInitialized, ClassLoader loader) {
if(null == loader){
loader = ClassLoaderUtil.getClassLoader();
}
name = name.replace(CharUtil.SLASH, CharUtil.DOT);
// 加载普通类
try {

View File

@ -17,12 +17,12 @@ import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* 来自org.apache.dubbo.common.utils.ReflectUtilsTest
* 来自org.apache.dubbo.common.utils.ClassDescUtilTest
*/
public class ClassDescTest {
@Test
void testDesc2Class() {
void descToClassTest() {
assertEquals(void.class, ClassDescUtil.descToClass("V"));
assertEquals(boolean.class, ClassDescUtil.descToClass("Z"));
assertEquals(boolean[].class, ClassDescUtil.descToClass("[Z"));
@ -48,7 +48,34 @@ public class ClassDescTest {
@Test
void nameToClassTest() {
final Class<?> aClass = ClassDescUtil.nameToClass("java.lang.Object[]", true, null);
Class<?> aClass = ClassDescUtil.nameToClass("java.lang.Object[]", true, null);
assertEquals(Object[].class, aClass);
aClass = ClassDescUtil.nameToClass("java.lang.Object", true, null);
assertEquals(Object.class, aClass);
}
@Test
void descToNameTest() {
assertEquals("short[]", ClassDescUtil.descToName(ClassDescUtil.getDesc(short[].class)));
assertEquals("boolean[]", ClassDescUtil.descToName(ClassDescUtil.getDesc(boolean[].class)));
assertEquals("byte[]", ClassDescUtil.descToName(ClassDescUtil.getDesc(byte[].class)));
assertEquals("char[]", ClassDescUtil.descToName(ClassDescUtil.getDesc(char[].class)));
assertEquals("double[]", ClassDescUtil.descToName(ClassDescUtil.getDesc(double[].class)));
assertEquals("float[]", ClassDescUtil.descToName(ClassDescUtil.getDesc(float[].class)));
assertEquals("int[]", ClassDescUtil.descToName(ClassDescUtil.getDesc(int[].class)));
assertEquals("long[]", ClassDescUtil.descToName(ClassDescUtil.getDesc(long[].class)));
assertEquals("int", ClassDescUtil.descToName(ClassDescUtil.getDesc(int.class)));
assertEquals("void", ClassDescUtil.descToName(ClassDescUtil.getDesc(void.class)));
assertEquals("java.lang.Object[][]", ClassDescUtil.descToName(ClassDescUtil.getDesc(Object[][].class)));
}
@Test
void nameToDescTest() {
// name2desc
assertEquals("Z", ClassDescUtil.nameToDesc(ClassDescUtil.getName(boolean.class)));
assertEquals("[[[I", ClassDescUtil.nameToDesc(ClassDescUtil.getName(int[][][].class)));
assertEquals("[[Ljava/lang/Object;",
ClassDescUtil.nameToDesc(ClassDescUtil.getName(Object[][].class)));
}
}