Java 使用ASM重命名类会在已编译的jar上引发ClassCastException和AbstractMethodError

Java 使用ASM重命名类会在已编译的jar上引发ClassCastException和AbstractMethodError,java,java-bytecode-asm,Java,Java Bytecode Asm,我正在尝试使用ASM将编译后的.jar中的所有类重命名为新名称。几乎所有功能都正常工作,我的应用程序一直正常运行,直到崩溃时出现ClassCastException或AbstractMethodError ClassRemapper adapter = new ClassRemapper(classWriter, new Remapper() { @Override public String mapType(String s) { return supe

我正在尝试使用ASM将编译后的.jar中的所有类重命名为新名称。几乎所有功能都正常工作,我的应用程序一直正常运行,直到崩溃时出现
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])));
    }
});
ClassRemapper adapter=newclassremapper(classWriter,newremapper())
{
@凌驾
公共字符串映射类型(字符串s)
{
返回super.mapType(getNewName);
}
@凌驾
公共字符串mapFieldName(字符串所有者、字符串名称、字符串描述符)
{
Type Type=Type.getType(描述符);
descriptor=descriptor.replace(type.getClassName(),getNewName(type.getClassName());
返回super.mapFieldName(getNewName(owner)、name、descriptor);
}
@凌驾
公共字符串映射(字符串名称)
{
返回getNewName(internalName);
}
@凌驾
公共字符串mapDesc(字符串描述符)
{
Type Type=Type.getType(描述符);
descriptor=descriptor.replace(type.getClassName(),getNewName(type.getClassName());
返回super.mapDesc(描述符);
}
@凌驾
公共字符串mapMethodDesc(字符串方法描述符)
{
类型methodType=Type.getMethodType(methodDescriptor);
列表类型=新建LinkedList();
对于(类型argumentType:methodType.getArgumentTypes())
添加(Type.getType(argumentType.getDescriptor().replace(argumentType.getClassName()、getNewName(argumentType.getClassName()))));
类型returnType=Type.getReturnType(methodDescriptor);
returnType=Type.getReturnType(“()”+returnType.getDescriptor().replace(returnType.getClassName()、getNewName(returnType.getClassName()));
return super.mapMethodDesc(Type.getMethodDescriptor(returnType,types.toArray(新类型[0]));
}
});
我想我在方法中遗漏了一些东西,但我找不到什么


getNewName(string)
基本上是
map.getOrDefault(string,string)

您正在不必要地重写方法
mapDesc
mapMethodDesc
mapType
,执行转换(尽管没有正确处理数组类型),然后调用
ClassRemapper
提供的超级实现,这些方法已经处理了所有情况,例如,跳过基本类型和分解数组类型,并为普通引用类型调用
map(String internalName)
。根据实际的重命名方案,多次应用可能会导致问题

同样,如果不想重命名字段,则无需覆盖
mapFieldName
。继承的实现将只返回原始名称(它还能做什么),不管您是否转换所有者类型。但这种过时的覆盖是无害的

这简化了您的整个适配器

ClassRemapper adapter = new ClassRemapper(classWriter, new Remapper()
{
    @Override
    public String map(String internalName)
    {
        return getNewName(internalName);
    }
});

您的大多数覆盖都是完全不必要的,甚至可能导致矛盾的结果
@Override public String map(String internalName){return getNewName(internalName);}
是您需要的唯一覆盖。根据您的重命名方案,多次应用可能会导致问题。除此之外,我建议阅读,因为这是一种典型的情况,
LinkedList
浪费资源,而与
ArrayList
相比没有任何好处……在我删除了不必要的覆盖之后,它工作得很好。我想我应该更好地阅读asm的文档。谢谢