使用反射将外部包类中的package-private类的private字段设置为 [英] Set private field of package-private Class from outer package Class with reflection

查看:76
本文介绍了使用反射将外部包类中的package-private类的private字段设置为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I need to change the value of a private variable in a package-private class from a outer-package 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

我已经看到>这个问题,尽管我无法为我的问题.

I have seen this, this, this and this question already, though I am not able to derive a solution for my problem.

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

Can someone give me a hint please ?

,因为我想在运行时修改parsingBlockOrSF的值(就像我通过调试器进行了更改一样),因此我需要一个JarVerifier实例,因此需要一个JarFile实例(感谢Gyro Gearless).看看Ankur Chrungoo提出的方法,我发现我需要获取一个已经存在的JarVerifier实例,因此我尝试了以下方法:

Edit 1: as I want to modify the value of parsingBlockOrSF during runtime (as if I changed it through debugger) I need an existing instance of JarVerifier thus of JarFile (thank you Gyro Gearless) By taking a look at the approach proposed by Ankur Chrungoo, I figured out I would need to get an already existing Instance of JarVerifier, thus I tried this:

    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.在我看来,上面显示的代码有意义并且应该可以工作,但是没有用,所以我的错误在哪里?

Where the JarFile jf creates a new instance of JarVerifier and saves it in the variable called jv. Thats why I am aiming to get both classes JarVerifier and JarFile, in order to get both variable I want to access (one beeing the actual boolean parsingBlockOrSF from the JarVerifier, the other beeing the JarVerifier instance jv from the JarFile instance. In my mind the code shown above make sense and should work, but it doesn't, so where is my mistake ?

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

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

Edit 2: changing the last line of the above code to : field.setBoolean(field1.getType(), newValue);

尽管它是Can not set boolean field java.util.jar.JarVerifier.parsingBlockOrSF to java.lang.Class

,使用此代码:

    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变量中),然后使用该对象修改其属性

Here I want to change the value of the parsingBlockOrSF in the jarVerifier inside the JarFile, so I first must work on the jarFile instance, get the jarVerifier out of it (what I am trying to do with field1 = calcc.getDeclaredField("jv") as the jarVerifier is stored in the jv variable inside the JarFile), and then using that object, modify its property

创建JarFile的代码:

The Code where the JarFile is created:

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

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

jarName is a String representing the path to the .jar File

推荐答案

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

I could see that the JarVerifier class does not have a default Constructor. The constructor it has is something like this:-

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<>();
    }

因此,您将必须使用反射获取非默认构造函数,然后使用它来创建实例. 因此,您的代码应如下所示:-

So, you would have to get the non-default Constructor using reflection and then use it to create the instance. So, your code should be something like this:-

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

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

假设:您的应用程序具有必需的安全权限,可以使用反射来修改访问权限.

Assumption: Your application has the required security permissions to modify access using reflection.

进一步参考: Java:没有类的newInstance默认构造函数

这篇关于使用反射将外部包类中的package-private类的private字段设置为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆