我使用 MongoDB 作为我们的数据存储,但我们想使用 Jackson 进行序列化/反序列化(Mongo pojo 类不能处理与 Jackson 一样多的场景 - 例如构建器)。
我们使用自定义 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 检索一个 long 值大于 Integer.MAXVALUE 的文档。发生这种情况时,反序列化会失败并显示以下消息:
原因:com.fasterxml.jackson.databind.JsonMappingException:无法反序列化 START_OBJECT token 中的长实例。
查看 bson,Mongo 数据返回给我们的方式如下:
“dateStamp”:{“$numberLong”:“1514334498165”}
所以...我认为我需要为 Jackson 注册一个额外的反序列化器来处理这种情况(检查 ID_START_OBJECT 的 token 类型,解析它是否存在,否则委托(delegate)给内置反序列化器)。我尝试使用 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 调用(原语是否以不同的方式处理并可能使注册的反序列化器短路?)。
jackson 版本 2.9.3。 MongoDB 驱动程序版本 3.6。
如果有人对攻击这个问题的角度有任何建议,我将不胜感激。
引用文章似乎没有帮助:MongoDB "NumberLong/$numberLong" issue while converting back to Java Object
最佳答案
我通过创建 JsonWriterSettings 对象来修复 Mongo 方面的问题来抑制奇怪的 json 反序列化,从而使其正常工作。这来自这里: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 {
//https://stackoverflow.com/questions/35209839/converting-document-objects-in-mongodb-3-to-pojos
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;
}
}
关于java - 在 Jackson 中反序列化 bson long 原始 json,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47985123/