Primavera dati MongoDb: _class MappingMongoConverter remove
-
25-10-2019 - |
Domanda
L'impostazione predefinita MappingMongoConverter aggiunge una chiave tipo personalizzato ( "_class") per ogni oggetto nel database. Quindi, se creo una Persona:
package my.dto;
public class Person {
String name;
public Person(String name) {
this.name = name;
}
}
e salvarlo db:
MongoOperations ops = new MongoTemplate(new Mongo(), "users");
ops.insert(new Person("Joe"));
l'oggetto con la conseguente mongo sarà:
{ "_id" : ObjectId("4e2ca049744e664eba9d1e11"), "_class" : "my.dto.Person", "name" : "Joe" }
Domande:
-
Quali sono le implicazioni del passaggio alla classe Person in uno spazio dei nomi diverso?
-
E 'possibile non inquinare l'oggetto con il tasto "_class"; senza scrivere un convertitore unico solo per la classe Person?
Soluzione
Quindi, ecco la storia: aggiungiamo il tipo di default come una sorta di suggerimento quale classe istanziare realtà. Come si deve il tubo in un tipo di leggere il documento in via MongoTemplate
in ogni caso ci sono due opzioni possibili:
- mano in un tipo del tipo effettivo memorizzato può essere assegnato. In tal caso si considera il tipo memorizzato, l'uso che per la creazione di oggetti. classico esempio qui sta facendo interrogazioni polimorfiche. Supponiamo di avere un
Contact
classe astratta e la vostraPerson
. Si potrebbe quindi query perContact
s e abbiamo essenzialmente Sono d' di determinare un tipo di istanziare. - Se - d'altra parte - pass in un tipo completamente diverso saremmo semplicemente maresciallo in quel determinato tipo, non in quello memorizzato nel documento in realtà. Che sarebbe coprire la domanda che cosa succede se si sposta il tipo.
Si potrebbe essere interessato a guardare questo biglietto che copre una sorta di mappatura di tipo pluggable strategia per trasformare le informazioni sul tipo in un tipo effettivo. Questo può servire semplicemente spazio fini di risparmio, come si potrebbe desiderare di ridurre un lungo nome di classe qualificato per un hash di alcune lettere. Sarebbe anche consentire scenari di migrazione più complesse in cui si potrebbe trovare chiavi di tipo completamente arbitrarie prodotte da un altro client datastore e si legano a quelli tipi Java.
Altri suggerimenti
Ecco la mia annotazione, e funziona.
@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>
Se si desidera disattivare l'attributo _class
per impostazione predefinita, ma preservare polimorfismo per le classi specificate, è possibile esplicitamente definire il tipo di _class
di campo (opzionale) per configuing:
@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;
}
Questo campo _class
preservare (o quello che volete a nome construtor) per gli enti solo specificati.
È possibile anche scrivere proprio TypeInformationMapper
ad esempio sulla base di annotazioni. Se si annota il documento da @DocumentType("aliasName")
si può mantenere il polimorfismo, mantenendo alias di classe.
ho spiegato brevemente sul mio blog , ma qui è un po 'pezzo di codice rapido: https://gist.github.com/athlan/6497c74cc515131e1336
Mentre, la risposta di Mkyong funziona ancora, vorrei aggiungere la mia versione della soluzione, come pochi bit sono obsolete e possono essere in procinto di pulizia.
Ad esempio: MappingMongoConverter(mongoDbFactory(), new MongoMappingContext())
è deprecato in favore di new MappingMongoConverter(dbRefResolver, new MongoMappingContext());
e SimpleMongoDbFactory(new Mongo(), "databasename");
a favore di new SimpleMongoDbFactory(new MongoClient(), database);
.
Quindi, la mia risposta finale di lavoro senza avvisi deprecazione è:
@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);
}
}
Spero che questo aiuti le persone che vorrebbero avere una classe pulita senza warning di deprecazione.
Questa è la mia soluzione di una riga:
@Bean
public MongoTemplate mongoTemplateFraud() throws UnknownHostException {
MongoTemplate mongoTemplate = new MongoTemplate(getMongoClient(), dbName);
((MappingMongoConverter)mongoTemplate.getConverter()).setTypeMapper(new DefaultMongoTypeMapper(null));//removes _class
return mongoTemplate;
}
Ho lottato a lungo con questo problema. Ho seguito l'approccio da mkyong ma quando ho introdotto un attributo LocalDate
(qualsiasi classe JSR310 da Java 8) Ho ricevuto la seguente eccezione :
org.springframework.core.convert.ConverterNotFoundException:
No converter found capable of converting from type [java.time.LocalDate] to type [java.util.Date]
La corrispondente org.springframework.format.datetime.standard.DateTimeConverters
convertitore fa parte della Primavera 4.1 e viene fatto riferimento in primavera dati MongoDB 1.7. Anche se ho usato le versioni più recenti del convertitore non ha saltato in.
La soluzione era quella di utilizzare il MappingMongoConverter
esistente e solo fornire un nuovo DefaultMongoTypeMapper
(il codice da mkyong è in fase di commento):
@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)
}
Per riassumere:
- estendere
AbstractMongoConfiguration
- annotate con
EnableMongoRepositories
- in
mongoTemplate
get convertitore dalla classe base, questo assicura che le classi tipo di conversione sono registrati
si solo bisogno di aggiungere l'annotazione @TypeAlias ??alla definizione di classe sopra cambiando il tipo 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;
}
}