在Java9中,如果我不知道它的模块,我怎么能反思地加载一个类?

时间:2017-04-06 05:37:45

标签: java reflection java-9

假设我有一个应用程序给出了一个众所周知的包名和类,我需要反射性地加载该类并从中调用一些方法。假设这个类在另一个java jar(“库”)中可用。

到目前为止,在java 9之前,因为类路径中的所有类都可用,所以直接实现这一点。

但是,对于Java 9,如果应用程序“module”不需要“library”包,则无法访问库类。

如何使用模块化罐子实现相同的行为?

示例:

这是我的申请:

// This is defined in ReflectionApp.jar
// ReflectionApp
// └── src
//     ├── module-info.java
//     └── org
//         └── reflection
//             └── app
//                 └── ReflectionApp.java
//
package org.reflection.app;

import java.lang.reflect.Method;

public class ReflectionApp {
    private static final String PACKAGE = "org.reflection.lib";
    private static final String CLASS = "ReflectiveClass";
    private static final String METHOD = "doSomeWork";

    public static void main(String[] args) throws Exception {

        // This will not work using java9
        Class<?> klass = Class.forName(String.format("%s.%s", PACKAGE, CLASS));
        Object obj = klass.getDeclaredConstructor().newInstance();
        Method meth = klass.getDeclaredMethod(METHOD);
        meth.invoke(obj);
    }
}

这是我的图书馆

// This is defined in ReflectionLib.jar
// ReflectionLib
// └── src
//     ├── module-info.java
//     └── org
//         └── reflection
//             └── lib
//                 └── ReflectiveClass.java
//
package org.reflection.lib;

public class ReflectiveClass {

    public void doSomeWork() {
        System.out.println("::: Doing some work!");
    }
}

目前,如果我尝试这样调用它(假设所有jar都在lib目录中创建并可用):

java --module-path lib -m ReflectionApp/org.reflection.app.ReflectionApp

然后我得到Exception in thread "main" java.lang.ClassNotFoundException: org.reflection.lib.ReflectiveClass

---解决方案---

感谢@Nicolai,我能够通过在命令中添加--add-modules参数来运行它。

⇒  java --module-path lib --add-modules ReflectionLib -m ReflectionApp/org.reflection.app.ReflectionApp
::: Doing some work!

2 个答案:

答案 0 :(得分:6)

plenty of ways to make reflection work,但没有一个像&#34那样直接;它只是工作&#34;在模块系统之前的方式。让我根据你的具体问题缩小范围。

但在此之前,您必须确保模块实际上将其放入模块图中。如果初始模块不能传递,则可以使用--add-modules library将其添加到图表中。

导出包

你写的是#34;如果应用程序&#39;模块&#39;不需要&#39;库&#39;包,库类无法访问&#34;。假设你的意思是 module 而不是 package ,这是真的,但不适用于此处。可访问性基于两件事:

  1. 两个模块之间的读取边缘
  2. 导出访问类型的访问模块
  3. 你没有写任何关于2.但是如果module library { exports org.reflection.lib; },那么你可以自由地使用反射。原因是当您开始使用反射API时会自动添加读取边缘。

    无法访问的类型

    现在它变得更有趣了。如果模块未导出org.reflection.libReflectiveClass未公开,则上述方法不起作用。在这种情况下,您有很多选择可供选择:

    • 将类型设为public并将包导出(可能只导入访问模块)
    • 打开包(可能只对访问模块)或模块
    • 添加命令行选项以实现上述任何

    要了解他们的比较方式,请查看有关reflection vs encapsulation in Java 9的文章。

答案 1 :(得分:1)

如果第一个模块不通过requires中的module-info.java子句依赖于第二个模块,则第二个模块不在第一个模块的依赖关系的传递闭包中。因此,第二个模块无法观察到运行时,并且您的反射失败。在这种情况下,您可以通过--add-modules选项将模块显式添加到模块图:

--add-modules <module-name>

在您的情况下,<module-name>应替换为ReflectionLib模块的名称。