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:

  1. Quali sono le implicazioni del passaggio alla classe Person in uno spazio dei nomi diverso?

  2. E 'possibile non inquinare l'oggetto con il tasto "_class"; senza scrivere un convertitore unico solo per la classe Person?

È stato utile?

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:

  1. 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 vostra Person. Si potrebbe quindi query per Contacts e abbiamo essenzialmente Sono d' di determinare un tipo di istanziare.
  2. 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;

    }

}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top