使用反射从外部包 Class 设置包私有 Class 的私有字段
Set private field of package-private Class from outer package Class with reflection
我需要从外部包 class.
更改包私有 class 中私有变量的值
- 包:java.util.jar 来自 jdk-9.0.1
- class: 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
我已经看过 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 保护。
我需要从外部包 class.
更改包私有 class 中私有变量的值- 包:java.util.jar 来自 jdk-9.0.1
- class: 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
我已经看过 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 保护。