反序列化 jackson 中的 bson long primitive json

Deserialize bson long primitive json in jackson

我正在使用 MongoDB 作为我们的数据存储,但我们想将 Jackson 用于 serialization/deserialization(Mongo pojo 类 几乎无法处理杰克逊的许多场景 - 例如建筑商)。

我们使用自定义 CodecProvider 进行此工作 - 这是编解码器本身:

class JacksonCodec<T> implements Codec<T> {


   private final ObjectMapper objectMapper;
    private final Codec<RawBsonDocument> rawBsonDocumentCodec;
    private final Class<T> type;

    public JacksonCodec(ObjectMapper objectMapper,
                        CodecRegistry codecRegistry,
                        Class<T> type) {
        this.objectMapper = objectMapper;
        this.rawBsonDocumentCodec = codecRegistry.get(RawBsonDocument.class);
        this.type = type;
    }

    @Override
    public T decode(BsonReader reader, DecoderContext decoderContext) {
        try {

            RawBsonDocument document = rawBsonDocumentCodec.decode(reader, decoderContext);
            String json = document.toJson();
            return objectMapper.readValue(json, type);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    @Override
    public void encode(BsonWriter writer, Object value, EncoderContext encoderContext) {
        try {

            String json = objectMapper.writeValueAsString(value);

            rawBsonDocumentCodec.encode(writer, RawBsonDocument.parse(json), encoderContext);

        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    @Override
    public Class<T> getEncoderClass() {
        return this.type;
    }
}

这工作正常,直到我们从 Mongo 中检索到一个长度大于 Integer.MAXVALUE 的文档。发生这种情况时,反序列化会失败并显示以下消息:

原因:com.fasterxml.jackson.databind.JsonMappingException:无法反序列化长出 START_OBJECT 令牌的实例。

查看 bson,Mongo 数据返回给我们的方式如下:

"dateStamp":{“$numberLong”:“1514334498165”}

所以...我在想我需要为 Jackson 注册一个额外的反序列化器来处理这种情况(检查 ID_START_OBJECT 的标记类型,如果存在则解析,否则委托给内置解串器)。我尝试使用 ObjectMapper SimpleModule 注册一个简单的 Long 解串器:

public class BsonLongDeserializer  extends JsonDeserializer<Long>{

    @Override
    public Class<Long> handledType() {
        return Long.class;
    }

    @Override
    public Long deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        if (p.currentTokenId() != JsonTokenId.ID_START_OBJECT){
            // have to figure out how to do this for real if we can get the deserilizer to actually get called
            return ctxt.readValue(p, Long.class);
        }
        return null;
    }
}

并注册:

private static ObjectMapper createMapper(){
    SimpleModule module = new SimpleModule();
    module.addDeserializer(Long.class, new BsonLongDeserializer());

    ObjectMapper mapper = new ObjectMapper()
    .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    .registerModule(module);

    return mapper;
}

但是 BsonLongDeserializer 从未被 Jackson 调用(原语处理方式不同并且可能使已注册的反序列化器短路吗?)。

杰克逊版本 2.9.3。 Mongo数据库驱动程序版本 3.6。

如果有人对攻击这个问题的角度有任何建议,我将不胜感激。

似乎没有帮助的参考文章:

我通过创建一个 JsonWriterSettings 对象来抑制奇怪的 json 反序列化,从而修复了 Mongo 方面的问题,从而使其正常工作。这来自这里:converting Document objects in MongoDB 3 to POJOS

编解码器现在看起来像这样:

class JacksonCodec<T> implements Codec<T> {
    private final ObjectMapper objectMapper;
    private final Codec<BsonDocument> rawBsonDocumentCodec;
    private final Class<T> type;

    public JacksonCodec(ObjectMapper objectMapper,
                        CodecRegistry codecRegistry,
                        Class<T> type) {
        this.objectMapper = objectMapper;
        this.rawBsonDocumentCodec = codecRegistry.get(BsonDocument.class);
        this.type = type;
    }

    @Override
    public T decode(BsonReader reader, DecoderContext decoderContext) {
        try {
            //
            JsonWriterSettings settings = JsonWriterSettings.builder().int64Converter((value, writer) -> writer.writeNumber(value.toString())).build();

            BsonDocument document = rawBsonDocumentCodec.decode(reader, decoderContext);
            String json = document.toJson(settings);
            return objectMapper.readValue(json, type);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    @Override
    public void encode(BsonWriter writer, Object value, EncoderContext encoderContext) {
        try {

            String json = objectMapper.writeValueAsString(value);

            rawBsonDocumentCodec.encode(writer, RawBsonDocument.parse(json), encoderContext);

        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    @Override
    public Class<T> getEncoderClass() {
        return this.type;
    }
}