Foreign
Foreign

Reputation: 405

Renaming classes with ASM throws ClassCastException and AbstractMethodError on compiled jar

I'm trying to rename all classes from a compiled .jar to new names using ASM ClassRemapper almost everything is working, my app runs normally until it crashes with either ClassCastException or 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])));
    }
});

I think I am missing something within methods, but I couldn't find what.

getNewName(string) is basically map.getOrDefault(string, string);

Upvotes: 1

Views: 580

Answers (1)

Holger
Holger

Reputation: 298529

Your are unnecessarily overriding the methods mapDesc, mapMethodDesc, and mapType, performing conversions (though not handling array types correctly), followed by invoking the super implementations provided by ClassRemapper which do already handle all cases, e.g. skipping primitive types and decomposing array types, and invoke map(String internalName) for ordinary references types. Depending on the actual renaming scheme, applying it multiple times may cause the problems.

Likewise, there is no need to override mapFieldName when you don’t want to rename fields. The inherited implementation will simply return the original name (what else could it do), whether you translate the owner type or not. But this obsolete override is harmless.

This simplifies your entire adapter to

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

Upvotes: 2

Related Questions