spring data mongodb calling save twice leads to duplicate key exception

As stated in my last edit the problem was with the custom serialization/deserialization and mongo document conversion. This resulted in id being null and therefore an insert was done instead of an upsert.

The following code is my implementation of my custom converter to map the objectid:

public class MongoBarConversion {

    @Component
    @ReadingConverter
    public static class ToBarConverter implements Converter<Document, Bar> {

        private final ObjectMapper mapper;

        @Autowired
        public ToBarConverter(ObjectMapper mapper) {
            this.mapper = mapper;
        }

        public Bar convert(Document source) {
            JsonNode json = toJson(source);
            setObjectId(source, json);
            return mapper.convertValue(json, new TypeReference<Bar>() {
            });
        }

        protected void setObjectId(Document source, JsonNode jsonNode) {
            ObjectNode modifiableObject = (ObjectNode) jsonNode;
            String objectId = getObjectId(source);
            modifiableObject.put(ID_FIELD, objectId);
        }

        protected String getObjectId(Document source) {
            String objectIdLiteral = null;
            ObjectId objectId = source.getObjectId("_id");
            if (objectId != null) {
                objectIdLiteral = objectId.toString();
            }
            return objectIdLiteral;
        }


        protected JsonNode toJson(Document source) {
            JsonNode node = null;
            try {
                String json = source.toJson();
                node = mapper.readValue(json, JsonNode.class);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
            return node;
        }

    }


    @Component
    @WritingConverter
    public static class ToDocumentConverter implements Converter<Bar, Document> {

        private final ObjectMapper mapper;

        @Autowired
        public ToDocumentConverter(ObjectMapper mapper) {
            this.mapper = mapper;
        }

        public Document convert(Bar source) {
            try {
                JsonNode jsonNode = toJson(source);
                setObjectId(source, jsonNode);
                String json = mapper.writeValueAsString(jsonNode);
                return Document.parse(json);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }

        protected void setObjectId(Bar source, JsonNode jsonNode) throws JsonProcessingException {
            ObjectNode modifiableObject = (ObjectNode) jsonNode;
            JsonNode objectIdJson = getObjectId(source);
            modifiableObject.set("_id", objectIdJson);
            modifiableObject.remove(ID_FIELD);
        }

        protected JsonNode getObjectId(Bar source) throws JsonProcessingException {
            ObjectNode _id = null;
            String id = source.getId();
            if (id != null) {
                _id = JsonNodeFactory.instance.objectNode();
                _id.put("$oid", id);
            }
            return _id;
        }

        protected JsonNode toJson(Bar source) {
            return mapper.convertValue(source, JsonNode.class);
        }
    }


}

So to conclude: two subsequent saves should (and will) definitely lead to an upsert if the id is non null. The bug was in my code.


All MongoDB drivers include functionality to generate ids on the client side. If you only save to get the id, research how to use client-side id generation and remove the first save entirely.