Question

La valeur par défaut MappingMongoConverter ajoute une touche de type personnalisé ( "de _class") à chaque objet dans la base de données. Donc, si je crée une personne:

package my.dto;
public class Person {
    String name;
    public Person(String name) {
        this.name = name; 
    }
}

et de l'enregistrer à la DB:

MongoOperations ops = new MongoTemplate(new Mongo(), "users");
ops.insert(new Person("Joe"));

l'objet résultant dans le mongo sera:

{ "_id" : ObjectId("4e2ca049744e664eba9d1e11"), "_class" : "my.dto.Person", "name" : "Joe" }

Questions:

  1. Quelles sont les implications de déplacer la classe personne dans un autre espace de noms?

  2. Est-il possible de ne pas polluer l'objet avec la touche « _class »; sans écrire un convertisseur unique juste pour la classe Person?

Était-ce utile?

La solution

Alors, voici l'histoire: nous ajoutons le type par défaut comme une sorte de soupçon quelle classe à instancier en fait. Comme vous devez tuyau dans un type de lire le document dans via MongoTemplate de toute façon, il y a deux options possibles:

  1. Vous la main dans un type du type réel stocké peut être affecté. Dans ce cas, nous considérons le type stocké, utilisez que pour la création d'objets. exemple classique ici est en train de faire des requêtes polymorphiques. Supposons que vous ayez un Contact de classe abstraite et votre Person. Vous pouvez ensuite requête pour Contacts et nous avons essentiellement doivent déterminer un type à instancier.
  2. Si vous - d'autre part - passe dans un type complètement différent que nous avions simplement maréchal dans ce type donné, non pas dans celui stocké dans le document en fait. Cela couvrirait votre question ce qui se passe si vous déplacez le type.

Vous pourriez être intéressé à regarder ce billet qui couvre une sorte de cartographie de type connectable stratégie pour transformer les informations de type dans un type réel. Cela peut simplement servir des fins d'économie d'espace que vous voudrez peut-être réduire un long nom de classe qualifié pour un hachage de quelques lettres. Elle permettrait également à des scénarios de migration plus complexes où vous pourriez trouver des clés de type complètement arbitraires produites par un autre client de datastore et se lient à ceux des types Java.

Autres conseils

Voici mon annotation, et cela fonctionne.

@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>

Si vous souhaitez désactiver l'attribut _class par défaut, mais préservez polymorfism pour certaines catégories, vous pouvez définir le type explictly de champ _class (en option) par 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;
}

Cela permettra de préserver champ _class (ou tout ce que vous voulez nom dans construtor) pour les entités spécifiées uniquement.

Vous pouvez également écrire propre TypeInformationMapper par exemple à base d'annotations. Si vous annoter votre document par @DocumentType("aliasName") vous garderez polymorphisme en gardant alias de classe.

je l'ai expliqué brièvement sur mon blog , mais voici un morceau de code rapide: https://gist.github.com/athlan/6497c74cc515131e1336

Alors, la réponse de Mkyong fonctionne toujours, je voudrais ajouter ma version de la solution que quelques bits sont déconseillés et peut-être dans le bord de nettoyage.

Par exemple: MappingMongoConverter(mongoDbFactory(), new MongoMappingContext()) est dépréciée en faveur de new MappingMongoConverter(dbRefResolver, new MongoMappingContext()); et SimpleMongoDbFactory(new Mongo(), "databasename"); en faveur de new SimpleMongoDbFactory(new MongoClient(), database);.

Alors, ma réponse finale de travail sans avertissement préalable est à l'obsolescence:

@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);

    }

}

Espérons que cela aide les gens qui aimeraient avoir une classe propre sans avertissement de désapprobation.

Ceci est ma solution d'une ligne:

@Bean 
public MongoTemplate mongoTemplateFraud() throws UnknownHostException {

  MongoTemplate mongoTemplate = new MongoTemplate(getMongoClient(), dbName);
  ((MappingMongoConverter)mongoTemplate.getConverter()).setTypeMapper(new DefaultMongoTypeMapper(null));//removes _class
  return mongoTemplate;
}

Je me suis battu longtemps avec ce problème. Je suivais l'approche de mkyong mais quand j'introduit un attribut LocalDate (toute classe JSR310 de Java 8) J'ai reçu l'exception suivante :

org.springframework.core.convert.ConverterNotFoundException:
No converter found capable of converting from type [java.time.LocalDate] to type [java.util.Date]

Le convertisseur org.springframework.format.datetime.standard.DateTimeConverters correspondant fait partie du printemps 4.1 et est référencé au printemps de données MongoDB 1.7. Même si je version, le convertisseur n'a pas sauté dans.

La solution était d'utiliser la MappingMongoConverter existante et seulement fournir une nouvelle DefaultMongoTypeMapper (le code de mkyong est sous commentaire):

@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)
    }

Pour résumer:

  • étendre AbstractMongoConfiguration
  • annoter avec EnableMongoRepositories
  • dans mongoTemplate get convertisseur de classe de base, ce qui garantit que les classes de conversion de type sont enregistrés

vous juste besoin d'ajouter l'annotation @TypeAlias ??à la défintion de classe sur la modification du type mappeur

@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;

    }

}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top