Question

MongoTemplate inserts an attribute named "_class" into anything it puts into Mongo, and there are ways to turn that off.

However, it seems to be unwilling to read anything back out of it that doesn't have a _class attribute. Simply removing that from the mongo document appears to make it inaccessible. Since reading data you didn't write yourself is an obvious use case, I figure I must be missing something here.

I've been attempting to use this:

List<SomeClass> list = mongoTemplate.findAll(SomeClass.class, "someCollection");

...where SomeClass is annotated with @Id and @Document, and the documents in someCollection otherwise correctly map to the object. I can verify this by creating one of these objects in code, using insert to get it into Mongo, and then see that I can read it back out again.

This works just fine if _class is there but fails if it is not. I do not care about polymorphism or anything that might actually need this attribute. How can I get MongoTemplate to read data that it didn't itself write?

Was it helpful?

Solution

Okay, I found the answer...DavidA's advice was correct but missing the crucial part: when you set up the MappingMongoConverter dealio with the null type mapping business, it not only stops writing the "_class" pollution, but also stops attempting to read it. This causes it to fall back to the type you provide when attempting to retrieve your documents from Mongo.

I haven't seen anywhere that anyone actually mentions that. :)

So, for anybody else running into this issue, here's the XML configuration I used (adapted from something I found somewhere else here on StackOverflow, but I lost the link, sorry):

<mongo:db-factory id="mongoDbFactory" host="${mongo.host}" port="${mongo.port}" dbname="${mongo.dbname}"/>

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

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

And then in the Java code:

//build query object
UnifiedProduct mpp = mongoTemplate.findOne(query, UnifiedProduct.class, "collection-name");

...which results in the UnifiedProduct class I wanted, and no annoying "_class" pollution.

OTHER TIPS

Spring's MappingMongoConverter uses a MongoTypeMapper in order to figure out what type to use when reading in a DBObject from the database. The DefaultMongoTypeMapper uses the "_class" attribute to work as you have described.

You should be able to implement your own MongoTypeMapper and tell the MappingMongoConberter to use it. Your version can use other indicators instead of "_class" value to determine what type should be created when reading.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top