12/03/2013

[MongoDB-Escape dots '.' in map key] Resolve org.springframework.data.mapping.model.MappingException: Map key foo.map.key contains dots but no replacement was configured!

Sometimes we need to save map into MongoDB. But the key of the map cannot have dots inside its keys.

If the key has dot(s), by default we'll get this kind of exception:
org.springframework.data.mapping.model.MappingException: Map key foo.bar.key contains dots but no replacement was configured! Make sure map keys don't contain dots in the first place or configure an appropriate replacement!
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.potentiallyEscapeMapKey(MappingMongoConverter.java:622)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeMapInternal(MappingMongoConverter.java:586)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.createMap(MappingMongoConverter.java:517)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writePropertyInternal(MappingMongoConverter.java:424)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter$3.doWithPersistentProperty(MappingMongoConverter.java:386)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter$3.doWithPersistentProperty(MappingMongoConverter.java:373)
    at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:257)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:373)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writePropertyInternal(MappingMongoConverter.java:451)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter$3.doWithPersistentProperty(MappingMongoConverter.java:386)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter$3.doWithPersistentProperty(MappingMongoConverter.java:373)
    at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:257)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:373)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writePropertyInternal(MappingMongoConverter.java:451)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter$3.doWithPersistentProperty(MappingMongoConverter.java:386)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter$3.doWithPersistentProperty(MappingMongoConverter.java:373)
    at org.springframework.data.mapping.model.BasicPersistentEntity.doWithProperties(BasicPersistentEntity.java:257)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:373)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:345)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:310)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:77)
    at org.springframework.data.mongodb.core.MongoTemplate.doSave(MongoTemplate.java:859)
    at org.springframework.data.mongodb.core.MongoTemplate.save(MongoTemplate.java:806)
    at org.springframework.data.mongodb.core.MongoTemplate.save(MongoTemplate.java:794)


Refer to the source code:

Spring => "MappingMongoConverter.java"
/**
     * Potentially replaces dots in the given map key with the configured map key replacement if configured or aborts
     * conversion if none is configured.
     * 
     * @see #setMapKeyDotReplacement(String)
     * @param source
     * @return
     */
    protected String potentiallyEscapeMapKey(String source) {

        if (!source.contains(".")) {
            return source;
        }

        if (mapKeyDotReplacement == null) {
            throw new MappingException(String.format("Map key %s contains dots but no replacement was configured! Make "
                    + "sure map keys don't contain dots in the first place or configure an appropriate replacement!", source));
        }

        return source.replaceAll("\\.", mapKeyDotReplacement);
    }

So the solution is configure the property mapKeyDotReplacement for bean MappingMongoConverter in the spring config file.

For example:
<bean id="mongoMoxydomainConverter" class="org.springframework.data.mongodb.core.convert.MappingMongoConverter">
        <constructor-arg index="0" ref="mongoDbFactory" />
        <constructor-arg index="1">
            <bean class="org.springframework.data.mongodb.core.mapping.MongoMappingContext" />
        </constructor-arg>
        <property name="mapKeyDotReplacement" value="\\+"/>
</bean>

What needs to be mentioned is that, the value that we set for "mapKeyDotReplacement" must follow the regular pattern's rule. If use reserved character, must use '\\' to translate it.




No comments:

Post a Comment