6

Apache Commons Bean UtilsのPropertyUtils.setProperty(object、name、value)メソッドを使用しています。

これらのクラスを提供する:

public class A {
    B b;
}

public class B {
    C c;
}

public class C {
}

この:

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

これを試してみると、次のようになります 。org.apache.commons.beanutils.NestedNullException:Beanクラス「クラスA」の「bc」のプロパティ値がNull

ネストされたプロパティにnull値がある場合、さらに深く進む前に、それをインスタンス化しようとする(デフォルトのコンストラクター)ことをPropertyUtilsに伝えることは可能ですか?

他のアプローチはありますか?

ありがとうございました

4

7 に答える 7

9

私はこれを行うことによってそれを解決しました:

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);
    }
}
于 2011-02-02T23:16:04.500 に答える
8

質問はapachecommonsPropertyUtils.setPropertyに関するものですが、 Spring式言語「SpEL 」で利用できる非常によく似た機能があり、 まさにあなたが望むことを実行します。さらに良いことに、リストと配列も扱います。上記のドキュメントリンクはSpring4.x用ですが、以下のコードはSpring3.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));
于 2016-12-27T23:24:45.867 に答える
2

少し修正:

String fn = fieldNames[i];
if (i != 0) {
        nestedProperty.append(".");
}
nestedProperty.append(fn);
Object value = PropertyUtils.getProperty(obj, nestedProperty.toString());
于 2011-02-25T10:06:18.757 に答える
0

これを実現するために、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;
}

私の解決策について何か提案があれば、私に知らせてください。

于 2015-07-28T02:06:43.967 に答える
0

デフォルトで各オブジェクトをインスタンス化するという非常に基本的なアプローチを採用しました。

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

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

public class C {
}

理想的ではありませんが、私の状況ではうまくいき、複雑な修正は必要ありませんでした。

于 2015-10-16T13:54:42.567 に答える
0

IMHO、最善の解決策は、commons- beanutilsを取り除き、SpringFrameworkorg.springframework.beans.PropertyAccessorFactoryを使用することです。

BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(targetObject);
wrapper.setAutoGrowNestedPaths(true);

動作の詳細については詳しく説明しませんが、確認したい場合は、上のリンクを参照してください。このAPIは非常に直感的ですが、SpringFrameworkCoreを構成する必要があります。クラスパスなので、この機能のためだけにSpringを追加することはお勧めしません。

ただし

味方としてcommons-beanutilsしかない場合、次のコードスニペットは、値を設定するときにネストされたパスを拡張するのに役立つ可能性があります。したがって、パスプロパティに沿ったnullオブジェクトについて心配する必要はありません。

この例では、JPAタプルクエリを使用して、対応する値を設定する特定のプロパティパスを持つカスタムオブジェクトを作成しました。

import java.util.ArrayList;
import java.util.List;

import javax.persistence.Tuple;
import javax.persistence.TupleElement;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.beanutils.expression.DefaultResolver;
public class TupleToObject<T> {


    public List<T> transformResult(List<Tuple> result, Class<T> targetClass) {
        try {
            List<T> objects = new ArrayList<>();
            for (Tuple tuple : result) {
                T target = targetClass.newInstance();

                List<TupleElement<?>> elements = tuple.getElements();
                for (TupleElement<?> tupleElement : elements) {
                    String alias = tupleElement.getAlias();
                    Object value = tuple.get(alias);

                    if (value != null) {
                        instantiateObject(target, alias);
                        PropertyUtils.setNestedProperty(target, alias, value);
                    }

                }
                objects.add(target);
            }
            return objects;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    private void instantiateObject(T target, String propertyPath) throws Exception {
        DefaultResolver resolver = new DefaultResolver();
        Object currentTarget = target;
        while (resolver.hasNested(propertyPath)) {
            final String property = resolver.next(propertyPath);
            Object value = PropertyUtils.getSimpleProperty(currentTarget, property);
            if (value == null) {
                Class<?> propertyType = PropertyUtils.getPropertyType(currentTarget, property);
                value = propertyType.newInstance();
                PropertyUtils.setSimpleProperty(currentTarget, property, value);
            }
            currentTarget = value;

            propertyPath = resolver.remove(propertyPath);
        }
    }
}

このコードはcommons-beanutils-1.9.3.jarを使用しています

于 2020-11-23T20:38:16.203 に答える
-1

いくつかの調査を行った後、「それは可能ですか...」という質問に対する簡単な答えは「いいえ」です。

于 2011-02-02T18:31:30.990 に答える