在 Java 中,验证类路径中被调用的所有方法是否实际存在于该类路径中

如何解决在 Java 中,验证类路径中被调用的所有方法是否实际存在于该类路径中

给定一个类路径(例如一组 jar 文件),我想知道,这些 jar 文件中的任何一个是否会对类路径中不存在的方法进行方法调用(忽略反射)。

例如,如果我的类路径上只有 foo.jar,并且它有一个调用 com.bar.something#bar(String) 的类,而 foo.jar 中不存在该类,那么我会被告知方法实际上并不存在。

解决方法

据我所知,没有任何工具可以执行此操作,并且 JVM 不会在启动时盲目加载其类路径中包含的所有类。它只是加载你告诉它是主类的任何东西,并且每当它加载一个类时,它会检查它需要加载哪些其他类以理解其中包含的签名(因此,字段类型,无论它{{1} } 或 extends、方法返回类型、方法参数类型和方法异常类型 - 如果任何此类类型尚未加载,则任何此类类将作为加载类的一部分立即加载) - 并加载所需的类执行一个语句,但只有当这样的语句实际运行时。换句话说,java(VM)延迟加载。您不能将其用于此目的。

你可以做的事情相当复杂。让我们首先收紧您的要求:

  1. 给定一组“源 jar”(),验证其中包含的每个类文件。
  2. 要验证一个类,找到中所有类中包含的所有方法和字段访问,并通过与“一组目标 jar”进行比较,确保提到的字段/方法访问确实存在(目标)。源和目标可能相同,也可能不同。为方便起见,您可能希望以静默方式扩展 目标 以始终包含

任何尝试使用 VM 的类加载能力(例如,您直接使用反射加载类)都是有问题的:这将运行静态初始化程序,谁知道会产生什么样的令人讨厌的副作用。它也会非常慢。不是个好主意。

您想要的是不要依赖虚拟机本身,而是手动处理您自己的代码来实现这一点;毕竟,类文件只是文件,你可以读取它们,解析它们,并根据它们的内容采取行动。可以从 Java 代码中列出 Jar 文件并读取其内容 - 没问题。

类文件格式在 JVM 规范中有很好的描述,但它是一种非常复杂的格式。我强烈建议您使用可以读取它的现有库。 ASM 浮现在脑海中。

在实践中,任何方法调用都使用少数“INVOKE”操作码之一编码在类文件中(正常方法调用是 INVOKEVIRTUAL 或 INVOKEINTERFACE,静态方法是 INVOKESTATIC,构造函数和初始值设定项是 INVOKESPECIAL。字段访问(你没有提到这一点,但如果您要验证引用实体的存在,当然您还需要考虑字段)是 GETFIELD 和 SETFIELD。

然而,所有这些操作码都不会立即对它们所指的内容进行完整编码。相反,它们仅编码一个小的索引号:该数字将在类文件的常量池中查找,您可以在其中找到实际引用的方法/字段的完全限定规范。例如,调用 ArrayList's 'ensureCapacity' 方法在类文件格式中被命名为一个常量,它本身引用 2 个字符串常量:一个字符串常量包含值 implements,另一个包含值 { {1}}。 (I 是原始 "java/util/ArrayList" 类型的 class-file-ese,"ensureCapacity(I)V" 代表返回类型;V 是 int 的 class-file-ese)。

因此,有一个简单的快捷方式,无需解析类文件中包含的字节码。 只需扫描常量池 - 您需要做的就是验证常量池中的每个方法和字段引用是否引用了实际存在的方法或字段。

有了足够的类文件内部知识(我已经在此处介绍了您需要了解的大部分内容)以及对 ASM 库的一些基本经验,您应该能够自己使用 ASM 编写类似的内容一天左右的时间。如果这对你来说都是希腊语,那无疑需要一周的时间,但不会超过这个时间;最好是一个中等规模的项目。

希望这些是足够的指针,让您弄清楚从这里开始的地方,或者至少,知道需要什么以及如果您不想写它,您可能想在网上搜索什么但仍然希望有人已经完成了这项工作并将其作为开源库发布在某个地方。

注意:还有动态调用要复杂得多,但就其性质而言,您无法静态验证这些,因此大概是因为您无法与基于 V 的方法调用进行有意义的交互在这里不相关。类似地,任何使用 void API 的 Java 代码显然都没有使用任何这些东西,并且甚至无法以这种方式进行数学验证。因此,无需担心做不可能的事情。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?