-
-
Save nsarvar/643fb2d9764e7bb778649dae152e63ca to your computer and use it in GitHub Desktop.
FieldUtils mutates and accesses fields using reflection.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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