1

private Methods: I know how to:

  • Run a private void method without parameters
  • Run a private void method with any numbers and Type of parameters
  • Run a private return method without parameters and with any kind of return-Type
  • Run a private return method with any number and Type of parameters and with any kind of return-Type

private Fields: I know how to:

  • 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:

  • Get any Type of private field
  • Get any Type of private final field

private Constructors: I know how to:

(Can be used to create a new Instance of the private Constructor in a Single-pattern, while keeping the instance 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:

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:

// 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:

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.):

// 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:

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:

// 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:

// 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:

// 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:

// 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.


EDIT 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:

// 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.

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.

Kevin Cruijssen
  • 9,153
  • 9
  • 61
  • 135
  • See `if` you can see `what's annoying` about this comment `and apply` the solution to `your` question :-) – Duncan Jones May 23 '14 at 15:27
  • @Duncan I've only used it to make the differences more clear. For example the "private", "private static", "private final" and "private static final". Ah well, removed it, see if it's better like this. – Kevin Cruijssen May 26 '14 at 07:00

1 Answers1

6
  • 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
Field privateStaticField = ...;
privateStaticField.setAccessible(true);
Object localVariable = privateStaticField.get(null);

Similarly for final field.

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. It gets worse if your field is a constant expression. See here.

Community
  • 1
  • 1
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724