标记为抽象但未由 javap 显示的方法

Method marked as abstract but not shown by javap

这是一个非常特殊的案例,似乎是 .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/util/List;)Ljava/util/List; at broker.services.resolver.impl.FileSyncServiceImpl.fetchFiles(FileSyncServiceImpl.java:71) at broker.services.resolver.impl.TransferFileSync.run(TransferFileSync.java:71) at 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) returns true。因此调试方法 getArchivedFilesByLastSyncTime 显示为 abstractjavap 以其他方式建议。但是我反编译FTGServiceLight的时候确实显示了body这个方法,所以好像是被覆盖了

可能导致此行为的原因

PS:我检查了 mvn 依赖树,这个 class 的替代版本从来没有出现过。

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

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

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

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

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

是一样的吗class老大?

您可以尝试的另一件事是检查 classloader 从哪些位置加载 classes。在 FileSyncServiceImpl 中执行:

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

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