5

I'm trying to persist the following object with spring-data-mongodb version 1.1.1.RELEASE:

@Document
public static class TestObject {

    private final int m_property;

    @PersistenceConstructor
    public TestObject(int a_property) {
        m_property = a_property;
    }

    public int property() {
        return m_property;
    }

}

I get a MappingException when I try to read the object back from the database (see full stacktrace below)

The naming convention my group uses requires argument variable names to be prefaced by a_ and instance variable names to be prefaced by m_. It seems like spring-data-mongodb is making the assumption that the constructor argument variable names must match the object instance variable names.

  • Why doesn't spring-data-mongodb use the constructor argument to instance variable mapping that I define within the constructor?
  • Is there another way to define this mapping such that spring-data-mongodb will properly construct my object, or is my only option to break the naming convention?

.

Exception in thread "main" org.springframework.data.mapping.model.MappingException: No property a_property found on entity class com.recorder.TestRecorder$TestObject to bind constructor parameter to!
    at org.springframework.data.mapping.model.PersistentEntityParameterValueProvider.getParameterValue(PersistentEntityParameterValueProvider.java:90)
    at org.springframework.data.convert.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:70)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:229)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:209)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:173)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:169)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:72)
    at org.springframework.data.mongodb.core.MongoTemplate$ReadDbObjectCallback.doWith(MongoTemplate.java:1820)
    at org.springframework.data.mongodb.core.MongoTemplate.executeFindMultiInternal(MongoTemplate.java:1542)
    at org.springframework.data.mongodb.core.MongoTemplate.findAll(MongoTemplate.java:1064)
    at com.recorder.TestRecorder.main(TestRecorder.java:43)
4

2 に答える 2

17

tl;dr

ドキュメントのどのフィールドを取得するかを見つけるために、フィールド名と一致するようにコンストラクター引数名に依存する必要があります。これをカスタマイズしたい場合@Value("#root.field_name")は、コンストラクター引数で使用します。

長い話

引数を持つコンストラクターを使用して、Spring Data がこのコンストラクターを使用して特定のクラスをインスタンス化できるようにする場合、呼び出し時にパラメーターをコンストラクターに渡す必要があります。どのドキュメント フィールドを渡す必要があるかを調べるには、一致するプロパティを調べて、潜在的なフィールド名のカスタマイズを調べる必要があります。次の例を参照してください。

@Document
class MyEntity {

  @Field("foo")
  private String myField;

  public MyEntity(String myField) {
    this.myField = myField;
  }
}

この場合、フィールドfooをコンストラクターにパイプする必要があり、何らかの方法でプロパティへの参照を取得できなければ、これを知る方法はありません。コンストラクターのパラメーター名が異なる場合、どのフィールド値を実際に引数として使用する必要があるかを確実に確認するにはどうすればよいでしょうか? 質問で示した例は、ドキュメントにフィールドが含まれており、より明示的な構成を追加する以外に、実際にそれを挿入したいことを確認する方法がまったくないため、そのままでは機能しません。m_property

この動作をカスタマイズするには、Spring の@Valueアノテーションを使用してカスタム ドキュメント フィールドをコンストラクターに挿入します。ドキュメント自体は、#root変数を介して利用できます。したがって、上記のサンプルを次のように簡単に変更できます。

@Document
class MyEntity {

  @Field("foo")
  private String myField;

  public MyEntity(@Value("#root.foo") String somethingDifferent) {
    this.myField = somethingDifferent;
  }
}

カスタム フィールド名をプロパティに追加し、プロパティの命名規則をデータベースに公開したくないことを強くお勧めします。使用法 pf@Valueリファレンス ドキュメントに簡単に記載されていますが、ドキュメントを改善してこれをより明確にするためにチケットを作成しました。

于 2012-12-12T07:23:24.723 に答える
0

いくつかのカスタムコンバーターを使用できます(そして削除し@PersistenceConstructorます):

// DB => Java
package com.recorder.converters;

public class TestObjectReadConverter implements Converter<DBObject, TestObject> 
{
   public TestObject convert(final DBObject source) {
       return new TestObject((Integer) source.get("m_property"));
   }
}

// JAVA => DB
package com.recorder.converters;

public class TestObjectWriteConverter implements Converter<TestObject, DBObject> 
{
    public DBObject convert(final TestObject source) {
        return new BasicDBObjectBuilder("m_property", source.property()).get();
    }
}

それらを宣言することを忘れないでください(xml config):

<mongo:mapping-converter base-package="com.recorder">
    <mongo:custom-converters>
        <mongo:converter>
             <bean class="com.recorder.converters.TestObjectReadConverter" />
        </mongo:converter>
        <mongo:converter>
             <bean class="com.recorder.converters.TestObjectWriteConverter"/>
        </mongo:converter>
    </mongo:custom-converters>
</mongo:mapping-converter>

このリファレンスを参照してください

補足:これは回避策です。命名規則は、回避する必要があるほど厳密なものではないと思います。おそらく、あなたのグループがそれらの命名規則を「再考」する時が来たのでしょう(その場合は生産性のために)。

于 2012-12-12T03:44:10.323 に答える