Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 471
Andreas Hauschild Avatar asked Dec 12 '18 13:12

Andreas Hauschild


3 Answers

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");
like image 92
Davide Lorenzo MARINO Avatar answered Oct 19 '22 19:10

Davide Lorenzo MARINO


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>
like image 32
Andreas Hauschild Avatar answered Oct 19 '22 18:10

Andreas Hauschild


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.

like image 20
MadJlzz Avatar answered Oct 19 '22 17:10

MadJlzz