Spring 数据 MongoDb:MappingMongoConverter 删除 _class
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6810488/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring data MongoDb: MappingMongoConverter remove _class
提问by Yuriy Nemtsov
The default MappingMongoConverteradds a custom type key ("_class") to each object in the database. So, if I create a Person:
默认的MappingMongoConverter为数据库中的每个对象添加一个自定义类型键(“_class”)。所以,如果我创建一个人:
package my.dto;
public class Person {
String name;
public Person(String name) {
this.name = name;
}
}
and save it to the db:
并将其保存到数据库:
MongoOperations ops = new MongoTemplate(new Mongo(), "users");
ops.insert(new Person("Joe"));
the resulting object in the mongo will be:
mongo 中的结果对象将是:
{ "_id" : ObjectId("4e2ca049744e664eba9d1e11"), "_class" : "my.dto.Person", "name" : "Joe" }
Questions:
问题:
What are the implications of moving the Person class into a different namespace?
Is it possible not to pollute the object with the "_class" key; without writing a unique converter just for the Person class?
将 Person 类移动到不同的命名空间有什么含义?
是否可以不污染带有“_class”键的对象;不为 Person 类编写一个独特的转换器?
采纳答案by Oliver Drotbohm
So here's the story: we add the type by default as some kind of hint what class to instantiate actually. As you have to pipe in a type to read the document into via MongoTemplate
anyway there are two possible options:
所以故事是这样的:我们默认添加类型作为某种暗示实际实例化哪个类。由于您必须通过管道输入一种类型以通过MongoTemplate
任何方式读取文档,因此有两种可能的选择:
- You hand in a type the actual stored type can be assigned to. In that case we consider the stored type, use that for object creation. Classical example here is doing polymorphic queries. Suppose you have an abstract class
Contact
and yourPerson
. You could then query forContact
s and we essentially have todetermine a type to instantiate. - If you - on the other hand - pass in a completely different type we'd simply marshal into that given type, not into the one stored in the document actually. That would cover your question what happens if you move the type.
- 您提交可以分配给实际存储类型的类型。在这种情况下,我们考虑存储类型,将其用于对象创建。这里的经典示例是进行多态查询。假设你有一个抽象类
Contact
和你的Person
. 然后您可以查询Contact
s,我们基本上必须确定要实例化的类型。 - 另一方面,如果您传入一个完全不同的类型,我们只需将其编组到该给定类型,而不是实际存储在文档中的类型。这将涵盖您的问题,如果您移动类型会发生什么。
You might be interested in watching this ticketwhich covers some kind of pluggable type mapping strategy to turn the type information into an actual type. This can serve simply space saving purposes as you might want to reduce a long qualified class name to a hash of a few letters. It would also allow more complex migration scenarios where you might find completely arbitrary type keys produced by another datastore client and bind those to Java types.
您可能有兴趣观看这张票,它涵盖了某种可插入的类型映射策略,以将类型信息转换为实际类型。这可以仅用于节省空间的目的,因为您可能希望将长限定类名称减少为几个字母的散列。它还允许更复杂的迁移场景,您可能会发现另一个数据存储客户端生成的完全任意的类型键,并将它们绑定到 Java 类型。
回答by mkyong
Here's my annotation, and it works.
这是我的注释,它有效。
@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;
}
}
回答by Athlan
If you want to disable _class
attribute by default, but preserve polymorfism for specified classes, you can explictly define the type of _class
(optional) field by configuing:
如果您想_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;
}
This will preserve _class
field (or whatever you want to name in construtor) for only specified entities.
这将仅保留_class
指定实体的字段(或您想在构造函数中命名的任何内容)。
You can also write own TypeInformationMapper
for example based on annotations. If you annotate your document by @DocumentType("aliasName")
you will keep polymorphism by keeping alias of class.
您还可以TypeInformationMapper
根据注释编写自己的示例。如果你注释你的文档,@DocumentType("aliasName")
你将通过保持类的别名来保持多态性。
I have explained briefly it on my blog, but here is some piece of quick code: https://gist.github.com/athlan/6497c74cc515131e1336
我已经在我的博客上简要解释过,但这里有一些快速代码:https: //gist.github.com/athlan/6497c74cc515131e1336
回答by AKKI
<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>
回答by harshavmb
While, Mkyong's answer still works, I would like to add my version of solution as few bits are deprecated and may be in the verge of cleanup.
虽然 Mkyong 的答案仍然有效,但我想添加我的解决方案版本,因为不推荐使用一些位并且可能处于清理的边缘。
For example : MappingMongoConverter(mongoDbFactory(), new MongoMappingContext())
is deprecated in favor of new MappingMongoConverter(dbRefResolver, new MongoMappingContext());
and SimpleMongoDbFactory(new Mongo(), "databasename");
in favor of new SimpleMongoDbFactory(new MongoClient(), database);
.
例如:MappingMongoConverter(mongoDbFactory(), new MongoMappingContext())
被弃用new MappingMongoConverter(dbRefResolver, new MongoMappingContext());
而SimpleMongoDbFactory(new Mongo(), "databasename");
赞成new SimpleMongoDbFactory(new MongoClient(), database);
.
So, my final working answer without deprecation warnings is :
所以,我没有弃用警告的最终工作答案是:
@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);
}
}
Hope this helps people who would like to have a clean class with no deprecation warnings.
希望这可以帮助那些希望拥有一个没有弃用警告的干净类的人。
回答by kozla13
This is my one line solution:
这是我的单行解决方案:
@Bean
public MongoTemplate mongoTemplateFraud() throws UnknownHostException {
MongoTemplate mongoTemplate = new MongoTemplate(getMongoClient(), dbName);
((MappingMongoConverter)mongoTemplate.getConverter()).setTypeMapper(new DefaultMongoTypeMapper(null));//removes _class
return mongoTemplate;
}
回答by Naveen Anamaneni
@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;
}
}
回答by ChrLipp
I struggled a long time with this problem. I followed the approach from mkyongbut when I introduced a LocalDate
attribute (any JSR310 class from Java 8) I received the following exception:
我在这个问题上挣扎了很长时间。我遵循了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]
The corresponding converter org.springframework.format.datetime.standard.DateTimeConverters
is part of Spring 4.1 and is referenced in Spring Data MongoDB 1.7. Even if I used newer versions the converter didn't jump in.
相应的转换器org.springframework.format.datetime.standard.DateTimeConverters
是 Spring 4.1 的一部分,并在 Spring Data MongoDB 1.7 中引用。即使我使用了较新的版本,转换器也没有加入。
The solution was to use the existing MappingMongoConverter
and only provide a new DefaultMongoTypeMapper
(the code from mkyong is under comment):
解决方案是使用现有的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)
}
To summarize:
总结一下:
- extend
AbstractMongoConfiguration
- annotate with
EnableMongoRepositories
- in
mongoTemplate
get converter from base class, this ensures that the type conversion classes are registered
- 延长
AbstractMongoConfiguration
- 注释
EnableMongoRepositories
- 在
mongoTemplate
从基类获取转换器中,这确保了类型转换类已注册
回答by Matt
you just need to add the @TypeAlias annotation to the class defintion over changing the type mapper
您只需要通过更改类型映射器将 @TypeAlias 注释添加到类定义中