2017-12-27 23 views
0

データストアとしてMongoDBを使用していますが、ジャクソンをシリアライゼーション/デシリアライズに使用したいと考えています(例えば、Mongo pojoクラスではJacksonのビルダーほどのシナリオは扱えません)。ジャーソンのbson longプリミティブjsonをデシリアライズする

私たちは、カスタム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; 
    } 
} 

我々はInteger.MAXVALUEよりも大きい、長いを持っているモンゴからドキュメントを取得するまで、これは、正常に動作します。その場合、次のメッセージでデシリアライズが失敗します。

原因:com.fasterxml.jackson.databind.JsonMappingException:START_OBJECTトークンからlongのインスタンスを逆シリアル化できません。 BSONを見ると

は、ここではモンゴデータは私達に戻って来ている方法は次のとおりです。

"日付スタンプ":{ "$ numberLong": "1514334498165"}

ので...私は考えていますジャクソンがこのケースを処理するために追加のデシリアライザを登録する必要があります(ID_START_OBJECTのトークンタイプをチェックし、存在する場合は解析し、そうでない場合は組み込みデシリアライザに委譲します)。

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; 
    } 
} 

し、それを登録します:私はObjectMapper SimpleModuleたシンプルなロングデシリアライザを登録しようとした

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はジャクソン(によって呼び出されることは決してありませんが別の方法で処理プリミティブと短絡登録デシリアライザです多分?)。

ジャクソン版2.9.3。 MongoDBドライババージョン3.6。

誰かがこれを攻撃するアングルについての提案があれば、私はそれを聞いていただければ幸いです。助けていないように見えます

参考記事:MongoDB "NumberLong/$numberLong" issue while converting back to Java Object

答えて

0

それは奇妙なJSONデシリアライズを抑制するためにJsonWriterSettingsオブジェクトを作成することで、物事のモンゴ側を固定することで、私を働いてしまいました。これは、ここから来た: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; 
    } 
} 
関連する問題