我使用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检索一个长度大于Integer.MAXVALUE的文档。发生这种情况时,反序列化失败,并显示以下消息:
引起:com.fasterxml.jackson.databind.JsonMappingException:无法反序列化START_OBJECT标记中的long实例。
关注bson,以下是Mongo数据如何回复给我们:
&#34;邮戳&#34; :{&#34; $ numberLong&#34; :&#34; 1514334498165&#34; }
所以...我认为我需要为Jackson注册一个额外的反序列化器来处理这种情况(检查ID_START_OBJECT的令牌类型,如果它在那里就解析,否则委托给内置-in deserializer)。我尝试使用ObjectMapper SimpleModule注册一个简单的长反序列化器:
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。 MongoDB驱动程序版本3.6。
如果有人有任何关于攻击这个角度的建议,我将不胜感激。
参考文章似乎没有帮助:MongoDB "NumberLong/$numberLong" issue while converting back to Java Object
答案 0 :(得分:2)
我通过创建一个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;
}
}