从具有反射的外部包Class设置包private Class的私有字段



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

  • 包:来自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

我已经看到了这个、这个、这个和这个问题,尽管我无法找到解决我的问题的办法。

有人能给我一个提示吗?


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

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实例,从中取出jarVerifer(我试图用field1=calcc.getDeclaredField("jv"(来做的事情,因为jarVerififer存储在JarFile中的jv变量中(,然后使用该对象修改其属性


创建JarFile的代码:

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

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

我可以看到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

您无法更改java.lang和java.util.jar包中的对象。这些包是系统包,如果您不能更改它,则由jvm保护。