问题
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