【问题标题】:Bypassing Java modularity via reflection通过反射绕过 Java 模块化
【发布时间】:2019-11-13 10:24:52
【问题描述】:

Java 模块系统是否应该阻止模块通过反射访问其他模块,而不声明正确的模块依赖关系?

例如,当编译这个 hello world Java 11 类时,它从另一个模块调用一个类,正如预期的那样,它不会编译,因为缺少对 java.xml 的依赖:

module m1 {}

package p1;
public class C1 {
    public static void main(String[] args) throws Exception {
        System.out.println(javax.xml.XMLConstants.XML_NS_URI);
    }
}

将模块依赖项添加到java.xml 后,它会按预期编译和运行。

但是,这个类:

module m1 {}

package p1;
public class C1 {
    public static void main(String[] args) throws Exception {
       System.out.println(Class.forName("javax.xml.XMLConstants").getField("XML_NS_URI").get(null));
    }
}

运行并打印结果,无需声明对java.xml的模块依赖:

java -version
openjdk version "11.0.2" 2019-01-15

java -p bin -m m1/p1.C1
http://www.w3.org/XML/1998/namespace

我们能够如此有效地绕过 Java 模块化。

这适用于任何模块到任何其他已解析的模块。

这怎么可能?模块系统是否应该防止这种情况发生?

【问题讨论】:

    标签: java java-module java-platform-module-system


    【解决方案1】:

    Java 模块系统中有两种可读性:static readabilityreflective readability。在模块系统的第一个版本中(在 Java 9 发布之前的开发过程中),这两种类型是相同的。因此,您的第二个示例确实会因错误而失败,因为从 m1java.xml 之间没有 requires 子句。后来这个政策被修改了,反射可读性的规则也被放宽了,因为这种严格的政策在许多严重依赖反射的框架(例如 Spring)中表现不佳。现在模块系统不要求反射的可读性边缘(但仍然必须导出目标类型,并且定义模块必须在模块图中)。

    5.2 反射可读性

    ...

    为了让我们需要做的框架可以访问提供者类 框架模块可读的提供者模块。我们可以 要求每个框架都明确添加必要的可读性 运行时模块图的边缘,就像在这个的早期版本中一样 文件,但经验表明这种方法很麻烦,而且 迁移障碍。

    因此,我们改为修改反射 API,只是假设 任何反映某种类型的代码都在一个可以读取 定义该类型的模块。这启用了上面的示例,并且 其他类似的代码,无需更改即可工作。这种方法不 弱化强封装:公共类型必须仍然在 导出的包,以便从其定义之外访问 模块,无论是来自编译代码还是通过反射。

    【讨论】:

      猜你喜欢
      • 2021-03-23
      • 2012-09-22
      • 1970-01-01
      • 2011-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多