Search code examples
javaspringmongodbspring-dataspring-websocket

Proper way to map ObjectId to String in DTO in Spring


I am working with Spring WebSocket. I have this DTO of the Message

@AllArgsConstructor
@Data
public class MessageDto {

    private ObjectId messageId;
    private ObjectId chatId;
}

When I send this DTO as response, ObjectId fields in DTO maps like this:

enter image description here

How can I map ObjectId field into String like 62790c02513ad11442eec6d7?


Solution

  • Spring uses Jackson to map objects to JSON, so the proper way to map ObjectId field in a object is to configure Jackson serializers.

    Create a serializer class:

    import com.fasterxml.jackson.core.JsonGenerator;
    import com.fasterxml.jackson.databind.JsonSerializer;
    import com.fasterxml.jackson.databind.SerializerProvider;
    import org.bson.types.ObjectId;
    
    import java.io.IOException;
    
    public class ObjectIdSerializer extends JsonSerializer<ObjectId> {
    
        @Override
        public void serialize(ObjectId id, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
                throws IOException {
            jsonGenerator.writeObject(id == null ? null : id.toString());
        }
    }
    

    And then specify the serializer in a DTO class:

    @AllArgsConstructor
    @Data
    public class MessageDto {
    
        @JsonSerialize(using = ObjectIdSerializer.class)
        private ObjectId messageId;
        @JsonSerialize(using = ObjectIdSerializer.class)
        private ObjectId chatId;
    }
    

    In conclusion, the ObjectId field of the MessageDto object will be serialized like a string in JSON

    Of course, there is a problem to deserialize JSON to an object. There are JsonDeserializer<> and @JsonDeserialize to solve this problem. But there (mapping ObjectId class field) deserializer is useless, because ObjectId already have a constructor, that receives a String parameter, so Jackson will use it.