What is the shortest, best, cleanest way to set a private field via Reflection in Java?

怎甘沉沦 提交于 2021-02-18 22:30:32

问题


Hi I've already worked with Reflection in Java. But if you are using the java standards (e.g. injecting a private field) you have to write a lot of code to get the job done.

What is the shortest way to inject a private field in a Java Object? Are there implementations in widely used and production ready libraries?


回答1:


Without using external libraries you need to:

  • get the Field instance
  • set the field instance as accessible
  • set the new value

As follow:

Field f1 = obj.getClass().getDeclaredField("field");
f1.setAccessible(true);
f1.set(obj, "new Value");



回答2:


The "One-Liner"

FieldUtils.writeField(Object target, String fieldName, Object value, boolean forceAccess)

If your Project uses Apache Commons Lang the shortest way to set a value via reflection is to use the static Method 'writeField' in the class 'org.apache.commons.lang3.reflect.FieldUtils'

The following simple example shows a Bookstore-Object with a field paymentService. The code shows how the private field is set two times with a different value.

import org.apache.commons.lang3.reflect.FieldUtils;

public class Main2 {
    public static void main(String[] args) throws IllegalAccessException {
        Bookstore bookstore = new Bookstore();

        //Just one line to inject the field via reflection
        FieldUtils.writeField(bookstore, "paymentService",new Paypal(), true);
        bookstore.pay(); // Prints: Paying with: Paypal

        //Just one line to inject the field via reflection
        FieldUtils.writeField(bookstore, "paymentService",new Visa(), true);
        bookstore.pay();// Prints Paying with: Visa
    }

    public static class Paypal implements  PaymentService{}

    public static class Visa implements  PaymentService{}

    public static class Bookstore {
        private  PaymentService paymentService;
        public void pay(){
            System.out.println("Paying with: "+ this.paymentService.getClass().getSimpleName());
        }
    }
}

You can get the lib via maven central:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.8.1</version>
</dependency>



回答3:


If you're using the Spring Framework, there is an utils class named ReflectionUtils

Here is a way to inject a value into a private field.

According to :

findField(Class<?> clazz, String name, Class<?> type)

and

setField(Field field, @Nullable Object target, @Nullable Object value)

You can write:

final Field field = ReflectionUtils.findField(Foo.class, "name", String.class)
ReflectionUtils.setField(field, targetObject, "theNewValue")

It is certainly not the shortest way to write this but it is shorter than the basic JDK tools to do this and I trusts people who are developing Spring so I am confident enough. Just be sure you actually really need reflection before doing this.

Plus if this is for a testing purpose, there is ReflectionTestUtils that provides you some methods too.

You'll find everything in the docs here

Hope it helps.




回答4:


what I would do is make this a helper method.

public static void changeField(Class cc, String field, String newValue) throws NoSuchFieldException, IllegalAccessException {
    Field f = cc.getDeclaredField(field);
    f.setAccessible(true);
    f.set(cc, newValue);
    f.setAccessible(false);
}

and call it like the following

changeField(cc, "field", "newValue");


来源:https://stackoverflow.com/questions/53744482/what-is-the-shortest-best-cleanest-way-to-set-a-private-field-via-reflection-i

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!