java - 仅更改方法结果和类加载器 NoSuchMethod

标签 java classloader name-mangling

我们从一个包含一个类和一种方法的 jar 开始,例如:

boolean foo( int bar ) { ... }

但是,此方法的结果是无用的(事实上,始终为真),并且使用此结果进行任何操作的客户端都会失败并出现错误。为此,方法改为:

void foo( int bar ) { ... }

并且所有项目都已重新编译。因此,我们可以假设该 jar 的所有用户都调用该方法:

foo(14);

没有人使用该表单(如果有人的话,则超出了此问题的范围):

boolean x = foo(14);

假设没有客户端(无论是新的还是旧的)使用 boolean 结果。

问题在于,在目标系统中,在不升级客户端的情况下加载新 jar。未更新的客户端在查找结果为“boolean”的“foo”方法时失败,并出现异常“NoSuchMethod”。即:

  • 客户端有一个类似“foo(14);”的语句不使用方法结果
  • 客户端是使用带有 boolean 方法的 jar 来编译的。
  • 客户端和库已加载到目标系统中
  • 库已使用 void 方法使用新 jar 进行更新
  • 客户端因“NoSuchMethod”而崩溃

问题的根源似乎是 Java 和 C/C++ 都不允许两种仅结果不同的方法,但只有 Java“名称修饰”在类加载器(链接器)的名称中包含结果类型在 C/C++ 中)正在寻找。

问题是:在这种情况下,有可能以任何方式欺骗库 jar 或类加载器来跳过“NoSuchMethod”异常吗?

最佳答案

这种行为完全是预料之中的。这是因为客户端编译的类包含 constant pool ,其中包括对方法的符号引用

假设我们有一个带有两个方法的 FooClass 类:

public boolean foo1(int bar) {
    return true;
}

public void foo2(int bar) {
    // ...
}

假设我们有另一个类 Main ,我们在其中调用这两个方法:

    FooClass fc = new FooClass();
    fc.foo1(1);
    fc.foo2(1);

如果我们反汇编Main.class,我们将看到方法引用不仅在名称上不同,而且在返回类型上也不同(注意(I)Z>(I)V):

     7: astore_1
     8: aload_1
     9: iconst_1
    10: invokevirtual #4                  // Method q42340444/FooClass.foo1:(I)Z
    13: pop
    14: aload_1
    15: iconst_1
    16: invokevirtual #5                  // Method q42340444/FooClass.foo2:(I)V

常量池包含:

   #4 = Methodref          #2.#25         // q42340444/FooClass.foo1:(I)Z
   #5 = Methodref          #2.#26         // q42340444/FooClass.foo2:(I)V

换句话说,它保留原始方法的返回类型,并在链接库中查找完全相同的方法,这会在您的情况下导致 NoSuchMethod 异常。

更具体地说,编译后的用户类链接到 FooClass.foo:(I)Z 方法,而您的新库不包含具有此类描述的方法,而仅包含 FooClass.foo :(I)V.

结论:如果不保留旧方法签名(可能最好使用 @Deprecated 注释对该方法进行注释)或重新编译客户端代码,则无法解决此问题.

关于java - 仅更改方法结果和类加载器 NoSuchMethod,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42340444/

相关文章:

java - 用 Java 聚合来自远程 Linux 服务器的日志文件?

java - 找不到带有 Class.forName() 的类,但它存在

c++ - GCC API 无法分解其自己的导出符号

c# - 如何将java嵌入到C#中

java - 如何在多模块maven项目中编译其中的单个模块?

java - Nexus 5 通知灯光颜色

java - 类加载器和重复的包和类名

java - 如何在java中使用类加载器获取数组类?

python - 防止 Ada DLL 中的名称错位

xcode - OpenCV 未解析的符号 - 名称修改不匹配 - xcode