如何在反序列化对象中保留字段的默认值?

时间:2015-09-10 20:11:13

标签: java json gson

我的情况如下:对象TableC有4个字段。只从JSON字符串中读取3个字段(field_C1field_C2field_C3)。第四个字段field_C4在对象中使用默认值定义。

当我序列化对象实例(用于输出)时 - 它忽略了字段field_C4,我期望默认值为"1""null"。当我明确地将程序中的实例字段的值定义为"NEW"时,它确实将它包含在Json输出字符串中。

查看输出,在反序列化期间创建对象实例时,看起来好像也忽略了构造函数。

激活对象实例的其他字段的最佳做法是什么 - 这些字段未包含在输入Json字符串的反序列化版本中?

package newpackage;
import java.util.List;

import com.google.gson.*;


public class jsonwithconstructor {

   public static void main(String[] args) throws ClassNotFoundException {

    String jsonstring = "{'TableC':["
            + "{'field_C1':'C_11','field_C2':'C_12','field_C3':'C_13'},"
            + "{'field_C1':'C_21','field_C2':'C_22','field_C3':'C_23'}"
            + "]}";

    jsonstring = jsonstring.replace('\'', '"');
    System.out.println(jsonstring); 

    RootObject root = new GsonBuilder().create().fromJson(jsonstring, RootObject.class);

    for (int i=0; i < root.TableC.size(); i++){
        System.out.println(root.TableC.get(i));
    }

    System.out.println();

    //root.TableC.get(0).field_C4 = "NEW";

    for (int i=0; i < root.TableC.size(); i++){
        System.out.println(root.TableC.get(i));
    }
    System.out.println();

    Gson gson = new Gson();

    String jsonoutput = gson.toJson(root);
    System.out.println(jsonoutput); 


}

public class TableC{
    public String field_C1;
    public String field_C2;
    public String field_C3;
    public String field_C4 = "1";

    public TableC(){
        this.field_C4 = "1";
    }

    @Override
    public String toString() {
        return ("TableC" + ", " + this.field_C1 + ", " + this.field_C2 + ", " + this.field_C3 + ", " + this.field_C4);
    }
}
public class RootObject{

    public List<TableC> TableC; 

}

}

输出如下所示:

{"TableC":[{"field_C1":"C_11","field_C2":"C_12","field_C3":"C_13"},{"field_C1":"C_21","field_C2":"C_22","field_C3":"C_23"}]}
TableC, C_11, C_12, C_13, null
TableC, C_21, C_22, C_23, null

TableC, C_11, C_12, C_13, NEW
TableC, C_21, C_22, C_23, null

{"TableC":[{"field_C1":"C_11","field_C2":"C_12","field_C3":"C_13","field_C4":"NEW"},{"field_C1":"C_21","field_C2":"C_22","field_C3":"C_23"}]}

3 个答案:

答案 0 :(得分:2)

这是一个已知的,目前尚未解决的问题:https://github.com/google/gson/issues/513

Gson使用反射构造反序列化对象中的字段值,因此它将仅根据JSON中的内容设置值。在Google为此问题提供修复程序之前,您无法做到这一点。

在此期间,您有许多变通方法对象:

  1. 在getter中包装字段,并lazily load包含值。如果永远不允许某个字段为null,那么这是一种很好的方式(并且我的个人建议),但它们确实需要是可变的。
  2. 将默认字段标记为final。如果它们是不可变的,这是一个很好的方法。
  3. 创建自定义ExclusionStrategy,并使用FieldAttributes标记应忽略的特定字段
    • 这是最通用的选项,但也是最多的代码。
  4. 仅使用不存在的字段对您的POJO进行反序列化,然后使用具有默认值的新数据结构构建该数据结构。
  5. 我同意所有这些都有缺点,但正如我上面所说,这是Gson的一个悬而未决的问题。

答案 1 :(得分:1)

使用Gson v2.7,我可以看到它调用了反序列化对象的默认构造函数,并保留了内部初始化的任何值。但是,我正在使用&#34; new Gson()&#34;而不是&#34; GsonBuilder&#34;,如果这有任何区别。

答案 2 :(得分:0)

我目前在v2.8.5上使用这种方法:

public class Test {
    @SerializedName("f")
    private int foo;
    @SerializedName("b")
    private int bar;

    public Test() {
        bar = -1;    // Uses -1 as default value for bar variable when it's not present in the JSON
    }
    ...
}

并像这样解析它:

Test test = new GsonBuilder().create().fromJson(jsonString, Test.class);