用ASM重命名的课程将ClasscastException和AppractMethoderror在编译JAR上重命名



我正在尝试使用ASM ClassRemapper重命名从编译的.jar到新名称的所有类,几乎所有内容都在运行,我的应用程序正常运行,直到使用ClassCastExceptionAbstractMethodError

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);

您不必要地覆盖方法mapDescmapMethodDescmapType,执行转换(尽管不正确处理阵列类型),然后调用ClassRemapper提供的超级实现,这些实现已经处理所有情况,例如跳过原始类型和分解数组类型,并为普通参考类型调用map(String internalName)。根据实际重命名方案,多次应用它可能会导致问题。

同样,当您不想重命名字段时,无需覆盖mapFieldName。无论您是否翻译所有者类型,继承的实现将简单地返回原始名称(还可以做什么)。但是这种过时的替代是无害的。

这将您的整个适配器简化为

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

最新更新