The core of a Java Bean Factory explained
Olivier Van de Velde
Technical Authority and Scrum Master EBP Web Apps at Siemens Mobility
A bean factory converts a generic object like a map, a JSON object, an XML object to a specific bean object. For example for a JSON bean factory the createBean function looks like this :
static public Object createBean(Class<?> beanClass, JSONObject jsonObject) throws JSONException {
This function creates a bean value from a bean class and a JSON object. It loops over all properties of the bean class :
BeanInfo beanInfo = Introspector.getBeanInfo(beanClass);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
And for each bean property searches for a JSONObject property with the same name :
while (jsonPropertyNamesIterator.hasNext()) {
String jsonPropertyName = jsonPropertyNamesIterator.next();
if (!propertyName.equals(jsonPropertyName)) {
continue;
}
When found the value of the property is retrieved from the generic object and stored in the bean property:
// get value from jsonObject
Object value = getBeanPropertyValueFromJSONObject(beanClass, jsonObject,
propertyName);
// set value in the bean
setBeanPropertyValue(bean, propertyDescriptor, value);
The getBeanPropertyValueFromJSONObject creates a bean property value from :
- a beanClass
- a JSON object
- the descriptor of a property to retrieve
public static Object getBeanPropertyValueFromJSONObject(Class<?> beanClass, JSONObject jsonObject, String propertyName)
?throws JSONException, IntrospectionException {
It first retrieves the generic property value from the JSON object :
Object jsonObjectPropertyValue = jsonObject.get(propertyName);
Then gets the class of the property in the bean class :
Class<?> propertyClass =
ReflectionUtil.getPropertyClass(propertyName, beanClass);
Then returns the bean value from the JSON object property value with the function :
return getBeanValueFromJSONObjectValue(propertyClass, jsonObjectPropertyValue);
The getBeanValueFromJSONObjectValue returns a bean value from 2 parameters :
- a bean class
- a JSON object
private static <T> Object getBeanValueFromJSONObjectValue( ?Class<?> beanValueClass, Object jsonObjectValue)
?throws NoSuchFieldException, JSONException {
First the type of the jsonObjectValue input parameter is checked:
- if it symbolizes a null value, a bean value of null is returned
- if it is a JSONObject, a bean by calling recursively the createBean method (see above)
- if is a JSONArray a typed array or typed container is created depending on the bean class value. When it is an array it is interesting to see how generics coma into play :
JSONArray jsonArray = (JSONArray) jsonObjectValue;
int length = jsonArray.length();
ArrayList<Class<?>> types = jsonArray.getTypes();
ArrayList<Object> items = jsonArray.getItems();
?if (beanValueClass.isArray()) {
Class<?> componentType = beanValueClass.getComponentType();
T[] typedArray = (T[]) Array.newInstance(componentType, length);
for (int i = 0; i < types.size(); i++) {
Class<?> type = types.get(i);
Object jsonObjectItemValue = items.get(i);
Object beanItemValue = getBeanValueFromJSONObjectValue(type,
jsonObjectItemValue);
typedArray[i] = (T) beanItemValue;
}
beanValue = typedArray;
}
The getBeanValueFromJSONObjectValue function is recursively called for each item of the JSONArray. Each value returned is casted with the generic parameter T which corresponds to the component type of the array:
Class<?> componentType = beanValueClass.getComponentType();
T[] typedArray = (T[]) Array.newInstance(componentType, length);
...
typedArray[i] = (T) beanItemValue;