Reputation: 405
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
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