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

时间:2018-12-04 10:32:06

标签: java reflection java-9

我需要从外部包装类中更改包装私有类中的私有变量的值。

  • 软件包:jdk-9.0.1中的java.util.jar
  • 类:JarVerifier.java
  • 变量:parsingBlockOrSF(私有布尔值)

我尝试过:

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

尽管我无法为我的问题提供解决方案,但我已经看到thisthisthisthis问题。

有人可以给我一个提示吗?


编辑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的变量中。这就是为什么我旨在同时获得两个类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文件的路径

2 个答案:

答案 0 :(得分:2)

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

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类的参考: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

答案 1 :(得分:0)

您不能从java.lang和java.util.jar包更改对象。这些软件包是系统软件包,如果不能更改,则受jvm保护。