web-dev-qa-db-ja.com

Spring data MongoDb:MappingMongoConverter remove _class

デフォルトMappingMongoConverterは、データベース内の各オブジェクトにカスタムタイプキー( "_class")を追加します。したがって、Personを作成すると、次のようになります。

package my.dto;
public class Person {
    String name;
    public Person(String name) {
        this.name = name; 
    }
}

それをdbに保存します。

MongoOperations ops = new MongoTemplate(new Mongo(), "users");
ops.insert(new Person("Joe"));

mongoの結果のオブジェクトは次のようになります。

{ "_id" : ObjectId("4e2ca049744e664eba9d1e11"), "_class" : "my.dto.Person", "name" : "Joe" }

質問:

  1. Personクラスを別の名前空間に移動するとどのような影響がありますか?

  2. 「_class」キーでオブジェクトを汚染しないことは可能ですか? Personクラス専用の独自のコンバーターを作成せずに?

32
Yuriy Nemtsov

だからここに話があります:デフォルトで型を何らかのクラスのヒントとして実際にインスタンス化するクラスを追加します。パイプを使用してドキュメントをMongoTemplateに読み込むために型をパイプする必要があるので、とにかく2つの可能なオプションがあります。

  1. 実際に保存されているタイプを割り当てることができるタイプを渡します。その場合、保存されたタイプを考慮して、オブジェクトの作成にそれを使用します。ここでの古典的な例は、ポリモーフィッククエリの実行です。抽象クラスContactPersonがあるとします。次に、Contactsをクエリすると、インスタンス化するタイプを本質的に決定する必要があります。
  2. 一方、完全に異なる型を渡した場合、実際にドキュメントに格納されている型ではなく、その型にマーシャリングされます。これは、タイプを移動するとどうなるかという問題をカバーします。

タイプ情報を実際のタイプに変換するプラグイン可能なタイプマッピング戦略をカバーする this ticket の監視に興味があるかもしれません。長い修飾クラス名を数文字のハッシュにしたい場合があるので、これは単にスペース節約の目的に役立ちます。また、別のデータストアクライアントによって生成された完全に任意のタイプキーを見つけ、それらをJavaタイプにバインドすることもある。

27
Oliver Drotbohm

これが私の注釈です。うまくいきます。

@Configuration
public class AppMongoConfig {

    public @Bean
    MongoDbFactory mongoDbFactory() throws Exception {
        return new SimpleMongoDbFactory(new Mongo(), "databasename");
    }

    public @Bean
    MongoTemplate mongoTemplate() throws Exception {

        //remove _class
        MappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext());
        converter.setTypeMapper(new DefaultMongoTypeMapper(null));

        MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory(), converter);

        return mongoTemplate;

    }

}
17
mkyong
<mongo:mongo Host="hostname" port="27017">
<mongo:options
...options...
</mongo:mongo>
<mongo:db-factory dbname="databasename" username="user" password="pass"                     mongo-ref="mongo"/>
<bean id="mongoTypeMapper"     class="org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper">
<constructor-arg name="typeKey"><null/></constructor-arg>
</bean>
<bean id="mongoMappingContext"      class="org.springframework.data.mongodb.core.mapping.MongoMappingContext" />
<bean id="mongoConverter"     class="org.springframework.data.mongodb.core.convert.MappingMongoConverter">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
<constructor-arg name="mappingContext" ref="mongoMappingContext" />
<property name="typeMapper" ref="mongoTypeMapper"></property>
</bean>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
<constructor-arg name="mongoConverter" ref="mongoConverter" />
<property name="writeResultChecking" value="EXCEPTION" /> 
</bean>
5
AKKI

__class_属性をデフォルトで無効にしたいが、指定されたクラスのポリモーフィズムを維持したい場合は、次のように構成することにより、明示的に__class_(オプション)フィールドのタイプを定義できます。

_@Bean
public MongoTemplate mongoTemplate() throws Exception {
    Map<Class<?>, String> typeMapperMap = new HashMap<>();
    typeMapperMap.put(com.acme.domain.SomeDocument.class, "role");

    TypeInformationMapper typeMapper1 = new ConfigurableTypeInformationMapper(typeMapperMap);

    MongoTypeMapper typeMapper = new DefaultMongoTypeMapper(DefaultMongoTypeMapper.DEFAULT_TYPE_KEY, Arrays.asList(typeMapper1));
    MappingMongoConverter converter = new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext());
    converter.setTypeMapper(typeMapper);

    MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory(), converter);
    return mongoTemplate;
}
_

これにより、指定されたエンティティのみの__class_フィールド(またはコンストラクタで名前を付けたいもの)が保持されます。

たとえば注釈に基づいて、独自のTypeInformationMapperを記述することもできます。 @DocumentType("aliasName")でドキュメントに注釈を付けると、クラスのエイリアスを保持することでポリモーフィズムを維持できます。

ブログで簡単に説明しました ですが、簡単なコードの一部を次に示します: https://Gist.github.com/athlan/6497c74cc515131e1336

5
Athlan

Mkyongの答えはまだ機能しますが、いくつかのビットが廃止されており、クリーンアップの危機に瀕している可能性があるため、私のバージョンのソリューションを追加したいと思います。

例:MappingMongoConverter(mongoDbFactory(), new MongoMappingContext())new MappingMongoConverter(dbRefResolver, new MongoMappingContext());を優先して非推奨になり、SimpleMongoDbFactory(new Mongo(), "databasename");new SimpleMongoDbFactory(new MongoClient(), database);を優先します。

だから、非推奨の警告なしの私の最終的な作業の答えは:

@Configuration
public class SpringMongoConfig {

    @Value("${spring.data.mongodb.database}")
    private String database;

    @Autowired
    private MongoDbFactory mongoDbFactory;

    public @Bean MongoDbFactory mongoDBFactory() throws Exception {
        return new SimpleMongoDbFactory(new MongoClient(), database);
    }

    public @Bean MongoTemplate mongoTemplate() throws Exception {

        DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory);

        // Remove _class
        MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, new MongoMappingContext());
        converter.setTypeMapper(new DefaultMongoTypeMapper(null));

        return new MongoTemplate(mongoDBFactory(), converter);

    }

}

これが非推奨の警告なしでクリーンなクラスを望んでいる人々を助けることを願っています。

4
harshavmb

これは私の1行のソリューションです。

@Bean 
public MongoTemplate mongoTemplateFraud() throws UnknownHostException {

  MongoTemplate mongoTemplate = new MongoTemplate(getMongoClient(), dbName);
  ((MappingMongoConverter)mongoTemplate.getConverter()).setTypeMapper(new DefaultMongoTypeMapper(null));//removes _class
  return mongoTemplate;
}
2
kozla13

私はこの問題に長い間苦しんでいました。私は mkyong からのアプローチに従いましたが、LocalDate属性(Java 8からのJSR310クラス))を導入すると、次の例外が発生しました:

org.springframework.core.convert.ConverterNotFoundException:
No converter found capable of converting from type [Java.time.LocalDate] to type [Java.util.Date]

対応するコンバータorg.springframework.format.datetime.standard.DateTimeConvertersはSpring 4.1の一部であり、Spring Data MongoDB 1.7で参照されています。新しいバージョンを使用しても、コンバーターはジャンプしませんでした。

解決策は、既存のMappingMongoConverterを使用し、新しいDefaultMongoTypeMapperのみを提供することでした(mkyongからのコードはコメントの下にあります):

@Configuration
@EnableMongoRepositories
class BatchInfrastructureConfig extends AbstractMongoConfiguration
{
    @Override
    protected String getDatabaseName() {
        return "yourdb"
    }

    @Override
    Mongo mongo() throws Exception {
        new Mongo()
    }

    @Bean MongoTemplate mongoTemplate()
    {
        // overwrite type mapper to get rid of the _class column
//      get the converter from the base class instead of creating it
//      def converter = new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext())
        def converter = mappingMongoConverter()
        converter.typeMapper = new DefaultMongoTypeMapper(null)

        // create & return template
        new MongoTemplate(mongoDbFactory(), converter)
    }

要約する:

  • 拡張AbstractMongoConfiguration
  • EnableMongoRepositoriesで注釈を付ける
  • mongoTemplateで、ベースクラスからコンバーターを取得します。これにより、型変換クラスが登録されます。
1
ChrLipp
@Configuration
public class MongoConfig {

    @Value("${spring.data.mongodb.database}")
    private String database;

    @Value("${spring.data.mongodb.Host}")
    private String Host;

    public @Bean MongoDbFactory mongoDbFactory() throws Exception {
        return new SimpleMongoDbFactory(new MongoClient(Host), database);
    }

    public @Bean MongoTemplate mongoTemplate() throws Exception {

        MappingMongoConverter converter = new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory()),
                new MongoMappingContext());
        converter.setTypeMapper(new DefaultMongoTypeMapper(null));

        MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory(), converter);

        return mongoTemplate;

    }

}
1

タイプマッパーを変更するだけで、@ TypeAliasアノテーションをクラス定義に追加する必要があります。

0
Matt