Spring data MongoDb:MappingMongoConverter entfernen _class
-
25-10-2019 - |
Frage
Die Standard - MappingMongoConverter fügt einen benutzerdefinierten Typ-Schlüssel ("_class") auf jedes Objekt in der Datenbank.Also, wenn ich eine Person:
package my.dto;
public class Person {
String name;
public Person(String name) {
this.name = name;
}
}
und speichern Sie es auf die db:
MongoOperations ops = new MongoTemplate(new Mongo(), "users");
ops.insert(new Person("Joe"));
das resultierende Objekt wird in der mongo wird:
{ "_id" : ObjectId("4e2ca049744e664eba9d1e11"), "_class" : "my.dto.Person", "name" : "Joe" }
Fragen:
Was sind die Auswirkungen von moving die Person-Klasse in einem anderen namespace?
Ist es möglich, nicht zu verschmutzen das Objekt mit der "_class" - Taste;ohne schreiben einer einzigartigen Konverter nur für die Person-Klasse?
Lösung
Hier ist also die Geschichte: Wir fügen den Typ standardmäßig als Hinweis hinzu, welche Klasse wir tatsächlich instanziieren sollen. Wie Sie in einen Typ putzen müssen, um das Dokument in via zu lesen MongoTemplate
Auf jeden Fall gibt es zwei mögliche Optionen:
- Sie übergeben einen Typ. Der tatsächliche gespeicherte Typ kann zugewiesen werden. In diesem Fall betrachten wir den gespeicherten Typ, verwenden Sie ihn für die Erstellung von Objekten. Klassisches Beispiel Hier legt polymorphe Abfragen. Angenommen, Sie haben eine abstrakte Klasse
Contact
und deinPerson
. Sie könnten dann nachfragenContact
s und wir im Wesentlichen müssen, zu ... haben Bestimmen Sie einen zum Instanziieren von einem Typ. - Wenn Sie - andererseits - in einen völlig anderen Typ übergeben, haben wir einfach in diesen gegebenen Typ eingetaucht, nicht in das, das tatsächlich im Dokument gespeichert ist. Das würde Ihre Frage behandeln, was passiert, wenn Sie den Typ verschieben.
Sie könnten anschauen diese Karte Dies deckt eine Art steckbarer Typ -Mapping -Strategie ab, um die Typinformationen in einen tatsächlichen Typ zu verwandeln. Dies kann einfach Platzeinsparungszwecken dienen, da Sie möglicherweise einen langen qualifizierten Klassennamen auf einen Hash mit wenigen Buchstaben reduzieren möchten. Es würde auch komplexere Migrationsszenarien ermöglichen, in denen Sie möglicherweise vollständig willkürliche Typen finden, die von einem anderen DataStore -Client erstellt und an Java -Typen binden.
Andere Tipps
Hier ist meine Annotation und es funktioniert.
@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>
Wenn Sie möchten, zu deaktivieren _class
Attribut standardmäßig, aber bewahren Polymorphismus für bestimmte Klassen können Sie ausdrücklich definieren, welche Art von _class
(optional) Feld von 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;
}
Dies wird beibehalten _class
Feld (oder wie auch immer du Sie nennen willst in construtor) für die nur die angegebenen Personen.
Sie können auch das schreiben eigener TypeInformationMapper
beispielsweise auf Basis von annotations.Wenn Sie Ihr Dokument mit Anmerkungen versehen von @DocumentType("aliasName")
Sie halten Polymorphismus indem alias der Klasse.
Ich habe kurz erklärt es auf meinem blog, aber hier ist ein Stück von quick-code:https://gist.github.com/athlan/6497c74cc515131e1336
Während Mkyongs Antwort immer noch funktioniert, möchte ich meine Lösung Version hinzufügen, da nur wenige Bits veraltet sind und möglicherweise kurz vor der Aufräumarbeiten stehen.
Zum Beispiel : MappingMongoConverter(mongoDbFactory(), new MongoMappingContext())
ist veraltet zugunsten von new MappingMongoConverter(dbRefResolver, new MongoMappingContext());
und SimpleMongoDbFactory(new Mongo(), "databasename");
zugunsten new SimpleMongoDbFactory(new MongoClient(), database);
.
Meine endgültige bearbeitete Antwort ohne Abschaltungswarnungen lautet:
@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);
}
}
Ich hoffe, dies hilft Menschen, die eine saubere Klasse ohne Abschaltwarnungen haben möchten.
Dies ist meine Lösung mit einer Zeilen:
@Bean
public MongoTemplate mongoTemplateFraud() throws UnknownHostException {
MongoTemplate mongoTemplate = new MongoTemplate(getMongoClient(), dbName);
((MappingMongoConverter)mongoTemplate.getConverter()).setTypeMapper(new DefaultMongoTypeMapper(null));//removes _class
return mongoTemplate;
}
Ich hatte lange mit diesem Problem zu kämpfen. Ich folgte dem Ansatz von Mkyong Aber als ich a vorstellte LocalDate
Attribut (jede JSR310 -Klasse von Java 8) Ich habe die folgende Ausnahme erhalten:
org.springframework.core.convert.ConverterNotFoundException:
No converter found capable of converting from type [java.time.LocalDate] to type [java.util.Date]
Der entsprechende Konverter org.springframework.format.datetime.standard.DateTimeConverters
ist Teil des Frühjahrs 4.1 und wird in den Federdaten MongoDB 1.7 verwiesen. Auch wenn ich neuere Versionen verwendet habe, sprang der Konverter nicht hinein.
Die Lösung bestand darin, die vorhandenen zu verwenden MappingMongoConverter
und nur eine neue zur Verfügung stellen DefaultMongoTypeMapper
(Der Code von Mkyong steht unter Kommentar):
@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)
}
Zusammenfassen:
- erweitern
AbstractMongoConfiguration
- Annotate mit
EnableMongoRepositories
- in
mongoTemplate
Get Converter aus der Basisklasse, dies stellt sicher, dass die Typ -Conversion -Klassen registriert sind
Sie müssen nur die @typealias -Annotation zur Klassendefinition hinzufügen, um den Typ Mapper zu ändern
@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;
}
}