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 类没有找到 * @throws UtilException 类没有找到
*/ */
public static Class<?> descToClass(String desc, final boolean isInitialized, final ClassLoader cl) 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 char firstChar = desc.charAt(0);
final Class<?> clazz = PRIMITIVE_CLASS_DESC_MAP.getKey(firstChar); final Class<?> clazz = PRIMITIVE_CLASS_DESC_MAP.getKey(firstChar);
if (null != clazz) { if (null != clazz) {
return clazz; return clazz;
} }
switch (firstChar) {
case 'L': // 去除尾部多余的".""/"
// "Ljava/lang/Object;" ==> "java.lang.Object" desc = StrUtil.trim(desc, StrTrimer.TrimMode.SUFFIX, (c) ->
desc = desc.substring(1, desc.length() - 1).replace('/', '.'); CharUtil.SLASH == c || CharUtil.DOT == c);
break;
case '[': if ('L' == firstChar) {
// "[[Ljava/lang/Object;" ==> "[[Ljava.lang.Object;" // 正常类的描述中需要去掉L;包装的修饰
desc = desc.replace(CharUtil.SLASH, CharUtil.DOT); // "Ljava/lang/Object;" ==> "java.lang.Object"
break; desc = desc.substring(1, desc.length() - 1);
default:
throw new UtilException("Class not found for : " + desc);
} }
return ClassUtil.forName(desc, isInitialized, cl); return ClassUtil.forName(desc, isInitialized, cl);
@ -226,28 +225,62 @@ public class ClassDescUtil {
} }
/** /**
* 获取code base * 获得类名称<br>
* 数组输出xxx[]形式其它类调用{@link Class#getName()}
* *
* @param clazz * <pre>{@code
* @return code base * java.lang.Object[][].class => "java.lang.Object[][]"
* }</pre>
*
* @param c
* @return 类名称
*/ */
public static String getCodeBase(final Class<?> clazz) { public static String getName(Class<?> c) {
if (clazz == null) { if (c.isArray()) {
return null; final StringBuilder sb = new StringBuilder();
do {
sb.append("[]");
c = c.getComponentType();
}
while (c.isArray());
return c.getName() + sb;
} }
final ProtectionDomain domain = clazz.getProtectionDomain(); return c.getName();
if (domain == null) { }
return null;
/**
* 获取构造或方法的名称表示<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) { ret.append(')');
return null; return ret.toString();
}
return location.getFile();
} }
/** /**
@ -269,6 +302,7 @@ public class ClassDescUtil {
int c = 0; int c = 0;
final int index = name.indexOf('['); final int index = name.indexOf('[');
if (index > 0) { if (index > 0) {
// c是[]对个数如String[][]则表示二维数组c的值是2获得desc结果就是[[LString;
c = (name.length() - index) / 2; c = (name.length() - index) / 2;
name = name.substring(0, index); name = name.substring(0, index);
} }
@ -284,7 +318,7 @@ public class ClassDescUtil {
// 原始类型数组根据name获取其描述 // 原始类型数组根据name获取其描述
sb.append(PRIMITIVE_CLASS_DESC_MAP.get(clazz).charValue()); sb.append(PRIMITIVE_CLASS_DESC_MAP.get(clazz).charValue());
} else { } else {
// 对象数组 // 对象数组必须转换为desc形式
// "java.lang.Object" ==> "Ljava.lang.Object;" // "java.lang.Object" ==> "Ljava.lang.Object;"
sb.append('L').append(name).append(';'); 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获取其描述 // 原始类型数组根据name获取其描述
sb.append(PRIMITIVE_CLASS_DESC_MAP.get(clazz).charValue()); sb.append(PRIMITIVE_CLASS_DESC_MAP.get(clazz).charValue());
} else { } else {
// 对象数组
// "java.lang.Object" ==> "Ljava.lang.Object;" // "java.lang.Object" ==> "Ljava.lang.Object;"
sb.append('L').append(name.replace(CharUtil.DOT, CharUtil.SLASH)).append(';'); sb.append('L').append(name.replace(CharUtil.DOT, CharUtil.SLASH)).append(';');
} }
@ -363,4 +396,29 @@ public class ClassDescUtil {
} }
return sb.toString(); 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 name 类名
* @param isInitialized 是否初始化 * @param isInitialized 是否初始化
@ -744,10 +748,11 @@ public class ClassUtil {
* @return 指定名称对应的类如果不存在类返回{@code null * @return 指定名称对应的类如果不存在类返回{@code null
* @link Class#forName(String, boolean, ClassLoader)} * @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){ if(null == loader){
loader = ClassLoaderUtil.getClassLoader(); loader = ClassLoaderUtil.getClassLoader();
} }
name = name.replace(CharUtil.SLASH, CharUtil.DOT);
// 加载普通类 // 加载普通类
try { try {

View File

@ -17,12 +17,12 @@ import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
/** /**
* 来自org.apache.dubbo.common.utils.ReflectUtilsTest * 来自org.apache.dubbo.common.utils.ClassDescUtilTest
*/ */
public class ClassDescTest { public class ClassDescTest {
@Test @Test
void testDesc2Class() { void descToClassTest() {
assertEquals(void.class, ClassDescUtil.descToClass("V")); assertEquals(void.class, ClassDescUtil.descToClass("V"));
assertEquals(boolean.class, ClassDescUtil.descToClass("Z")); assertEquals(boolean.class, ClassDescUtil.descToClass("Z"));
assertEquals(boolean[].class, ClassDescUtil.descToClass("[Z")); assertEquals(boolean[].class, ClassDescUtil.descToClass("[Z"));
@ -48,7 +48,34 @@ public class ClassDescTest {
@Test @Test
void nameToClassTest() { 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); 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)));
} }
} }