Переименование классов с помощью ASM создает исключение ClassCastException и AbstractMethodError на скомпилированном jar - PullRequest
0 голосов
/ 02 марта 2019

Я пытаюсь переименовать все классы из скомпилированного .jar в новые имена, используя ASM 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);

1 Ответ

0 голосов
/ 05 марта 2019

Вы без необходимости переопределяете методы mapDesc, mapMethodDesc и mapType, выполняете преобразования (хотя и не обрабатываете типы массивов правильно), после чего вызываете супер реализации, предоставляемые ClassRemapper, которые уже обрабатывают все случаиНапример, пропуская примитивные типы и декомпозируя типы массивов, и вызывайте map(String internalName) для обычных ссылочных типов.В зависимости от фактической схемы переименования, многократное применение может вызвать проблемы.

Аналогично, нет необходимости переопределять mapFieldName, если вы не хотите переименовывать поля.Унаследованная реализация просто вернет исходное имя (что еще оно может сделать), независимо от того, переводите ли вы тип владельца или нет.Но это устаревшее переопределение безвредно.

Это упрощает весь ваш адаптер до

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