1

私は設計して開発している新しいSpringアプリケーションのために、いくつかの技術的理由からMongoDBを永続化レイヤーとして使用しています。これは、私がバリューオブジェクトを含むいくつかのDDD原則を実装しようとしている最初のプロジェクトです。私は実際には単に文字列であるValueObjectを保存する最良の方法を見つけることを試みています。私のSpring REST Controllerは、Lombokの@Valueを使用して、RestController側のValueObjectに値を解析します。しかし、値を保存すると、構造化された方法でMongoDB側に保存されます。例えばSpringとMongoDB:より平らな方法で値オブジェクトを保存する

マイVO:

@Value 
public class PersonKey { 
    private String value; 
} 

文書私はMongoDBの中に保存されます:MongoDBの中に保存されますどのような

@Document 
public class PersonDocument { 
    private PersonKey personKey; 
    private Name name; 
    ... 
} 

{.. "personKey": {"value": "faeeaf2"} ...} 

私が実際に何をwアリ:最小限の追加定型コード付きもちろん

{.. "personKey": "faeeaf2" ..} 

.. :-)

+0

'PHP'では、' insert'、 'update'、' find' mongodbの各動作のたびに呼び出されるコンバータクラスを作成しました。そのコンバータは再帰的であり、リフレクションを使用します。 –

+0

これはPHPですが、動的言語です。私はそれが静的言語としてJavaのために異なっていると思います:-) – Kristof

+0

それは私が答えを提供していない理由です。多分それがあなたを助けます。 –

答えて

1

あなたの唯一のオプションは、変換後DBObjectを変更するonAfterConvert方法でAbstractMongoEventListenerを使用することであるようです。 Unforunatelyでは、ドキュメント内の単一フィールドの変換を簡単に変更することはできません。カスタムコンバータは、単一のフィールドではなく、ドキュメント全体を保存するときに使用されます。また、getterメソッドを使用してフィールドアクセスを置き換えることもできません(「オブジェクトのフィールドは、ドキュメント内のフィールドとの間の変換に使用されます。公開JavaBeanのプロパティは使用されません。」http://docs.spring.io/spring-data/data-mongo/docs/1.4.2.RELEASE/reference/html/mapping-chapter.html)。だから、あなたが望むものを達成する唯一の方法は、mongodbイベントを通してです。ただし、イベントハンドラでリフレクションを使用して、フィールドに@Value注釈が付いているかどうかを確認することができます。したがって、より一般的な方法でフィールドを変換することができます。 @Value注釈が存在する場合は、DBObjectに値属性を置き換えます。

これを達成するには、AbstractMongoEventListenerを拡張する必要があります。あなたはonBeforeSaveイベントハンドラで、ここでの例を見ることができます:

https://github.com/ttrelle/spring-data-examples/blob/master/springdata-mongodb/src/main/java/mongodb/OrderBeforeSaveListener.java

更新: @maartinusが@Valueオブジェクトが動作しませんのために、それはでは使用できませんので、検索するためにリフレクションを使用して、コメントに気づいたようランタイム(保持はSOURCEに設定されています)。したがって、オブジェクトの値を返す単一のメソッドvalue()を使用して、独自の注釈やインターフェース(例:ValueObject)を導入する必要があります。

+0

'@lombok.Value'のチェックは、' @Retention(RetentionPolicy.SOURCE) 'として動作しません。 – maaartinus

+1

@maaartinusそうですね、答えを更新します。 –

0

私はまったく同じ問題に取り組んでいます。そして、実際にはCustomConvertersでこれを行うことができます。あなたとまったく同じではないかもしれませんが、非常に似たような方法です。私が克服できなかった唯一の問題は、実行時に動的にコンバーターを選択できないことです。これは、行番号182CustomConversions#registerConversionの実装によるものです。

この例は、私が現在取り組んでいることを示しています。 GenericConverterを使用していますが、通常のConvertersにフォールバックすることもできます。この例では、フィールド注釈はチェックされません。むしろ、それはSingleValueと呼ばれるインターフェイスを使用します。単一の値を表すすべてのバリューオブジェクトがこのインターフェイスを実装します。したがって、フィールドの注釈の必要はありません。

@Configuration 
@Slf4j 
public class MongoDbConfiguration { 

    @Bean 
    @Primary 
    public CustomConversions mongoCustomConversions() throws Exception { 
     final List converterList = new ArrayList<>(); 
     converterList.add(new SingleValueConverter()); 
     return new CustomConversions(converterList); 
    } 

    private static class SingleValueConverter implements GenericConverter { 

     @Override 
     public Set<ConvertiblePair> getConvertibleTypes() { 
      return new HashSet<>(Arrays.asList(new ConvertiblePair[]{ 
        new ConvertiblePair(UUIDEntityReference.class, String.class), 
        new ConvertiblePair(String.class, FundingProcessId.class) 
        // put here all of your type conversions (two way!) 
      })); 
     } 

     @Override 
     public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { 
      try { 
       // first check if the instance of this type is an instance of our 'SingleValue' interface 
       if (source instanceof SingleValue) { 
        return ((SingleValue) source).getValue(); 
       } 

       final Class<?> objectType = targetType.getType(); 
       final Constructor<?> constructor = objectType.getConstructor(sourceType.getType()); 
       return constructor.newInstance(source); 
      } catch (ReflectiveOperationException e) { 
       throw new RuntimeException("Could not convert unexpected type " + 
         sourceType.getObjectType().getName() + " to " + targetType.getObjectType().getName(), e); 
      } 
     } 
    } 
} 

これは私が見つけることができる最もエレガントな方法です。すべてのタイプの登録を自動化する方法を探しています。これは、アノテーションとクラスパスのスキャンで可能です。この実装は、メソッドのgetValue

  • であなたがインターフェイスSingleValueを持っているもの

    1. のカップルを想定していることを

      注あなたの「単一値」値の各クラスは、単一の引数を持つコンストラクタを持っています内部型表現(例えば、UUIDの文字列)

    編集:私は間違ったサンプルコードを投稿しました。更新されました

  • 関連する問題