1

Im using Mongo Java driver 3.7

This is my POJO(with getters and setters) -

public class Sample{
    public int field1;
    public JsonNode field2;
}

Im using the below code to insert an object of Sample into MongoDB.

MongoCollection<Sample> myCollection = database.getCollection("myCollection",Sample.class);
ObjectMapper mapper = new ObjectMapper();
    Sample obj = new Sample();
    obj.setField1(1);
    String sampleJSON = "{ \"key\": \"value\" }";
    obj.setField2(mapper.readTree(sample));

myCollection.insertOne(obj);

Seen Output: (JsonNode field is empty)

{
    "_id" : ObjectId("5afbff8a8f621e1e328a8c4e"),
    "field1" : 1
    "field2" : [
                 [ ]
               ],
}

Note: In debug mode, it is clear that the JsonNode is created with proper data. But insert is misbehaving. I guess I'm missing something here. Any leads appreciated.

Update: I tried writing a custom codec for JsonNode class, but it is never being used by mongo. This is my codec code -

@Slf4j
public class JsonNodeCodec implements CollectibleCodec<JsonNode> {
    @Inject
    private ObjectMapper objectMapper;

    @Override
    public JsonNode generateIdIfAbsentFromDocument(JsonNode jsonNode) {
        return null;
    }

    @Override
    public boolean documentHasId(JsonNode jsonNode) {
        return false;
    }

    @Override
    public BsonValue getDocumentId(JsonNode jsonNode) {
        return null;
    }

    @Override
    public JsonNode decode(BsonReader reader, DecoderContext decoderContext) {
        String task = reader.readString();
        JsonNode node = objectMapper.readTree(task);
        return node;
    }

    @Override
    public void encode(BsonWriter writer, JsonNode jsonNode, EncoderContext encoderContext) {
        writer.writeString(jsonNode.toString());
    }

    @Override
    public Class<JsonNode> getEncoderClass() {
        return JsonNode.class;
    }
}

And I'm registering the codec like this -

Codec<JsonNode> jsonNodeCodec = new JsonNodeCodec();
CodecRegistry codecRegistry = CodecRegistries.fromRegistries(com.mongodb.MongoClient.getDefaultCodecRegistry(),
            CodecRegistries.fromCodecs(jsonNodeCodec),
            CodecRegistries.fromProviders(PojoCodecProvider.builder().automatic(true).build())
    );

PS: Other codecs registered for custom POJOs are working fine. But this codec is never being used to encode/decode JSON objects

2 Answers 2

5

Just add custom converters to convert JsonNode object to org.bson.Document and vice-versa. Keep your POJOs/Document classes as it is with JsonNode fields. If using spring :

@Bean
public MongoCustomConversions mongoCustomConversions() {
    List<Converter<?, ?>> converters = new ArrayList<>();
    converters.add(JsonNodeToDocumentConverter.INSTANCE);
    converters.add(DocumentToJsonNodeConverter.INSTANCE);
    return new MongoCustomConversions(converters);
}

@WritingConverter
enum JsonNodeToDocumentConverter implements Converter<JsonNode, Document> {
    INSTANCE;

    public Document convert(JsonNode source) {
        if(source == null)
            return null;

        return Document.parse(source.toString());
    }
}

@ReadingConverter
enum DocumentToJsonNodeConverter implements Converter<Document, JsonNode> {
    INSTANCE;

    public JsonNode convert(Document source) {
        if(source == null)
            return null;

        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.readTree(source.toJson());
        } catch (IOException e) {
            throw new RuntimeException("Unable to parse DbObject to JsonNode", e);
        }
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Will this just add two more converters to list existing default converters? Or this replaces all converters with two total converters?
Will add two more, Default constructor is MongoCustomConversions() { this(Collections.emptyList()); }
Why you use singletons for converters?
2

I was facing the same issue here and resolved using ObjectMapper.

Use below:

ObjectMapper mapper =   new ObjectMapper();
Map inputMap        =   mapper.convertValue(jsonNode, Map.class);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.