2016-07-15 4 views
1

DBに格納するためにシリアル化する際に暗号化する必要がある特定のオブジェクトの特定のフィールドがあります。Java Jacksonカスタムポリモルファスデシリアライザを使用してフィールドを暗号化/復号化する

メモリ内で暗号化する必要はありません。私はこれをコードベースの残りの部分に透過的に行いたいので、enc/decステップをser/deserレベルに置くことを考えました。

汎用的であるためには、私はインターフェイスおよび注釈を作成しました:

@JsonTypeInfo(
     use = JsonTypeInfo.Id.NAME, 
     include = JsonTypeInfo.As.PROPERTY, 
     property = "__TYPE__") 
@JsonSubTypes({ 
     @JsonSubTypes.Type(value = Type1.class, name = "Type1"), 
     @JsonSubTypes.Type(value = Type2.class, name = "Type2"), 
     @JsonSubTypes.Type(value = Type3.class, name = "Type3") 
}) 

@JsonSerialize(using=EncryptedSerializer.class) 
@JsonDeserialize(using=EncryptedDeserializer.class) 
public interface EncryptedType {} 

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.FIELD) 
public @interface EncryptedField {} 

アイデアは、クラスがにマッチするように、空のインターフェイスを実装するということですカスタムser/deserは、フィールドを反射的に見つけ、注釈が付いている場合はその魔法を実行します。直列化ステップは、魔法のように動作し、私のような出力文字列を取得: {」TYPE ":" のType1" 、 "encryptedField": "aGAzLwT47gE/QNlUuAhnJg =="、 "unencryptedField": "平文"}

しかし、復号化はひどいです。私はそれを働かせることはできません:多形性と解読を組み合わせるために実装すべきものがわかりません。

@JsonDeserializeアノテーションを削除して、ジャクソンにそれをさせても、正しくポリモフィックではなく暗号化されたフィールドでデシリアライズされます。カスタムデシリアライザを使用しようとすると、NPEからすべての種類のエラーが発生します。あなたはどのよう

  • 戻す前に暗号化されたフィールドを持つタイプ情報を使用して知っているよう

    1. ジャクソンは、(私はインスタンス上で私の復号化をやらせる、この事をデシリアライズ:私は私のデシリアライザで達成したいことは何かに似ています正確に入力する必要はなく、私は反射を通してアクセスすることができます)。

      public class EncryptedDeserializer extends StdDeserializer<EncryptedType> { 
      [..super etc..] 
      
      
      @Override 
      public EncryptedType deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { 
          return null; 
      } 
      
      @Override 
      public EncryptedType deserializeWithType(JsonParser p, DeserializationContext ctxt, 
           TypeDeserializer typeDeserializer) throws IOException { 
          EncryptedType newInstance = super.deserializeWithType(p, ctxt, typeDeserializer); 
      
          Field[] fields = newInstance.getClass().getDeclaredFields(); 
          for (Field field : fields) { 
           if (field.isAnnotationPresent(EncryptedField.class)) { 
            boolean accessibility = field.isAccessible(); 
            field.setAccessible(true); 
            try { 
             field.set(newInstance, ApplicationContextRegister.getApplicationContext().getBean(TextEncryptionService.class).decrypt((String) field.get(newInstance))); 
            } catch (Exception e) { 
             log.error("Could not decryption field " + field.getName() + " of " + newInstance + ". Skipping decryption"); 
            } 
            field.setAccessible(accessibility); 
           } 
          } 
          return newInstance; 
      } 
      

      しかし、これはエラーで失敗するかEncryptedDeserializer文句はデフォルト(引数なし)コンストラクタを持っていないか、私は本当にさまざまなオプションを試してみましたが、私は得ることに保つ:ここ

  • は、私がこれまで持っているものです立ち往生した。

    +0

    githubのjackson-cryptoはこれを行いますが、少し異なる出力を生成します。 Beanの直列化修飾子を使用して、他の(シ)シリアライザをラップします。これのコードはここにあります(https://github.com/meltmedia/jackson-crypto/tree/develop/src/main/java/com/meltmedia/jackson/crypto)。 –

    答えて

    0

    推測したとおり、多型のためには@JsonTypeInfoのものが必要です。

    カスタムデシリアライザは、暗号化ロジックを実現する1つの方法です。必要に応じて、逆シリアル化のコンストラクタで@JsonCreatorアノテーションを試してみてください(暗号化ロジックをそこに含めることができます)。@JsonPropertyでカスタマイズされたアノテーションで暗号化が処理されるようにしてください。

    "EncryptedDeserializerにはデフォルト(引数なし)コンストラクタがありません"という固有のエラーに関して - なぜそれを作成しないのですか(たとえそれがprivateであっても)?ジャクソンはこのようなことを、リフレクションによるインスタンス化に使用しています

    +0

    カスタムポリモーフィックデシリアライザ(decrtyptionなし)を実装する方法の例を教えてください。それを行う方法の技術は、私を解読するのではなく、解読することです。コンストラクターの問題は、私が試して達成しなかった多くのものの1つに過ぎません。私はそこに1つを入れる方法を知っていますが、それでも動作しません。私は多形のカスタムデシリアライザをどうやって行うのですか?それは私を止めるものです。 –

    +0

    https://fasterxml.github.io/jackson-databind/javadoc/2.2.0/com/fasterxml/jackson/databind/annotation /JsonDeserialize.html、 '@ JsonDeserialize'は、" setter "のメソッドやフィールド、または値クラスにアタッチすることによって、逆シリアル化の設定に使用されるアノテーションです。私はあなたが抽象クラスにそれを適用できるはずですが、あなたはインターフェイスに直接適用することはできないと思います。 私は実例を思いついてみるつもりです。 – Olaf

    関連する問題