如何将java.lang.reflect.Type
的实例转换为jvm泛型类型签名?
Type type = method.getGenericReturnType();
String signature = toTypeSig(type);
例如,这个类型:
Map<String, Map<?, ? super Integer>>
必须成为此字符串:
"Ljava/util/Map<Ljava/lang/String;Ljava/util/Map<*-Ljava/lang/Integer;>;>;"
使用orb.objectweb.asm.ClassWriter
的人如何解决此问题?
我已经完成了对类型信息的迭代。 但我更喜欢更强大的东西。 (我已经发布了自己的解决方案作为答案,因为它有点长)
答案 0 :(得分:2)
我想你想从类文件中获取jvm签名(或者你的意思是来自源文件?)
从下面的课程可能是一个解决方案
public class GetSignature {
// the method for which you want to retrieve the signature
Map<String, Map<?, ? super Integer>> someMethod() {
return null;
}
public static void main(String[] args) throws Exception {
// make the private method in class Method accessible
Method methodGenericSignature = Method.class.getDeclaredMethod(
"getGenericSignature",
(Class<?>[]) null
);
methodGenericSignature.setAccessible(true);
// get the signature from the method
Method method = GetSignature.class.getDeclaredMethod("someMethod",
(Class<?>[]) null
);
String returnValue = (String) methodGenericSignature.invoke(method,
(Object[]) null
);
System.out.println("signature: " + returnValue);
}
}
输出
signature: ()Ljava/util/Map<Ljava/lang/String;Ljava/util/Map<*-Ljava/lang/Integer;>;>;
编辑小剪片以演示如何使用library获取签名。
public class GetSignatureDemo {
public static void main(String[] args) throws IOException {
InputStream is = new FileInputStream("/tmp/GetSignature.class");
ClassReader classReader = new ClassReader(is);
classReader.accept(getClassVisitor(), 0);
}
private static ClassVisitor getClassVisitor() {
return new ClassVisitor(Opcodes.ASM4) {
@Override
public MethodVisitor visitMethod(int access, String name,
String descriptor, String signature, String[] exceptions) {
System.out.printf(
"method: %s descriptor: %s signature: %s%n",
name,
descriptor,
signature
);
return super.visitMethod(access, name, descriptor, signature, exceptions);
}
};
}
}
示例输出
method: someMethod descriptor: ()Ljava/util/Map; signature: ()Ljava/util/Map<Ljava/lang/String;Ljava/util/Map<*-Ljava/lang/Integer;>;>;
答案 1 :(得分:1)
我的最终解决方案。我发帖以供参考。因为method.setAccessible(true)
不可用时可能会有用。
这或多或少是我最终使用的。 因为我需要将泛型返回类型转换为类签名。我没有使用类型变量。
适用于没有类型参数的方法。 对于具有泛型类型参数的方法,它会尝试替换参数。
处理此方法的通用返回类型:<P> List<P> someMethod()
结果为"Ljava/util/List<Ljava/lang/Object;>;"
static String toGenericSignature(final Type type)
{
StringBuilder sb = new StringBuilder();
toGenericSignature(sb, type);
return sb.toString();
}
static void toGenericSignature(StringBuilder sb, final Type type)
{
if (type instanceof GenericArrayType)
{
sb.append("[");
toGenericSignature(sb, ((GenericArrayType) type).getGenericComponentType());
}
else if (type instanceof ParameterizedType)
{
ParameterizedType pt = (ParameterizedType) type;
sb.append('L');
sb.append(((Class) pt.getRawType()).getName().replace('.', '/'));
sb.append('<');
for (Type p : pt.getActualTypeArguments())
{
toGenericSignature(sb, p);
}
sb.append(">;");
}
else if (type instanceof Class)
{
Class clazz = (Class) type;
if (!clazz.isPrimitive() && !clazz.isArray())
{
sb.append('L');
sb.append(clazz.getName().replace('.', '/'));
sb.append(';');
}
else
{
sb.append(clazz.getName().replace('.', '/'));
}
}
else if (type instanceof WildcardType)
{
WildcardType wc = (WildcardType) type;
Type[] lowerBounds = wc.getLowerBounds();
Type[] upperBounds = wc.getUpperBounds();
boolean hasLower = lowerBounds != null && lowerBounds.length > 0;
boolean hasUpper = upperBounds != null && upperBounds.length > 0;
if (hasUpper && hasLower && Object.class.equals(lowerBounds[0]) && Object.class.equals(upperBounds[0]))
{
sb.append('*');
}
else if (hasLower)
{
sb.append("-");
for (Type b : lowerBounds)
{
toGenericSignature(sb, b);
}
}
else if (hasUpper)
{
if (upperBounds.length == 1 && Object.class.equals(upperBounds[0]))
{
sb.append("*");
}
else
{
sb.append("+");
for (Type b : upperBounds)
{
toGenericSignature(sb, b);
}
}
}
else
{
sb.append('*');
}
}
else if (type instanceof TypeVariable)
{
//sb.append("T");
//sb.append(((TypeVariable) type).getName());
//sb.append(";");
// work around: replaces the type variable with it's first bound.
toGenericSignature(sb, ((TypeVariable) type).getBounds()[0]);
}
else
{
throw new IllegalArgumentException("Invalid type: " + type);
}
}