Der Standardwert MappingMongoConverter fügt jedem Objekt in der Datenbank einen benutzerdefinierten Typschlüssel ("_class") hinzu. Also, wenn ich eine Person erstelle:
package my.dto;
public class Person {
String name;
public Person(String name) {
this.name = name;
}
}
und speichere es in der Datenbank:
MongoOperations ops = new MongoTemplate(new Mongo(), "users");
ops.insert(new Person("Joe"));
das resultierende Objekt im Mongo wird sein:
{ "_id" : ObjectId("4e2ca049744e664eba9d1e11"), "_class" : "my.dto.Person", "name" : "Joe" }
Fragen:
Was bedeutet es, die Person-Klasse in einen anderen Namespace zu verschieben?
Ist es möglich, das Objekt nicht mit der Taste "_class" zu verschmutzen? ohne einen eindeutigen Konverter nur für die Person-Klasse zu schreiben?
Hier ist die Geschichte: Wir fügen den Typ standardmäßig als Hinweis hinzu, welche Klasse tatsächlich instanziiert werden soll. Da Sie einen Typ eingeben müssen, um das Dokument über MongoTemplate
einzulesen, gibt es zwei Möglichkeiten:
Contact
und Ihre Person
. Sie könnten dann nach Contact
s fragen, und wir müssen im Wesentlichen einen zu instanziierenden Typ bestimmen .Sie könnten daran interessiert sein, dieses Ticket anzusehen, das eine Art steckbarer Typzuordnungsstrategie behandelt, um die Typinformationen in einen tatsächlichen Typ umzuwandeln. Dies kann einfach zu platzsparenden Zwecken dienen, da Sie einen langen qualifizierten Klassennamen möglicherweise auf einen Hash von wenigen Buchstaben reduzieren möchten. Dies würde auch komplexere Migrationsszenarien ermöglichen, in denen Sie möglicherweise vollständig beliebige Typschlüssel finden, die von einem anderen Datenspeicher-Client erstellt wurden, und diese an Java -Typen binden.
Hier ist meine Anmerkung, 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 das _class
-Attribut standardmäßig deaktivieren möchten, aber den Polymorfismus für bestimmte Klassen beibehalten möchten, können Sie den Typ des _class
-Felds (optional) explizit definieren, indem Sie Folgendes konfigurieren:
@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;
}
Dadurch wird das Feld _class
(oder was auch immer Sie in construtor benennen möchten) nur für angegebene Entitäten beibehalten.
Sie können auch eigene TypeInformationMapper
schreiben, zum Beispiel basierend auf Anmerkungen. Wenn Sie Ihr Dokument durch @DocumentType("aliasName")
mit Anmerkungen versehen, behalten Sie den Polymorphismus bei, indem Sie den Alias der Klasse beibehalten.
Ich habe es in meinem Blog kurz erklärt , aber hier ist ein kurzer Code: https://Gist.github.com/athlan/6497c74cc515131e1336
Während Mkyongs Antwort noch funktioniert, möchte ich meine Lösungsversion hinzufügen, da nur wenige Bits veraltet sind und möglicherweise im Begriff sind, aufgeräumt zu werden.
Beispiel: MappingMongoConverter(mongoDbFactory(), new MongoMappingContext())
wird zugunsten von new MappingMongoConverter(dbRefResolver, new MongoMappingContext());
und SimpleMongoDbFactory(new Mongo(), "databasename");
zugunsten von new SimpleMongoDbFactory(new MongoClient(), database);
nicht mehr empfohlen.
Meine letzte funktionierende Antwort ohne Verwerfungswarnungen lautet also:
@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);
}
}
Hoffe, dies hilft Menschen, die eine saubere Klasse ohne Verwerfungswarnungen haben möchten.
Dies ist meine einzeilige Lösung:
@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 ein LocalDate
-Attribut einführte (eine beliebige JSR310-Klasse aus Java 8), erhielt ich die folgende Ausnahme:
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 von Spring 4.1 und wird in Spring Data MongoDB 1.7 referenziert. Auch wenn ich neuere Versionen verwendet habe, ist der Konverter nicht eingesprungen.
Die Lösung bestand darin, die vorhandene MappingMongoConverter
zu verwenden und nur eine neue DefaultMongoTypeMapper
bereitzustellen (der Code von mkyong wird kommentiert):
@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:
AbstractMongoConfiguration
EnableMongoRepositories
kommentierenmongoTemplate
get converter from base class sicher, dass die Typkonvertierungsklassen registriert sindsie müssen lediglich die Annotation @TypeAlias 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;
}
}