简体   繁体   English

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

[英]Set private field of package-private Class from outer package Class with reflection

I need to change the value of a private variable in a package-private class from a outer-package class.我需要从外部包类更改包私有类中私有变量的值。

  • package: java.util.jar from jdk-9.0.1包:来自 jdk-9.0.1 的 java.util.jar
  • class: JarVerifier.java类:JarVerifier.java
  • variable: parsingBlockOrSF (private boolean)变量:parsingBlockOrSF(私有布尔值)

I tried this:我试过这个:

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

It gives me Exception in thread "main" java.lang.InstantiationException: java.util.jar.JarVerifier它给了我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 ?有人可以给我一个提示吗?


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:编辑 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);
}

Where the JarFile jf creates a new instance of JarVerifier and saves it in the variable called jv. JarFile jf 创建 JarVerifier 的新实例并将其保存在名为 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 ?这就是为什么我的目标是获得 JarVerifier 和 JarFile 这两个类,以便获得我想要访问的两个变量(一个从 JarVerifier 中获取实际的布尔解析块OrSF,另一个从 JarFile 实例中获取 JarVerifier 实例 jv。在我看来,上面显示的代码有意义并且应该可以工作,但它没有,那么我的错误在哪里?

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


Edit 2: changing the last line of the above code to : field.setBoolean(field1.getType(), newValue);编辑 2:将上述代码的最后一行更改为: field.setBoolean(field1.getType(), newValue);

It seems as the object is recognized, though it Can not set boolean field java.util.jar.JarVerifier.parsingBlockOrSF to java.lang.Class似乎该对象已被识别,但它Can not set boolean field java.util.jar.JarVerifier.parsingBlockOrSF to java.lang.Class


Edit 3: by using this Code:编辑 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);

I get this error: 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"我收到此错误: 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"

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 中 jarVerifier 中 parsingBlockOrSF 的值,因此我首先必须处理 jarFile 实例,从中取出 jarVerifier(我正在尝试使用 field1 =calcc.getDeclaredField("jv" ) 因为 jarVerifier 存储在 JarFile 内的 jv 变量中),然后使用该对象,修改其属性


The Code where the JarFile is created:创建 JarFile 的代码:

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

jarName is a String representing the path to the .jar File jarName 是一个字符串,表示 .jar 文件的路径

I could see that the JarVerifier class does not have a default Constructor.我可以看到 JarVerifier 类没有默认的构造函数。 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);

Reference for JarVerifier class: https://github.com/netroby/jdk9-dev/blob/master/jdk/src/java.base/share/classes/java/util/jar/JarVerifier.java JarVerifier 类参考: 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.假设:您的应用程序具有使用反射修改访问所需的安全权限。

Further reference: Java: newInstance of class that has no default constructor进一步参考: Java:没有默认构造函数的类的newInstance

You cannot change object from java.lang and java.util.jar package.您不能从 java.lang 和 java.util.jar 包更改对象。 these packages is system package and if you can't change it.these protects by jvm.这些包是系统包,如果你不能改变它。这些由 jvm 保护。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在公共类中使用包私有类 - Use package-private class in the public class 为什么Android类加载器允许从另一个包反射访问包私有类的公共字段? - Why does Android classloader allow reflective access to the public field of a package-private class from another package? 最终 class 中的受保护与私有包 - Protected vs package-private in final class 应用程序类可以是包私有的吗? - Can Application class be package-private? Spring在测试期间从package-private类获取配置 - Spring gets config from package-private class during test 为什么Java Reflection无法在另一个包中找到类的包私有构造函数? - Why can't Java Reflection find the package-private constructor of a class in another package? 通过另一个包的公共子类使用包私有类的公共方法引用时出现IllegalAccessError - IllegalAccessError when using a public method reference of a package-private class through a public subclass from another package .java文件中的包私有类 - 为什么它可以访问? - Package-private class within a .java file - why is it accessible? 如何在`java.util`中扩展package-private类 - How to extend package-private class in `java.util` 使用CGLib拦截JDK类的package-private方法 - Interception of package-private method for JDK class with CGLib
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM