Maven插件中使用ByteBuddy重命名内部类失败求助
Maven插件中ByteBuddy重命名内部类报错解决
在Maven插件的process-classes阶段使用ByteBuddy重命名类时,顶级类重命名成功,但处理内部类时出现以下错误:
Constructor public dev.rvr.MainImpl$CoolImpl() defines an illegal receiver class dev.rvr.Main
实现代码
String className = classNameOfFile(root, file); try { Class<?> clazz = cl.loadClass(className); if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) { return; } var builder = new ByteBuddy().rebase(clazz).name(className + "Impl"); var unloaded = builder.make(); var loaded = unloaded.load(cl); unloaded.saveIn(root); Queue<Class<?>> queue = new LinkedList<>(Arrays.stream(clazz.getDeclaredClasses()).toList()); while (!queue.isEmpty()) { var innerClass = queue.poll(); String name = innerClass.getSimpleName(); new ByteBuddy().rebase(innerClass).innerTypeOf(loaded.getLoaded()).name(className+"Impl$"+name+"Impl").make().saveIn(root); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IOException e) { throw new RuntimeException(e); }
目标类代码
public class Main { public static void main(String[] args) { System.out.println("Hello world!"); } public TestingThing getTestingThing() { return new TestingThing(); } public Cool getCool() { return new Cool(); } public static class Cool{ public void cool(){ System.out.println("Cool"); } public void cool2(){ System.out.println("Cool2"); } public void cool3(){ System.out.println("Cool3"); } } }
问题原因
报错的核心是:内部类(即使是static内部类)的构造方法中仍然保留了对原顶级类dev.rvr.Main的引用,而我们已经将顶级类重命名为dev.rvr.MainImpl,导致接收器类不匹配。同时,顶级类中创建内部类的代码(比如getCool()方法)仍然指向原内部类名称,也需要同步更新。
解决方案
修改代码,确保内部类的所有引用都指向新的顶级类,同时更新顶级类中对内部类的引用:
String className = classNameOfFile(root, file); try { Class<?> clazz = cl.loadClass(className); if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) { return; } String newTopClassName = className + "Impl"; // 处理顶级类,同步修改内部类引用 var topBuilder = new ByteBuddy().rebase(clazz) .name(newTopClassName) .visit(new AgentBuilder.Transformer() { @Override public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) { return builder.method(ElementMatchers.any()) .intercept(MethodDelegation.to(new Object() { @RuntimeType public Object intercept(@Origin Method method, @AllArguments Object[] args, @SuperCall Callable<?> callable) throws Exception { // 替换原内部类实例为新的内部类实例 if (method.getReturnType().isMemberClass() && method.getReturnType().getEnclosingClass() == clazz) { String innerSimpleName = method.getReturnType().getSimpleName(); String newInnerClassName = newTopClassName + "$" + innerSimpleName + "Impl"; Class<?> newInnerClass = cl.loadClass(newInnerClassName); return newInnerClass.getDeclaredConstructor().newInstance(); } return callable.call(); } })); } }); var topUnloaded = topBuilder.make(); var topLoaded = topUnloaded.load(cl); topUnloaded.saveIn(root); Queue<Class<?>> queue = new LinkedList<>(Arrays.stream(clazz.getDeclaredClasses()).toList()); while (!queue.isEmpty()) { var innerClass = queue.poll(); String innerSimpleName = innerClass.getSimpleName(); String newInnerClassName = newTopClassName + "$" + innerSimpleName + "Impl"; // 处理内部类,修正接收器类引用 var innerBuilder = new ByteBuddy().rebase(innerClass) .name(newInnerClassName) .innerTypeOf(topLoaded.getLoaded()) .visit(new AgentBuilder.Transformer() { @Override public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) { return builder.constructor(ElementMatchers.any()) .intercept(ConstructorDelegation.to(innerClass.getDeclaredConstructor()) .withParameterBinder(FieldLocator.ForInstrumentedField.of("this$0").bindTo(topLoaded.getLoaded()))); } }); var innerUnloaded = innerBuilder.make(); innerUnloaded.load(cl); innerUnloaded.saveIn(root); } } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } catch (IOException e) { throw new RuntimeException(e); }
关键修改点
- 统一管理新的类名:为顶级类和内部类定义一致的命名规则,避免名称不匹配
- 修正内部类构造方法:通过参数绑定将
this$0字段指向新的顶级类实例,解决接收器类非法的问题 - 更新顶级类内部引用:拦截创建内部类的方法,返回新的内部类实例,确保调用逻辑正确
内容的提问来源于stack exchange,提问作者rowan-vr
相关产品推荐
相关产品推荐

