简体   繁体   English

Java - 将私有静态字段复制到局部变量的反射

[英]Java - reflection to copy private static field to a local variable

private Methods : I know how to: private Methods :我知道如何:

  • Run a private void method without parameters 运行不带参数的私有void方法
  • Run a private void method with any numbers and Type of parameters 使用任何数字和参数类型运行私有void方法
  • Run a private return method without parameters and with any kind of return-Type 运行不带参数的私有返回方法和任何类型的return-Type
  • Run a private return method with any number and Type of parameters and with any kind of return-Type 使用任何数量和类型的参数以及任何类型的return-Type运行私有返回方法

private Fields : I know how to: private Fields :我知道如何:

  • Set any Type of private field 设置任何类型的私有字段
  • Set any Type of private static field 设置任何类型的私有静态字段
  • Set any Type of private final field 设置任何类型的私人最终字段
  • Set any Type of private static final field 设置任何类型的私有静态最终字段

private Fields : I know how to: private Fields :我知道如何:

  • Get any Type of private field 获取任何类型的私人领域
  • Get any Type of private final field 获取任何类型的私人最终字段

private Constructors : I know how to: private Constructors :我知道如何:

(Can be used to create a new Instance of the private Constructor in a Single-pattern, while keeping the instance Field null) (可用于在单一模式中创建私有构造函数的新实例,同时保持实例Field null)

  • Create a new Instance of a private Constructor without parameter 创建一个没有参数的私有构造函数的新实例
  • Create a new Instance of a private Constructor with any number and Type of parameters 使用任意数量和类型的参数创建私有构造函数的新实例

What I don't know, and what I want to know: 我不知道的,以及我想知道的:

  • Get any Type of private static Field and set it to a local (non-static) variable 获取任何类型的私有静态字段并将其设置为本地(非静态)变量
  • Get any Type of private static final Field and set it to a local (non-static) variable 获取任何类型的私有静态最终字段并将其设置为本地(非静态)变量

What and how should I change in my code? 我应该如何更改代码?

This part in the TestMethodsClass: TestMethodsClass中的这部分:

if(Modifier.isStatic(field.getModifiers())){
    Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    modifiersField.setInt(field, field.getModifiers() & ~Modifier.STATIC);
}

Or the call I do in a UnitTest-Class: 或者我在UnitTest-Class中进行的调用:

// Getting private STATIC String myString of the class MyClass and set it to a local variable
// public static call equivalent: String localString = myClassInstance.myString;
// public Getter call equivalent: String localString = myClassInstance.getMyString();
try {
    String localString = TestMethodsClass.getPrivateField(myClassInstance, "myString");
}
catch (MyUnitTestException ex) {
    Assert.fail("setPrivateField caused an Exception: " + ex.getThrownException());
}

My current class and some examples of how to call it: 我目前的课程以及如何调用它的一些示例:

TestMethodsClass.java: TestMethodsClass.java:

package unittests;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class TestMethodsClass
{
    // Test method to run a private void Method from a class
    public static void runPrivateVoidMethod(Object ob, String methodName, Class<?>[] paramTypes, Object[] paramValues) throws MyUnitTestException{
        try {
            Method method = null;
            if(paramTypes == null){
                method = ob.getClass().getDeclaredMethod(methodName, (Class[])null);
                if(method != null){
                    method.setAccessible(true);
                    method.invoke(ob);
                }
            }
            else{
                if(paramValues != null && paramTypes.length == paramValues.length){
                    method = ob.getClass().getDeclaredMethod(methodName, paramTypes);
                    if(method != null){
                        method.setAccessible(true);
                        method.invoke(ob, paramValues);
                    }
                }
                else
                    runPrivateReturnMethod(ob, methodName, null, null);
            }
        }
        catch (NoSuchMethodException ex){
            throw new MyUnitTestException(ex);
        }
        catch (IllegalAccessException ex){
            throw new MyUnitTestException(ex);
        }
        catch (IllegalArgumentException ex){
            throw new MyUnitTestException(ex);
        }
        catch (InvocationTargetException ex) {
            throw new MyUnitTestException(ex);
        }
    }

    // Test method to run a private Method that returns something from a class
    public static Object runPrivateReturnMethod(Object ob, String methodName, Class<?>[] paramTypes, Object[] paramValues) throws MyUnitTestException{
        Object returnObject = null;
        try {
            Method method = null;
            if(paramTypes == null){
                method = ob.getClass().getDeclaredMethod(methodName, (Class[])null);
                if(method != null){
                    method.setAccessible(true);
                    returnObject = method.invoke(ob);
                }
            }
            else{
                if(paramValues != null && paramTypes.length == paramValues.length){
                    method = ob.getClass().getDeclaredMethod(methodName, paramTypes);
                    if(method != null){
                        method.setAccessible(true);
                        returnObject = method.invoke(ob, paramValues);
                    }
                }
                else
                    returnObject = runPrivateReturnMethod(ob, methodName, null, null);
            }
        }
        catch (NoSuchMethodException ex){
            throw new MyUnitTestException(ex);
        }
        catch (IllegalAccessException ex){
            throw new MyUnitTestException(ex);
        }
        catch (IllegalArgumentException ex){
            throw new MyUnitTestException(ex);
        }
        catch (InvocationTargetException ex) {
            throw new MyUnitTestException(ex);
        }
        return returnObject;
    }

    // Test method to set a private Field from a class
    public static void setPrivateField(Object ob, String fieldName, Object value) throws MyUnitTestException{
        try {
            Field field = ob.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            if(Modifier.isStatic(field.getModifiers())){
                Field modifiersField = Field.class.getDeclaredField("modifiers");
                modifiersField.setAccessible(true);
                modifiersField.setInt(field, field.getModifiers() & ~Modifier.STATIC);
            }
            if(Modifier.isFinal(field.getModifiers())){
                Field modifiersField = Field.class.getDeclaredField("modifiers");
                modifiersField.setAccessible(true);
                modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
            }
            field.set(ob, value);
        }
        catch (NoSuchFieldException ex){
            throw new MyUnitTestException(ex);
        }
        catch (IllegalAccessException ex){
            throw new MyUnitTestException(ex);
        }
        catch (IllegalArgumentException ex){
            throw new MyUnitTestException(ex);
        }
    }

    // Test method to access a private Field from a class
    public static Object getPrivateField(Object ob, String fieldName) throws MyUnitTestException{
        Object returnObject = null;
        try {
            Field field = ob.getClass().getDeclaredField(fieldName);
            if(Modifier.isStatic(field.getModifiers())){
                Field modifiersField = Field.class.getDeclaredField("modifiers");
                modifiersField.setAccessible(true);
                modifiersField.setInt(field, field.getModifiers() & ~Modifier.STATIC);
            }
            returnObject = field.get(ob);
        }
        catch (NoSuchFieldException ex) {
            throw new MyUnitTestException(ex);
        }
        catch (IllegalAccessException ex) {
            throw new MyUnitTestException(ex);
        }
        catch (IllegalArgumentException ex) {
            throw new MyUnitTestException(ex);
        }
        return returnObject;
    }

    // test method to access a private Constructor (of a Singleton class)
    public static Object getPrivateConstuctor(Object ob, Class<?>[] paramTypes, Object[] paramValues) throws MyUnitTestException{
        Object returnObject = null;
        try {
            Constructor<?> constructor = null;
            if(paramTypes == null){
                constructor = ob.getClass().getDeclaredConstructor(paramTypes);
                if(constructor != null){
                    constructor.setAccessible(true);
                    returnObject = constructor.newInstance();
                }
            }
            else{
                if(paramValues != null && paramTypes.length == paramValues.length){
                    constructor = ob.getClass().getDeclaredConstructor(paramTypes);
                    if(constructor != null){
                        constructor.setAccessible(true);
                        returnObject = constructor.newInstance(paramValues);
                    }
                }
                else
                    getPrivateConstuctor(ob, null, null);
            }
        }
        catch (NoSuchMethodException ex) {
            throw new MyUnitTestException(ex);
        }
        catch (InstantiationException ex) {
            throw new MyUnitTestException(ex);
        }
        catch (IllegalAccessException ex) {
            throw new MyUnitTestException(ex);
        }
        catch (IllegalArgumentException ex) {
            throw new MyUnitTestException(ex);
        }
        catch (InvocationTargetException ex) {
            throw new MyUnitTestException(ex);
        }
        return returnObject;
    }
}

(Here is the getPrivateField again separtly, since this is the method where it's about.): (这里是seply的getPrivateField,因为这是它的方法。):

// Test method to access a private Field from a class
public static Object getPrivateField(Object ob, String fieldName) throws MyUnitTestException{
    Object returnObject = null;
    try {
        Field field = ob.getClass().getDeclaredField(fieldName);
        if(Modifier.isStatic(field.getModifiers())){
            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(field, field.getModifiers() & ~Modifier.STATIC);
        }
        returnObject = field.get(ob);
    }
    catch (NoSuchFieldException ex) {
        throw new MyUnitTestException(ex);
    }
    catch (IllegalAccessException ex) {
        throw new MyUnitTestException(ex);
    }
    catch (IllegalArgumentException ex) {
        throw new MyUnitTestException(ex);
    }
    return returnObject;
}

MyUnitTestException.java: MyUnitTestException.java:

package unittests;

public class MyUnitTestException extends Exception
{
    private static final long serialVersionUID = 1L;

    private Throwable thrownException;

    public MyUnitTestException(Throwable ex){
        super(ex);
        thrownException = ex;
    }

    public String getThrownException(){
        if(thrownException != null)
            return thrownException.getClass().getName();
        else
            return null;
    }
}

Example usages: 示例用法:

Setting private int myInteger of the class MyClass to 3: 将类MyClass的private int myInteger设置为3:

// public static call equivalent: myClassInstance.myInteger = 3;
// public Setter call equivalent: myClassInstance.setMyInteger(3);
try {
    TestMethodsClass.setPrivateField(myClassInstance, "myInteger", 3);
}
catch (MyUnitTestException ex) {
    Assert.fail("setPrivateField caused an Exception: " + ex.getThrownException());
}

Getting private String myString of the class MyClass and set it to a local variable: 获取MyClass类的私有String myString并将其设置为局部变量:

// public static call equivalent: String localString = myClassInstance.myString;
// public Getter call equivalent: String localString = myClassInstance.getMyString();
try {
    String localString = TestMethodsClass.getPrivateField(myClassInstance, "myString");
}
catch (MyUnitTestException ex) {
    Assert.fail("setPrivateField caused an Exception: " + ex.getThrownException());
}

Getting private (Constructor of) MyClass() and set it to a local variable: 获取私有(构造函数)MyClass()并将其设置为局部变量:

// public call equivalent: MyClass localMyClassInstance = new MyClass();
try {
    MyClass localMyClassInstance = TestMethodsClass.getPrivateConstructor(myClassInstance, null, null);
}
catch (MyUnitTestException ex) {
    Assert.fail("setPrivateField caused an Exception: " + ex.getThrownException());
}

Running a private void Setter-Method with a MyOtherObject as parameter: 使用MyOtherObject作为参数运行私有void Setter-Method:

// public call equivalent: myObjectInstance.setMyOtherClass(myOtherClassInstance);
try {
    TestMethodsClass.runPrivateVoidMethod(MyClass, "setMyOtherClass", new Class<?>[]{ MyOtherClass.class }, new Object[]{ myOtherClassInstance });
}
catch (MyUnitTestException ex) {
    Assert.fail("setPrivateField caused an Exception: " + ex.getThrownException());
}

PS: I only this in my UnitTests. PS:我只在我的UnitTests中使用它。


EDIT 1: 编辑1:

My UnitTest: 我的单位测试:

Controller controller = Controller.getInstance();

...

try {
    Controller cInstance = (Controller)TestMethodsClass.getPrivateField(controller, "instance");
}
catch (MyUnitTestException ex){
    Assert.fail("getPrivateField caused an Exception: " + ex.getThrownException());
}

instance -field of the Controller: Controller的instance字段:

// Singleton class where we store all lists of the Models
public class Controller
{
    // Default field used by the Singleton Design Pattern
    private static Controller instance;

    ...

    // This Constructor is private since this is a Singleton class
    private Controller() {
        ...
    }

    // Default method used by the Singleton Design Pattern
    public static Controller getInstance(){
        if(instance == null)
            instance = new Controller();

        return instance;
    }

    ...
}

This causes the following UnitTest.error in the catch. 这会导致catch中的以下UnitTest.error。

junit.framework.AssertionFailedError: getPrivateField caused an Exception: java.lang.IllegalAccessException
    at junit.framework.Assert.fail(Assert.java:47)
    at controllers.ControllerUnitTest.controllerTest(ControllerUnitTest.java:69)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:110)
    at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Thanks in advance for the responses. 在此先感谢您的回复。

  • Get any Type of private static Field and set it to a local (non-static) variable 获取任何类型的private static Field并将其设置为本地(非静态)变量
  • Get any Type of private static final Field and set it to a local (non-static) variable 获取任何类型的private static final Field并将其设置为本地(非静态)变量
Field privateStaticField = ...;
privateStaticField.setAccessible(true);
Object localVariable = privateStaticField.get(null);

Similarly for final field. 同样适用于final领域。

If you meant set the value of the field to the value of a local variable 如果您的意思是将字段的值设置为局部变量的值

Field privateStaticField = ...;
privateStaticField.setAccessible(true);
Object localVariable = ...;
privateStaticField.set(null, localVariable);

For final members, it is a little more complicated as you have to play with modifiers. 对于final成员来说,由于你必须使用修饰符,因此它会更复杂一些。 It gets worse if your field is a constant expression. 如果你的字段是一个常量表达式会变得更糟。 See here . 看到这里

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM