Java Reflection Java
This tutorial shows different ways to set nest field values by using Java Reflection.
Examples
Example POJOs
package com.logicbig.example;
public class Person {
private Address address;
.............
}
package com.logicbig.example;
public class Address {
private AddressLine line1;
private City city;
.............
}
package com.logicbig.example;
public class AddressLine {
private String houseNumber;
private String street;
.............
}
package com.logicbig.example;
public class City {
private String cityName;
.............
}
Using java.lang.reflect.Field
package com.logicbig.example;
import java.lang.reflect.Field;
public class JavaFieldExample {
public static void main(String[] args) throws Exception {
Person p = new Person();
Address address = new Address();
address.setLine1(new AddressLine());
address.setCity(new City());
p.setAddress(address); //commenting this will also work
System.out.println("before: " + p);
setField(p, "address.line1.houseNumber", "4508");
setField(p, "address.line1.street", "Westfall Dr");
setField(p, "address.city.cityName", "Los Alamos");
System.out.println("after: " + p);
}
private static void setField(Object object, String fieldName, Object fieldValue)
throws Exception {
if (fieldName.contains(".")) {
int firstDotLocation = fieldName.indexOf('.');
String childFieldName = fieldName.substring(0, firstDotLocation);
Field field = object.getClass().getDeclaredField(childFieldName);
field.setAccessible(true);
Object childFieldInstance = field.get(object);
if (childFieldInstance == null) {
Class<?> type = field.getType();
//invoking no argument constructor
childFieldInstance = type.getConstructor().newInstance();
field.set(object, childFieldInstance);
}
field.setAccessible(false);
setField(childFieldInstance, fieldName.substring(firstDotLocation + 1), fieldValue);
} else {
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, fieldValue);
field.setAccessible(false);
}
}
}
before: Person{address=Address{line1=AddressLine{houseNumber='null', street='null'}, city=City{cityName='null'}}} after: Person{address=Address{line1=AddressLine{houseNumber='4508', street='Westfall Dr'}, city=City{cityName='Los Alamos'}}}
Invoking setter via java.lang.reflect.Method
package com.logicbig.example;
import java.lang.reflect.Method;
public class JavaSetterMethodExample {
public static void main(String[] args) throws Exception {
Person p = new Person();//must have getters/setters
Address address = new Address();
address.setLine1(new AddressLine());
address.setCity(new City());
p.setAddress(address); //commenting this will also work
System.out.println("before: " + p);
setFieldValue(p, "address.line1.houseNumber", "4508");
setFieldValue(p, "address.line1.street", "Westfall Dr");
setFieldValue(p, "address.city.cityName", "Los Alamos");
System.out.println("after: " + p);
}
private static void setFieldValue(Object object, String fieldName, Object fieldValue)
throws Exception {
if (fieldName.contains(".")) {
int firstDotLocation = fieldName.indexOf('.');
String childFieldName = fieldName.substring(0, firstDotLocation);
Method getter = object.getClass().getDeclaredMethod(fieldToGetterName(childFieldName));
Object childFieldInstance = getter.invoke(object);
if (childFieldInstance == null) {
Class<?> type = getter.getReturnType();
//invoking no argument constructor
childFieldInstance = type.getConstructor().newInstance();
Method setter = object.getClass().getDeclaredMethod(
fieldToSetterName(childFieldName), type);
setter.invoke(object, childFieldInstance);
}
setFieldValue(childFieldInstance, fieldName.substring(firstDotLocation + 1), fieldValue);
} else {
Method setter = object.getClass().getDeclaredMethod(fieldToSetterName(fieldName),
fieldValue.getClass());
setter.invoke(object, fieldValue);
}
}
private static String fieldToGetterName(String fieldName) {
return "get" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
}
private static String fieldToSetterName(String fieldName) {
return "set" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
}
}
before: Person{address=Address{line1=AddressLine{houseNumber='null', street='null'}, city=City{cityName='null'}}} after: Person{address=Address{line1=AddressLine{houseNumber='4508', street='Westfall Dr'}, city=City{cityName='Los Alamos'}}}
Using BeanInfo
package com.logicbig.example;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.util.Arrays;
public class JavaBeanInfoExample {
public static void main(String[] args) throws Exception {
Person p = new Person();//must have getters/setters
Address address = new Address();
address.setLine1(new AddressLine());
address.setCity(new City());
p.setAddress(address); //commenting this will also work
System.out.println("before: " + p);
setFieldValue(p, "address.line1.houseNumber", "4508");
setFieldValue(p, "address.line1.street", "Westfall Dr");
setFieldValue(p, "address.city.cityName", "Los Alamos");
System.out.println("after: " + p);
}
private static void setFieldValue(Object object, String fieldName, Object fieldValue)
throws Exception {
if (fieldName.contains(".")) {
int firstDotLocation = fieldName.indexOf('.');
String childFieldName = fieldName.substring(0, firstDotLocation);
PropertyDescriptor pd = findPropertyDescriptor(object.getClass(), childFieldName);
Object childFieldInstance = pd.getReadMethod().invoke(object);
if (childFieldInstance == null) {
Class<?> type = pd.getPropertyType();
childFieldInstance = type.getConstructor().newInstance();
pd.getWriteMethod().invoke(object, childFieldInstance);
}
setFieldValue(childFieldInstance, fieldName.substring(firstDotLocation + 1), fieldValue);
} else {
PropertyDescriptor pd = findPropertyDescriptor(object.getClass(), fieldName);
pd.getWriteMethod().invoke(object, fieldValue);
}
}
private static PropertyDescriptor findPropertyDescriptor(Class<?> c, String fieldName)
throws Exception {
BeanInfo beanInfo = Introspector.getBeanInfo(c);
return Arrays.stream(beanInfo.getPropertyDescriptors())
.filter(pd -> pd.getName().equals(fieldName))
.findAny()
.orElseThrow(() -> new IllegalArgumentException("field not found: " + fieldName));
}
}
before: Person{address=Address{line1=AddressLine{houseNumber='null', street='null'}, city=City{cityName='null'}}} after: Person{address=Address{line1=AddressLine{houseNumber='4508', street='Westfall Dr'}, city=City{cityName='Los Alamos'}}}
Using Apache Commons BeanUtils
pom.xml<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
package com.logicbig.example;
import org.apache.commons.beanutils.BeanUtils;
public class ApacheCommonBeanUtilsExample {
public static void main(String[] args) throws Exception {
Person p = new Person();//must have getters and setters
Address address = new Address();
address.setLine1(new AddressLine());
address.setCity(new City());
p.setAddress(address);
System.out.println("before: " + p);
BeanUtils.setProperty(p, "address.line1.houseNumber", "4508");
BeanUtils.setProperty(p, "address.line1.street", "Westfall Dr");
BeanUtils.setProperty(p, "address.city.cityName", "Los Alamos");
System.out.println("after: " + p);
}
}
before: Person{address=Address{line1=AddressLine{houseNumber='null', street='null'}, city=City{cityName='null'}}} after: Person{address=Address{line1=AddressLine{houseNumber='4508', street='Westfall Dr'}, city=City{cityName='Los Alamos'}}}
Using Spring beans
pom.xml<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
Direct Field Access
package com.logicbig.example;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.ConfigurablePropertyAccessor;
import org.springframework.beans.PropertyAccessorFactory;
public class SpringFieldAccessorExample {
public static void main(String[] args) {
Person p = new Person();
Address address = new Address();
address.setLine1(new AddressLine());
address.setCity(new City());
p.setAddress(address);
System.out.println("before: " + p);
ConfigurablePropertyAccessor propertyAccessor = PropertyAccessorFactory.forDirectFieldAccess(p);
propertyAccessor.setPropertyValue("address.line1.houseNumber", "4508");
propertyAccessor.setPropertyValue("address.line1.street", "Westfall Dr");
propertyAccessor.setPropertyValue("address.city.cityName", "Los Alamos");
System.out.println("after: " + p);
}
}
before: Person{address=Address{line1=AddressLine{houseNumber='null', street='null'}, city=City{cityName='null'}}} after: Person{address=Address{line1=AddressLine{houseNumber='4508', street='Westfall Dr'}, city=City{cityName='Los Alamos'}}}
Setter Access
package com.logicbig.example;
import org.springframework.beans.ConfigurablePropertyAccessor;
import org.springframework.beans.PropertyAccessorFactory;
public class SpringPropertyAccessorExample {
public static void main(String[] args) {
Person p = new Person();//must have getters/setters
Address address = new Address();
address.setLine1(new AddressLine());
address.setCity(new City());
p.setAddress(address);
System.out.println("before: " + p);
ConfigurablePropertyAccessor propertyAccessor = PropertyAccessorFactory.forBeanPropertyAccess(p);
propertyAccessor.setPropertyValue("address.line1.houseNumber", "4508");
propertyAccessor.setPropertyValue("address.line1.street", "Westfall Dr");
propertyAccessor.setPropertyValue("address.city.cityName", "Los Alamos");
System.out.println("after: " + p);
}
}
before: Person{address=Address{line1=AddressLine{houseNumber='null', street='null'}, city=City{cityName='null'}}} after: Person{address=Address{line1=AddressLine{houseNumber='4508', street='Westfall Dr'}, city=City{cityName='Los Alamos'}}}
Example ProjectDependencies and Technologies Used: - commons-beanutils 1.9.4: Apache Commons BeanUtils provides an easy-to-use but flexible wrapper around reflection and introspection.
- spring-beans 5.2.5.RELEASE: Spring Beans.
- JDK 8
- Maven 3.5.4
|
|