【问题标题】:Gson custom type adapter to serialize null on one object type only?Gson 自定义类型适配器仅在一种对象类型上序列化 null?
【发布时间】:2016-04-17 18:50:44
【问题描述】:

我只想为我的 JSON 正文中正在进行 PUT 的一种类型序列化 null。我不想为对象中的任何其他类型序列化空值。我有这样的事情:

public class Patient {
    public Address address;
    public String first_name;
    public String last_name;
}

如果地址为空,我只想序列化地址。比如

Patient patient = new Patient();
patient.address = null;
patient.last_name = "Doe";

看起来像这样:

"address":null,
"last_name":"Doe"

在地址被分配为空的地方,患者被排除在对象之外,因为默认情况下,Gson 不会序列化我想要的空值,并且姓氏保留分配的字符串值。

是否有我可以使用的 Gson 自定义类型适配器?

public class GsonCustomAdapter extends TypeAdapter<Address>

我对这个概念一点也不熟悉,并且一直在尝试理解它。非常感谢任何帮助。

【问题讨论】:

    标签: java json serialization gson


    【解决方案1】:

    如果默认情况下您不想序列化空值,您可以告诉JsonWriter 仅在您实际读取Address 实例时对其进行序列化。

    让我们假设以下类:

    class Address {
        public String country = "UK";
        public String city = "London";
    }
    

    现在我们为Address 类创建一个特定的类型适配器。在这里,您明确表示即使 JsonWriter 不应该在响应中写入 null 值,您也允许它仅为 Address 字段这样做(请参阅代码中的 cmets)。

    class AddressAdapter extends TypeAdapter<Address> {
        @Override
        public void write(JsonWriter out, Address address) throws IOException {
            if (address == null) {
                //if the writer was not allowed to write null values
                //do it only for this field
                if (!out.getSerializeNulls()) {
                    out.setSerializeNulls(true);
                    out.nullValue();
                    out.setSerializeNulls(false);
                } else {
                    out.nullValue();
                }
            } else {
                out.beginObject();
                out.name("country");
                out.value(address.country);
                out.name("city");
                out.value(address.city);
                out.endObject();
            }
        }
    
        @Override
        public Address read(JsonReader in) throws IOException {
            if(in.peek() == JsonToken.NULL) {
                in.nextNull();
                return null;
            }
            in.beginObject();
            Address address = new Address();
            in.nextName();
            address.country = in.nextString();
            in.nextName();
            address.city = in.nextString();
            in.endObject();
            return address;
        }
    }
    

    现在您必须注册此适配器,以便解析器知道他在序列化/反序列化 Address 字段时必须使用它。为此,请使用注解 @JsonAdapter

    class Patient {
        @JsonAdapter(AddressAdapter.class)
        public Address address;
        public String first_name;
        public String last_name;
    }
    

    它已经完成了!

    例如,让我们以您的患者为例:

    Patient patient = new Patient();
    patient.last_name = "Doe";
    

    将解析器设置为序列化空值,您会得到:

    {"address":null,"first_name":null,"last_name":"Doe"}
    

    当你不允许时(默认设置):

    {"address":null,"last_name":"Doe"}
    

    通过为患者设置地址:

    patient.address = new Address();
    ...
    {"address":{"country":"UK","city":"London"},"last_name":"Doe"}
    

    如果您想在 Java 端坚持命名约定,请注意,您可以使用注解 @SerializedName,例如:

    @SerializedName("first_name") public String firstName;
    @SerializedName("last_name")  public String lastName;
    

    希望对您有所帮助! :-)

    【讨论】:

    • 哇。这太棒了
    • 您知道是否可以避免在示例中重新实现 Address 的序列化?我想在地址为空时设置 JsonToken.NULL,否则我想使用内置的 gson 序列化程序正常进行。
    • @Alexis C. 你能提供使用moshi的解决方案吗
    • 谢谢!很好的答案!唯一需要指出的是 out.nullValue() 抛出,在这种情况下 out.setSerializeNulls(false) 永远不会被执行,所以在那里添加一个 finally 子句就可以了。
    猜你喜欢
    • 1970-01-01
    • 2013-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-04
    • 2015-07-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多