Spring Data 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"));
Полученным объектом в монго будет:
{ "_id" : ObjectId("4e2ca049744e664eba9d1e11"), "_class" : "my.dto.Person", "name" : "Joe" }
Вопросы:
Каковы последствия перемещения класса человека в другое пространство имен?
Возможно ли не загрязнять объект с помощью ключа "_class"; Не написав уникальный конвертер только для класса человека?
Решение
Итак, вот история: мы по умолчанию добавляем тип как какой -то намек на то, какой класс на самом деле экземплятся. Как вам нужно вписать в тип, чтобы прочитать документ в VIA MongoTemplate
В любом случае есть два возможных варианта:
- Вы передаете тип фактического хранимого типа можно назначить. В этом случае мы рассмотрим сохраненный тип, используйте его для создания объектов. Классический пример здесь выполняет полиморфные запросы. Предположим, у вас есть абстрактный класс
Contact
и вашPerson
. Анкет Тогда вы можете запроситьContact
S и мы по существу иметь Определите тип для экземпляра. - Если вы - с другой стороны - пройдите совершенно другой тип, мы просто засорим этот тип, а не в тот, который на самом деле хранится в документе. Это охватит ваш вопрос, что произойдет, если вы переместите тип.
Вы можете быть заинтересованы в просмотре этот билет который охватывает какую -то стратегию отображения плановых типов, чтобы превратить информацию типа в фактический тип. Это может служить простой целях сохранения пространства, так как вы, возможно, захотите уменьшить давно квалифицированное название класса в хэш из нескольких букв. Это также позволит более сложные сценарии миграции, где вы можете найти совершенно произвольные ключи типа, созданные другим клиентом данных, и связывать их с типами 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
Поле (или как вы хотите назвать в Construtor) только для указанных объектов.
Вы также можете написать собственный 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);
}
}
Надеюсь, что это поможет людям, которые хотели бы провести чистый класс без предупреждений об испаке.
Это мое решение для линии:
@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
Атрибут (любой класс JSR310 от Java 8) Я получил следующее исключение:
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
является частью пружины 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 в определение класса по поводу изменения типа Mapper
@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;
}
}