春のデータ MongoDb:MappingMongoConverter _class を削除する
-
25-10-2019 - |
質問
デフォルト マッピングモンゴコンバータ カスタム タイプ キー (「_class」) をデータベース内の各オブジェクトに追加します。したがって、人を作成すると、次のようになります。
package my.dto;
public class Person {
String name;
public Person(String name) {
this.name = name;
}
}
それをデータベースに保存します。
MongoOperations ops = new MongoTemplate(new Mongo(), "users");
ops.insert(new Person("Joe"));
mongo 内の結果のオブジェクトは次のようになります。
{ "_id" : ObjectId("4e2ca049744e664eba9d1e11"), "_class" : "my.dto.Person", "name" : "Joe" }
質問:
Person クラスを別の名前空間に移動すると、どのような影響がありますか?
「_class」キーでオブジェクトを汚染しないようにすることはできますか。Person クラス専用の独自のコンバータを作成せずに?
解決
ストーリーは次のとおりです。デフォルトでタイプを、実際にインスタンス化するクラスを何らかのヒントとして追加します。ドキュメントを介して読むためにタイプでパイプする必要があるので MongoTemplate
とにかく、2つの可能なオプションがあります。
- 実際の保存されたタイプを割り当てることができるタイプを手渡します。その場合、保存されたタイプを検討し、オブジェクトの作成にそれを使用します。ここでの古典的な例は、多型クエリを行うことです。抽象クラスがあるとします
Contact
そしてあなたのPerson
. 。その後、クエリすることができますContact
Sと私たちは本質的に した方が良い インスタンス化するタイプを決定します。 - あなたが - 一方で、まったく異なるタイプを渡すと、実際にドキュメントに保存されているものにはなく、そのタイプにそのタイプに刻みます。それはあなたがタイプを移動するとどうなるかという質問をカバーします。
あなたは見ることに興味があるかもしれません このチケット タイプ情報を実際のタイプに変えるための何らかのプラグ可能なタイプマッピング戦略をカバーします。これは、長い資格のあるクラス名を数文字のハッシュに減らしたいと思うかもしれないので、単に宇宙節約の目的を果たすことができます。また、別のDataStoreクライアントによって生成された完全に任意のタイプキーを見つける可能性があり、それらをJavaタイプに結合する可能性のある、より複雑な移行シナリオを可能にします。
他のヒント
これが私の注釈です、そしてそれは機能します。
@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;
}
}
<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>
無効にしたい場合 _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
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);
}
}
これが、非推奨の警告のないクリーンなクラスを望んでいる人々に役立つことを願っています。
これが私の1つのラインソリューションです:
@Bean
public MongoTemplate mongoTemplateFraud() throws UnknownHostException {
MongoTemplate mongoTemplate = new MongoTemplate(getMongoClient(), dbName);
((MappingMongoConverter)mongoTemplate.getConverter()).setTypeMapper(new DefaultMongoTypeMapper(null));//removes _class
return mongoTemplate;
}
私はこの問題に長い間苦労しました。私はアプローチに従いました 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
ベースクラスからコンバーターを取得すると、タイプ変換クラスが登録されることが保証されます
@TypeAliasアノテーションをクラスの定義に追加するだけで、タイプのマッパーの変更について
@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;
}
}