使用 ASM 重命名 类 会在已编译的 jar 上抛出 ClassCastException 和 AbstractMethodError
Renaming classes with ASM throws ClassCastException and AbstractMethodError on compiled jar
我正在尝试使用 ASM ClassRemapper 将编译后的 .jar 中的所有 类 重命名为新名称 ClassRemapper 几乎一切正常,我的应用程序正常运行,直到它崩溃 ClassCastException
或 AbstractMethodError
ClassRemapper adapter = new ClassRemapper(classWriter, new Remapper()
{
@Override
public String mapType(String s)
{
return super.mapType(getNewName(s));
}
@Override
public String mapFieldName(String owner, String name, String descriptor)
{
Type type = Type.getType(descriptor);
descriptor = descriptor.replace(type.getClassName(), getNewName(type.getClassName()));
return super.mapFieldName(getNewName(owner), name, descriptor);
}
@Override
public String map(String internalName)
{
return getNewName(internalName);
}
@Override
public String mapDesc(String descriptor)
{
Type type = Type.getType(descriptor);
descriptor = descriptor.replace(type.getClassName(), getNewName(type.getClassName()));
return super.mapDesc(descriptor);
}
@Override
public String mapMethodDesc(String methodDescriptor)
{
Type methodType = Type.getMethodType(methodDescriptor);
List<Type> types = new LinkedList<>();
for (Type argumentType : methodType.getArgumentTypes())
types.add(Type.getType(argumentType.getDescriptor().replace(argumentType.getClassName(), getNewName(argumentType.getClassName()))));
Type returnType = Type.getReturnType(methodDescriptor);
returnType = Type.getReturnType("()" + returnType.getDescriptor().replace(returnType.getClassName(), getNewName(returnType.getClassName())));
return super.mapMethodDesc(Type.getMethodDescriptor(returnType, types.toArray(new Type[0])));
}
});
我想我在方法中遗漏了一些东西,但我找不到什么。
getNewName(string)
基本上是 map.getOrDefault(string, string);
您不必要地重写方法 mapDesc
、mapMethodDesc
和 mapType
,执行转换(尽管没有正确处理数组类型),然后调用 ClassRemapper
已经处理了所有情况,例如跳过原始类型和分解数组类型,并为普通引用类型调用 map(String internalName)
。根据实际的重命名方案,多次应用它可能会导致问题。
同样,当您不想重命名字段时,无需覆盖 mapFieldName
。继承的实现将简单地 return 原始名称(它还能做什么),无论您是否翻译所有者类型。但是这个过时的覆盖是无害的。
这会将您的整个适配器简化为
ClassRemapper adapter = new ClassRemapper(classWriter, new Remapper()
{
@Override
public String map(String internalName)
{
return getNewName(internalName);
}
});
我正在尝试使用 ASM ClassRemapper 将编译后的 .jar 中的所有 类 重命名为新名称 ClassRemapper 几乎一切正常,我的应用程序正常运行,直到它崩溃 ClassCastException
或 AbstractMethodError
ClassRemapper adapter = new ClassRemapper(classWriter, new Remapper()
{
@Override
public String mapType(String s)
{
return super.mapType(getNewName(s));
}
@Override
public String mapFieldName(String owner, String name, String descriptor)
{
Type type = Type.getType(descriptor);
descriptor = descriptor.replace(type.getClassName(), getNewName(type.getClassName()));
return super.mapFieldName(getNewName(owner), name, descriptor);
}
@Override
public String map(String internalName)
{
return getNewName(internalName);
}
@Override
public String mapDesc(String descriptor)
{
Type type = Type.getType(descriptor);
descriptor = descriptor.replace(type.getClassName(), getNewName(type.getClassName()));
return super.mapDesc(descriptor);
}
@Override
public String mapMethodDesc(String methodDescriptor)
{
Type methodType = Type.getMethodType(methodDescriptor);
List<Type> types = new LinkedList<>();
for (Type argumentType : methodType.getArgumentTypes())
types.add(Type.getType(argumentType.getDescriptor().replace(argumentType.getClassName(), getNewName(argumentType.getClassName()))));
Type returnType = Type.getReturnType(methodDescriptor);
returnType = Type.getReturnType("()" + returnType.getDescriptor().replace(returnType.getClassName(), getNewName(returnType.getClassName())));
return super.mapMethodDesc(Type.getMethodDescriptor(returnType, types.toArray(new Type[0])));
}
});
我想我在方法中遗漏了一些东西,但我找不到什么。
getNewName(string)
基本上是 map.getOrDefault(string, string);
您不必要地重写方法 mapDesc
、mapMethodDesc
和 mapType
,执行转换(尽管没有正确处理数组类型),然后调用 ClassRemapper
已经处理了所有情况,例如跳过原始类型和分解数组类型,并为普通引用类型调用 map(String internalName)
。根据实际的重命名方案,多次应用它可能会导致问题。
同样,当您不想重命名字段时,无需覆盖 mapFieldName
。继承的实现将简单地 return 原始名称(它还能做什么),无论您是否翻译所有者类型。但是这个过时的覆盖是无害的。
这会将您的整个适配器简化为
ClassRemapper adapter = new ClassRemapper(classWriter, new Remapper()
{
@Override
public String map(String internalName)
{
return getNewName(internalName);
}
});