Возможно ли автоматическое создание экземпляра вложенного свойства с помощью Commons Bean Utils? - PullRequest
6 голосов
/ 02 февраля 2011

Я использую PropertyUtils.setProperty (объект, имя, значение) метод Apache Commons Bean Utils:

Предоставление следующих классов:

public class A {
    B b;
}

public class B {
    C c;
}

public class C {
}

Иthis:

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

Если я пытаюсь это сделать, я получаю: org.apache.commons.beanutils.NestedNullException: нулевое значение свойства для 'bc' в классе бобов 'класс A '

Можно ли сообщить PropertyUtils, что если вложенное свойство имеет нулевое значение, попытайтесь создать его экземпляр (конструктор по умолчанию), прежде чем пытаться углубиться?

Любой другой подход?

Спасибовы

Ответы [ 6 ]

9 голосов
/ 03 февраля 2011

Я решил это следующим образом:

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);
    }
}
5 голосов
/ 28 декабря 2016

Я знаю, что вопрос о apache commons PropertyUtils.setProperty, но в Spring Expression Language "SpEL " есть очень похожая функциональность, которая делает именно то, что вы хотите.Более того, он также работает со списками и массивами.Ссылка на документ выше для весны 4.x, но код ниже работает для меня весной 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));
2 голосов
/ 25 февраля 2011

Небольшая коррекция:

String fn = fieldNames[i];
if (i != 0) {
        nestedProperty.append(".");
}
nestedProperty.append(fn);
Object value = PropertyUtils.getProperty(obj, nestedProperty.toString());
0 голосов
/ 16 октября 2015

Я выбрал очень простой подход - создать экземпляр каждого из объектов по умолчанию:

public class A {
    B b = new B();
}

public class B {
    C c = new C();
}

public class C {
}

Не идеально, но он работал для моей ситуации и не требовал сложных исправлений.

0 голосов
/ 28 июля 2015

Я использовал только отражение без библиотеки Apache для достижения этой цели.Предполагается, что все объекты, подлежащие обходу, являются POJO, и конструкция по умолчанию общедоступна.Таким образом, нет необходимости создавать опорный путь для каждого цикла.

public Object getOrCreateEmbeddedObject(Object inputObj,String[] fieldNames) throws Exception {

    Object cursor = inputObj;

    //Loop until second last index
    for (int i = 0; i < fieldNames.length - 1; i++){
        Field ff = getClassFieldFrom(cursor,fieldNames[i]);
        Object child = ff.get(cursor);
        if(null == child) {
            Class<?> cls=ff.getType();
            child = cls.newInstance();
            ff.set(cursor, child);
        }
        cursor = child;
    }

    return cursor;
}

private Field getClassFieldFrom(Object object, String fieldStr)
            throws NoSuchFieldException {
        java.lang.reflect.Field ff = object.getClass().getDeclaredField(fieldStr);
        ff.setAccessible(true);
        return ff;
}

Если у вас есть предложения по моему решению, пожалуйста, дайте мне знать.

0 голосов
/ 02 февраля 2011

После некоторого исследования, короткий ответ на вопрос «Возможно ли ...»: Нет .

...