使用反射从外部包 Class 设置包私有 Class 的私有字段

Set private field of package-private Class from outer package Class with reflection

我需要从外部包 class.

更改包私有 class 中私有变量的值

我试过这个:

private void writePrivateJarVerifierField(boolean newValue) throws Exception {
    Class<?> clazz = Class.forName("java.util.jar.JarVerifier");
    Field field = clazz.getDeclaredField("parsingBlockOrSF");
    field.setAccessible(true);
    field.setBoolean(clazz.newInstance(), newValue);
}

它给了我Exception in thread "main" java.lang.InstantiationException: java.util.jar.JarVerifier

我已经看过 this, this, this and this 个问题,但我无法为我的问题得出解决方案。

有人可以给我提示吗?


编辑 1: 因为我想在运行时修改 parsingBlockOrSF 的值(就像我通过调试器更改它一样)我需要一个现有的 JarVerifier 实例,因此是 JarFile 的实例(谢谢你 Gyro Gearless)通过查看 Ankur Chrungoo 提出的方法,我发现我需要获得一个已经存在的 JarVerifier 实例,因此我尝试了这个:

    private void writePrivateJarVerifierField(boolean newValue, JarFile jf) throws Exception {
    Class<?> clazz = Class.forName("java.util.jar.JarVerifier");
    Class<?> clacc = Class.forName("java.util.jar.JarFile");
    Field field = clazz.getDeclaredField("parsingBlockOrSF");
    Field field1 = clacc.getDeclaredField("jv");
    field.setAccessible(true);
    field1.setAccessible(true);
    field.setBoolean(field1.get(jf), newValue);
}

其中 JarFile jf 创建了一个新的 JarVerifier 实例并将其保存在名为 jv 的变量中。这就是为什么我的目标是同时获得 classes JarVerifier 和 JarFile,以便获得我想要访问的两个变量(一个是来自 JarVerifier 的实际布尔 parsingBlockOrSF,另一个是来自 JarFile 实例的 JarVerifier 实例 jv . 在我看来,上面显示的代码是有道理的并且应该可以工作,但它没有,所以我的错误在哪里?

我得到的异常:java.lang.NullPointerException at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:57)


编辑 2: 将上述代码的最后一行更改为: field.setBoolean(field1.getType(), newValue);

虽然它Can not set boolean field java.util.jar.JarVerifier.parsingBlockOrSF to java.lang.Class

,但似乎已识别出该对象

编辑 3: 使用此代码:

    Class<?> clazz = Class.forName("java.util.jar.JarVerifier");
Class<?> clacc = Class.forName("java.util.jar.JarFile");
Field field = clazz.getDeclaredField("parsingBlockOrSF");
Field field1 = clacc.getDeclaredField("jv");
field.setAccessible(true);
field1.setAccessible(true);
field.setBoolean(clazz.getConstructor(byte[].class).newInstance(new byte[1]), newValue);

我收到此错误:Exception in thread "main" java.lang.IllegalAccessException: class JarVerifier cannot access a member of class java.util.jar.JarVerifier (in module java.base) with modifiers "public"

这里我想更改 JarFile 中的 jarVerifier 中的 parsingBlockOrSF 的值,所以我首先必须处理 jarFile 实例,从中获取 jarVerifier(我正在尝试对 field1 执行的操作 = calcc.getDeclaredField("jv") 因为 jarVerifier 存储在 JarFile 中的 jv 变量中),然后使用该对象,修改其 属性


创建 JarFile 的代码:

    JarFile jf = null;
    jf = new JarFile(jarName, true);

jarName 是表示 .jar 文件路径的字符串

我可以看到 JarVerifier class 没有默认的构造函数。 它的构造函数是这样的:-

public JarVerifier(byte rawBytes[]) {
        manifestRawBytes = rawBytes;
        sigFileSigners = new Hashtable<>();
        verifiedSigners = new Hashtable<>();
        sigFileData = new Hashtable<>(11);
        pendingBlocks = new ArrayList<>();
        baos = new ByteArrayOutputStream();
        manifestDigests = new ArrayList<>();
    }

因此,您必须使用反射获取非默认构造函数,然后使用它来创建实例。 所以,你的代码应该是这样的:-

field.setBoolean(clazz.getConstructor(byte[].class).newInstance(new byte[1]), newValue);

JarVerifier 参考 class:https://github.com/netroby/jdk9-dev/blob/master/jdk/src/java.base/share/classes/java/util/jar/JarVerifier.java

假设:您的应用程序具有使用反射修改访问权限所需的安全权限。

进一步参考:Java: newInstance of class that has no default constructor

您不能更改 java.lang 和 java.util.jar 包中的对象。这些包是系统包,如果你不能改变 it.these 由 jvm 保护。