【问题标题】:Method marked as abstract but not shown by javap标记为抽象但 javap 未显示的方法
【发布时间】:2015-12-31 13:01:11
【问题描述】:

这是一个非常特殊的案例,似乎是 .class 文件损坏。我们的应用程序依赖于其他团队提供的依赖项。有 2 个相关的 java 文件:FTGServiceFTGServiceLight implements FTGService

所以当我执行javap -p FTGService 时,它会打印:

....  
public abstract java.util.List<munshi.transfers.domain.TransferredFile> getArchivedFilesByLastSyncTime(java.util.Date, java.util.Date, java.util.Date, java.util.Date, java.util.Date, java.util.List<java.lang.String>, java.util.List<java.lang.Integer>);

在执行javap -p FTGServiceLight 时,它会打印:

....  
public java.util.List<munshi.transfers.domain.TransferredFile> getArchivedFilesByLastSyncTime(java.util.Date, java.util.Date, java.util.Date, java.util.Date, java.util.Date, java.util.List<java.lang.String>, java.util.List<java.lang.Integer>);
....

当我做javap -v FTGServiceLight时,可以在here找到相关信息。

但是运行时会报错:

java.lang.AbstractMethodError: munshi.transfers.service.light.FTGServiceLight.getArchivedFilesByLastSyncTime(Ljava/util/Date;Ljava/util/Date;Ljava/util/Date;Ljava/util/Date;Ljava/util/Date;Ljava/util/List;Ljava/实用程序/列表;)Ljava/实用程序/列表; 在 broker.services.resolver.impl.FileSyncServiceImpl.fetchFiles(FileSyncServiceImpl.java:71) 在 broker.services.resolver.impl.TransferFileSync.run(TransferFileSync.java:71) 在 sun.reflect.GeneratedMethodAccessor129.invoke(Unknown Source) at

getArchivedFilesByLastSyncTime 出于某种原因被标记为abstract。此外,当我调试它时,这就是它所显示的:

FTGServiceLight.getMethod("getArchivedFilesByLastSyncTime",Date.class,Date.class,Date.class,Date.class,Date.class, List.class, List.class))

注意modifiers 显示为1025,执行Modifiers.isAbstract(1025) 返回true。因此,调试方法getArchivedFilesByLastSyncTime 显示为abstract,但javap 建议采用其他方式。但是当我反编译FTGServiceLight时,确实显示了body的方法,所以好像被覆盖了。

什么可能导致这种行为

PS:我已经检查了 mvn 依赖树,并且这个类的替代版本从未出现过。

【问题讨论】:

  • 也许你有多个版本的类,Javap看到的和JVM看到的不同。
  • 如后期脚本中所述。只有一个依赖项。

标签: java jvm javac bytecode


【解决方案1】:

看起来确实是一个多重依赖问题。仅检查 Maven 依赖树并不能确保您在运行时没有同一类的多个版本。

它可以被缓存,它可以从不同的地方加载,等等。在 FileSyncServiceImpl 中,尝试打印出加载 FTGServiceLight 的位置:

 System.out.println(
    FTGServiceLight.class.getClassLoader().getResource(
        FTGServiceLight.class.getName().replace('.', '/') + ".class"));

并与使用此类的上下文进行比较:

 System.out.println(
    FileSyncServiceImpl.class.getClassLoader().getResource(
        FileSyncServiceImpl.class.getName().replace('.', '/') + ".class"));

是同一个classlaoder吗?

您可以尝试的另一件事是检查类加载器用来加载类的位置是什么。在 FileSyncServiceImpl 中执行:

 System.out.print(
    Arrays.toString(((URLClassLoader)
        Test1.class.getClassLoader()).getURLs()));

它将为您提供该类加载器所在的 jar 文件(和目录)列表。然后,您可以检查 FTGServiceLight 是否位于其中任何一个以及是否多次出现。

【讨论】:

  • 谢谢@Anton。您的第一个建议帮助我解决了问题。问题是:我们的很多罐子都是自动生成的。碰巧的是,我的依赖项中有一些 jar,它也包含 FTGServiceLight 在同一个包结构中。但是该文件属于以前的版本,并且在自动生成时它包含了以前的版本文件。我的应用程序选择了那个,导致错误。
猜你喜欢
  • 2013-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多