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
.