Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible automatically instantiation of a nested Property with Commons Bean Utils?

I'm using PropertyUtils.setProperty(object, name, value) method of Apache Commons Bean Utils:

Giving these classes:

public class A {
    B b;
}

public class B {
    C c;
}

public class C {
}

And this:

A a = new A();
C c = new C();
PropertyUtils.setProperty(a, "b.c", c); //exception

If I try that I get: org.apache.commons.beanutils.NestedNullException: Null property value for 'b.c' on bean class 'class A'

Is it possible to tell PropertyUtils that if a nested property has a null value try to instantiate it (default constructor) before trying to go deeper?

Any other approach?

Thank you

like image 634
Alfredo Osorio Avatar asked Feb 02 '11 17:02

Alfredo Osorio


People also ask

What is commons BeanUtils used for?

Commons BeanUtils is a collection of utilities that makes working with beans and bean properties much easier. This project contains utilities that allow one to retrieve a bean property by name, sort beans by a property, translate beans to maps, and more.

How does BeanUtils copyProperties work?

BeanUtils class provides a copyProperties method that copies the properties of source object to target object where the property name is same in both objects. Remember this will copy the properties with the same name only.


3 Answers

I solved it by doing this:

private void instantiateNestedProperties(Object obj, String fieldName) {
    try {
        String[] fieldNames = fieldName.split("\\.");
        if (fieldNames.length > 1) {
            StringBuffer nestedProperty = new StringBuffer();
            for (int i = 0; i < fieldNames.length - 1; i++) {
                String fn = fieldNames[i];
                if (i != 0) {
                    nestedProperty.append(".");
                }
                nestedProperty.append(fn);

                Object value = PropertyUtils.getProperty(obj, nestedProperty.toString());

                if (value == null) {
                    PropertyDescriptor propertyDescriptor = PropertyUtils.getPropertyDescriptor(obj, nestedProperty.toString());
                    Class<?> propertyType = propertyDescriptor.getPropertyType();
                    Object newInstance = propertyType.newInstance();
                    PropertyUtils.setProperty(obj, nestedProperty.toString(), newInstance);
                }
            }
        }
    } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
    } catch (InvocationTargetException e) {
        throw new RuntimeException(e);
    } catch (NoSuchMethodException e) {
        throw new RuntimeException(e);
    } catch (InstantiationException e) {
        throw new RuntimeException(e);
    }
}
like image 103
Alfredo Osorio Avatar answered Oct 18 '22 03:10

Alfredo Osorio


I know the question is about apache commons PropertyUtils.setProperty but there is very similar functionality available in Spring Expression Language "SpEL" which does exactly what you want. Better still it deals with lists and arrays too. The doc link above is for spring 4.x but the code below works for me in spring 3.2.9.

    StockOrder stockOrder = new StockOrder(); // Your root class here

    SpelParserConfiguration config = new SpelParserConfiguration(true,true);   // auto create objects if null
    ExpressionParser parser = new SpelExpressionParser(config);
    StandardEvaluationContext modelContext = new StandardEvaluationContext(stockOrder);

    parser.parseExpression("techId").setValue(modelContext, "XXXYYY1");
    parser.parseExpression("orderLines[0].partNumber").setValue(modelContext, "65498");
    parser.parseExpression("orderLines[0].inventories[0].serialNumber").setValue(modelContext, "54686513216");

    System.out.println(ReflectionToStringBuilder.toString(stockOrder));
like image 45
Noctiluque Avatar answered Oct 18 '22 03:10

Noctiluque


A little correction:

String fn = fieldNames[i];
if (i != 0) {
        nestedProperty.append(".");
}
nestedProperty.append(fn);
Object value = PropertyUtils.getProperty(obj, nestedProperty.toString());
like image 2
pfuy Avatar answered Oct 18 '22 02:10

pfuy