簡體   English   中英

使用 GSON 在 JSON 序列化中包含某個瞬態字段

[英]Include a certain transient field in JSON serialization with GSON

我有這堂課

Myclass
{
  transient String field1;
  transient String field2;
  ... // other non transient fields
}

我存儲序列化對象,以這種方式通過網絡使用它們(不包括瞬態字段)。

但是,僅對於一種特殊情況,我需要在序列化中包含 field2。

有沒有辦法不使用 gson 在序列化中排除某個瞬態字段?

解決方案0:

為類使用自定義類型適配器。

考慮

@JsonAdapter(KA.class)
class K{
    private transient String name;
    private transient String password;
}

class Entity_Adapter extends TypeAdapter<Entity>{
    @Override
    public void write(JsonWriter out, Entity value) throws IOException {
        out.beginObject();
        
        out.name("name");
        out.value(value.getName());
        
        out.name("password");
        out.value(value.getPassword());
        
        out.endObject();
    }

    @Override
    public Entity read(JsonReader in) throws IOException {
        Entity k=new Entity();
        in.beginObject();
        
        in.nextName();
        k.setName(in.nextString());
        
        in.nextName();
        k.setPassword(in.nextString());
        
        in.endObject();
        return k;
    }
}

完整的例子在這里

解決方案1:(不健壯)

添加另一個非transient字段,並始終為其復制field2任何新設置值。 例如

transient String field1;
transient String field2;

@SerializedName("field2")
private String field2_non_trans;

public void setField2(String arg_val){
this.field2 = arg_val;
this.field2_non_trans = arg_val;
}

public String getField2(){
  if(field2 == null){
    field2 = field2_non_trans;
  } 
  return field2;
}

完整樣本在這里

但是您必須跟蹤對該field2每次更改,以始終更新field2_non_trans的 val 副本,因此如果該field2是由構造函數設置的,或者在其setter函數之外,您必須確保為field2_non_trans

對於反序列化,您必須:

  • 一旦反序列化結束,您需要使用方法將field2_non_trans的反序列化值設置為field2
  • 或者簡單地通過getField2()方法返回field2_non_trans ,其中field2null

解決方案2:

將該field2標記為非瞬態。

您可以使用另一個非瞬態字段復制瞬態字段,並從瞬態字段設置器中寫入值。 這個想法是每次瞬態字段更新時更新克隆字段。

盡管由於此類問題,我永遠不會建議對不同的庫使用相同的類,但您可以輕松管理 Gson 將排除策略應用於正在序列化和反序列化的字段的方式。

public final class TransientExclusionStrategy
        implements ExclusionStrategy {

    private static final ExclusionStrategy instance = new TransientExclusionStrategy();

    private TransientExclusionStrategy() {
    }

    public static ExclusionStrategy getInstance() {
        return instance;
    }

    @Override
    public boolean shouldSkipField(final FieldAttributes attributes) {
        @Nullable
        final Expose expose = attributes.getAnnotation(Expose.class);
        if ( expose == null ) {
            return attributes.hasModifier(Modifier.TRANSIENT);
        }
        return !expose.serialize();
    }

    @Override
    public boolean shouldSkipClass(final Class<?> clazz) {
        return false;
    }

}

此實現將通過以下單元測試:

public final class TransientExclusionStrategyTest {

    private static final String EXPOSED = "EXPOSED";
    private static final String IGNORED = "IGNORED";

    @SuppressWarnings("all")
    private static final class MyClass {

        final String s0 = EXPOSED; // no explicit expose, serialized by default

        @Expose(serialize = false)
        final String s1 = IGNORED; // ignored by annotation

        @Expose(serialize = true)
        final String s2 = EXPOSED; // serialized by annotation

        final transient String ts0 = IGNORED; // no explicit expose, ignored by default

        @Expose(serialize = false)
        final transient String ts1 = IGNORED; // ignored by annotation

        @Expose(serialize = true)
        final transient String ts2 = EXPOSED; // serialized by annotation

    }

    @Test
    public void test() {
        final Gson gson = new GsonBuilder()
                .addSerializationExclusionStrategy(TransientExclusionStrategy.getInstance())
                .create();
        final JsonObject json = (JsonObject) gson.toJsonTree(new MyClass());
        for ( final Map.Entry<String, JsonElement> e : json.entrySet() ) {
            final String stringValue = e.getValue().getAsString();
            Assertions.assertEquals(EXPOSED, stringValue, () -> "Expected " + EXPOSED + " but was " + stringValue + " for " + e.getKey());
        }
    }

}

因此,您不需要為每個這樣的“特殊”類處理任何特殊類型的適配器或引入中間字段(這不一定與您正在使用的其他庫和框架處於沖突狀態)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM