How do I combine java.util.Map-based mappings with the Spring Data MongoDB annotations (@Id, @Field, ...)?

1.1k Views Asked by At

I'm going to store a dynamic document with a certain ID. By the dynamic document I mean a map of strings to objects where I don't really care the exact mapping in order to store documents in arbitrary form. However, I would like those documents to be identified by a certain ID specified programmatically, but I would like to have the ID to be declared with org.springframework.data.annotation.Id. Here is the document mapping I expected to work:

@Document(collection = "mappings")
public final class Mapping
        extends org.bson.Document { // implements Map<String, Object> implicitly

    @Id
    private String id;

    public void setId(final String id) {
        this.id = id;
    }

}

And the respective repository:

@Repository
interface IMappingRepository
        extends MongoRepository<Mapping, String> {
}

Unfortunately, because of implementing the Map interface (I guess), the ID annotation seems to be absolutely ignored in the mapping. For example, if I specify the _id property myself, I can easily override the key:

final Mapping mapping = new Mapping();
mapping.put("_id", "foo");
mappingRepository.save(mapping);

{ "_id" : "foo", "_class" : "foo.Mapping", ... }

However, if I assign the annotated field like this (the way I would like to use):

final Mapping mapping = new Mapping();
mapping.setId("foo");
mappingRepository.save(mapping);

then my mapping won't work having automatically assigned keys:

{ "_id" : ObjectId("585173b7853b017ee9c1468f"), "_class" : "foo.Mapping", ... }

Another pitfall of this is issue, is that, for example, the delete(entity) in the repository won't work throwing the following exception:

java.lang.IllegalArgumentException: The given id must not be null!
at org.springframework.util.Assert.notNull(Assert.java:115) ~[spring-core-4.3.4.RELEASE.jar:4.3.4.RELEASE]
at org.springframework.data.mongodb.repository.support.SimpleMongoRepository.delete(SimpleMongoRepository.java:156) ~[spring-data-mongodb-1.9.5.RELEASE.jar:na]
at org.springframework.data.mongodb.repository.support.SimpleMongoRepository.delete(SimpleMongoRepository.java:166) ~[spring-data-mongodb-1.9.5.RELEASE.jar:na]

The library source code:

____    public void delete(ID id) {
156:        Assert.notNull(id, "The given id must not be null!");
____        mongoOperations.remove(getIdQuery(id), entityInformation.getJavaType(), entityInformation.getCollectionName());
____    }
____
____    /*
____     * (non-Javadoc)
____     * @see org.springframework.data.repository.CrudRepository#delete(java.lang.Object)
____     */
____    public void delete(T entity) {
____        Assert.notNull(entity, "The given entity must not be null!");
166:        delete(entityInformation.getId(entity));
____    }

It looks like my mapping ID is always ignored, however, mappingRepository.delete(id) works great.

Similarly, the @Field annotation is totally ignored too.

What am I missing and how do I combine the Spring Data MongoDB annotations and the map-like objects? Or is it possible to "unwrap" a map field to the top level of the mapping (say, a Map<String, Object> map could be annotated somehow in order to be merged with the parent object similarly to what com.fasterxml.jackson.annotation.JsonUnwrapped is designed for)? Or am I just missing an idiomatic way of doing this right? Thanks!

Edit 1:

I would like to make a small correction: if the Mapping.id field is removed frmo the mapping (effectively missing @Id), then the mappingRepository.delete(ID) fails with NullPointerException.

0

There are 0 best solutions below