Skip to content

Instantly share code, notes, and snippets.

@nsarvar
Forked from jasper-vandemalle/FieldUtils.java
Created July 17, 2021 15:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nsarvar/643fb2d9764e7bb778649dae152e63ca to your computer and use it in GitHub Desktop.
Save nsarvar/643fb2d9764e7bb778649dae152e63ca to your computer and use it in GitHub Desktop.
FieldUtils mutates and accesses fields using reflection.
package be.vandemalle.jasper.util.reflection;
import java.lang.reflect.Field;
import org.apache.commons.lang.StringUtils;
public class FieldUtils {
/**
* Get the specified field on the class. If the field is not found on the class itself will recursively check
* the superclass.
* @param clazz the class definition containing the field
* @param fieldName the field to locate
* @return the field if found, otherwise an exception is thrown
*/
private static Field getField(Class < ? > clazz, String fieldName) {
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException nsf) {
if (clazz.getSuperclass() != null) {
return getField(clazz.getSuperclass(), fieldName);
}
throw new IllegalStateException("Could not locate field '" + fieldName + "' on class " + clazz);
}
}
/**
* Returns the value of a (nested) field on a bean.
* @param bean the object
* @param fieldName the field name, with "." separating nested properties
* @return the value
*/
public static Object get(Object bean, String fieldName) {
String[] nestedFields = StringUtils.split(fieldName, ".");
Class < ? > componentClass = bean.getClass();
Object value = bean;
try {
for (String nestedField : nestedFields) {
Field field = getField(componentClass, nestedField);
field.setAccessible(true);
value = field.get(value);
if (value != null) {
componentClass = value.getClass();
}
}
} catch (IllegalAccessException iae) {
throw new IllegalStateException(iae);
}
return value;
}
/**
* Sets the value of a (nested) field on a bean.
* @param bean the object
* @param fieldName the field name, with "." separating nested properties
* @param newValue the value to set
*/
public static void set(Object bean, String fieldName, Object newValue) {
String[] nestedFields = StringUtils.split(fieldName, ".");
Class < ? > componentClass = bean.getClass();
Object value = bean;
Field field = null;
try {
for (int i = 0; i < nestedFields.length; i++) {
String nestedField = nestedFields[i];
field = getField(componentClass, nestedField);
field.setAccessible(true);
if (i == nestedFields.length - 1) {
break;
}
value = field.get(value);
if (value != null) {
componentClass = value.getClass();
}
}
field.set(value, newValue);
} catch (IllegalAccessException iae) {
throw new IllegalStateException(iae);
}
}
}
package be.vandemalle.jasper.util.reflection;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class FieldUtilsTest {
private static final String EXPECTED = "expectedValue";
@Test
public void testSet() throws Exception {
Beta beta = new Beta();
FieldUtils.set(beta, "gamma", EXPECTED);
assertEquals(EXPECTED, beta.gamma);
}
@Test
public void testSetNavigatePath() throws Exception {
Alpha alpha = new Alpha(new Beta(EXPECTED));
FieldUtils.set(alpha, "beta.gamma", EXPECTED);
assertEquals(EXPECTED, alpha.beta.gamma);
}
@Test
public void testSetSuper() throws Exception {
Omega omega = new Omega(new Beta());
FieldUtils.set(omega, "beta", new Beta(EXPECTED));
assertEquals(EXPECTED, omega.beta.gamma);
}
@Test
public void testSetSuperNavigatePath() throws Exception {
Omega omega = new Omega(new Beta());
FieldUtils.set(omega, "beta.gamma", EXPECTED);
assertEquals(EXPECTED, omega.beta.gamma);
}
@Test
public void testGet() throws Exception {
Alpha alpha = new Alpha(new Beta(EXPECTED));
Object actual = (Object) FieldUtils.get(alpha, "beta");
actual = (Object) FieldUtils.get(actual, "gamma");
assertEquals(EXPECTED, actual);
}
@Test
public void testGetNavigatePath() throws Exception {
Alpha alpha = new Alpha(new Beta(EXPECTED));
Object actual = (Object) FieldUtils.get(alpha, "beta.gamma");
assertEquals(EXPECTED, actual);
}
@Test
public void testGetSuper() throws Exception {
Omega omega = new Omega(new Beta(EXPECTED));
Object actual = (Object) FieldUtils.get(omega, "beta");
actual = (Object) FieldUtils.get(actual, "gamma");
assertEquals(EXPECTED, actual);
}
@Test
public void testGetSuperNavigatePath() throws Exception {
Omega omega = new Omega(new Beta(EXPECTED));
Object actual = (Object) FieldUtils.get(omega, "beta.gamma");
assertEquals(EXPECTED, actual);
}
// used to test basic field access
private class Alpha {
protected Beta beta;
public Alpha(Beta beta) {
this.beta = beta;
}
}
// used to test the nested property
private class Beta {
private String gamma;
public Beta(String gamma) {
this.gamma = gamma;
}
public Beta() {
}
}
// used to test the super
private class Omega extends Alpha {
public Omega(Beta beta) {
super(beta);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment