简体   繁体   English

Gson 反序列化对象时忽略 null

[英]Gson ignore null when deserializing object

I want to deserialize a json string that containts a null value in Java.我想反序列化一个包含 Java 空值的 json 字符串。 I want to deserialize the object to a Properties object.我想将对象反序列化为Properties对象。 The json string is something like: json 字符串类似于:

{"prop1":null, "propr2":"fancy value"}

When I deserialize using当我反序列化使用

String json = //
new Gson().fromJson(json, Properties.class);

I get a null pointer exception because of the Hastable that into the Properties object.由于Hastable进入Properties对象,我得到了一个空指针异常。 How can I instruct Gson to ignore deserialization of null values?如何指示 Gson 忽略空值的反序列化?

The problem is indeed that Gson's default adapter tries to put null into the Properties , which is forbidden.问题确实是 Gson 的默认适配器试图将null放入Properties ,这是被禁止的。

To solve this, you could write your own TypeAdapter for Properties .要解决此问题,您可以为Properties编写自己的TypeAdapter You would then have to create Gson instances using a GsonBuilder on which you registered that type adapter.然后,您必须使用注册该类型适配器的GsonBuilder创建 Gson 实例。

The following shows how such an adapter could look.下面显示了这种适配器的外观。 It is slightly more strict in that it prevents non-String keys and values during serialization (which Gson's default adapter does not) since they would cause issues during deserialization.它稍微更严格,因为它在序列化期间防止非字符串键和值(Gson 的默认适配器不会),因为它们会在反序列化期间导致问题。 You could however replace that and delegate serialization to Gson's adapter by using Gson.getDelegateAdapter​ .但是,您可以替换和使用委派系列化GSON的适配器Gson.getDelegateAdapter

private static final TypeAdapter<Properties> PROPERTIES_ADAPTER = new TypeAdapter<Properties>() {
    @Override
    public Properties read(JsonReader in) throws IOException {
        in.beginObject();

        Properties properties = new Properties();
        while (in.hasNext()) {
            String name = in.nextName();
            JsonToken peeked = in.peek();

            // Ignore null values
            if (peeked == JsonToken.NULL) {
                in.nextNull();
                continue;
            }
            // Allow Json boolean
            else if (peeked == JsonToken.BOOLEAN) {
                properties.setProperty(name, Boolean.toString(in.nextBoolean()));
            }
            // Expect string or number
            else {
                properties.setProperty(name, in.nextString());
            }
        }

        in.endObject();
        return properties;
    }

    private String asString(Object obj) {
        if (obj.getClass() != String.class) {
            throw new IllegalArgumentException("Properties contains non-String object " + obj);
        }
        return (String) obj;
    }

    /*
     * Could also delegate to Gson's implementation for serialization.
     * However, that would not fail if the Properties contains non-String values,
     * which would then cause issues when deserializing the Json again. 
     */
    @Override
    public void write(JsonWriter out, Properties properties) throws IOException {
        out.beginObject();

        for (Map.Entry<Object, Object> entry : properties.entrySet()) {
            // Make sure that key is a String, otherwise properties
            // cannot be deserialized again
            out.name(asString(entry.getKey()));

            Object value = entry.getValue();
            // Be lenient and allow Numbers and Booleans as values
            if (value instanceof Number) {
                out.value((Number) value);
            } else if (value instanceof Boolean) {
                out.value((Boolean) value);
            } else {
                // Require that value is a String
                out.value(asString(value));
            }
        }

        out.endObject();
    }

}.nullSafe(); // Handle null Properties, e.g. `Properties props = null`

public static void main(String[] args) throws IOException {
    Gson gson = new GsonBuilder()
        // Register the custom type adapter
        .registerTypeAdapter(Properties.class, PROPERTIES_ADAPTER)
        .create();

    String json = "{\"prop1\":true, \"prop2\":\"text\", \"prop3\":null}";
    Properties deserialized = gson.fromJson(json, Properties.class); 
    System.out.println("Deserialized: " + deserialized);

    Properties properties = new Properties();
    properties.setProperty("prop", "text");
    // Discouraged to put non-Strings, but type adapter supports these
    properties.put("boolean", true);
    properties.put("number", 1234);
    System.out.println("Serialized: " + gson.toJson(properties));
}

We have this solution:我们有这个解决方案:

1. All of your data classes need to extends abstract class 1. 你所有的数据类都需要扩展抽象类

abstract class PoJoClass

2. Create this safe deserializer to delete nulls from JSON 2. 创建这个安全的反序列化器以从 JSON 中删除空值

class SafeDeserializer<T : PoJoClass>(private val gson: Gson) :JsonDeserializer<T> {
    override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): T {

        val jsonObject = json as JsonObject
        removeNullsFromJson(jsonObject)
        return gson.fromJson(jsonObject, typeOfT)
    }

    private fun removeNullsFromJson(jsonObject: JsonObject) {
        val iterator = jsonObject.keySet().iterator()

        while (iterator.hasNext()) {
            val key = iterator.next()
            when(val json = jsonObject[key]){
                is JsonObject -> removeNullsFromJson(json)
                is JsonNull -> iterator.remove()
            }
        }
    }
}

3. And register it in your GSON instance 3. 并在您的 GSON 实例中注册它

val gson = Gson().newBuilder()
                .registerTypeHierarchyAdapter(PoJoClass::class.java, SafeDeserializer<PoJoClass>(Gson()))
                .create()

请参阅http://sites.google.com/site/gson/gson-user-guide#TOC-Null-Object-Support

Gson gson = new GsonBuilder().serializeNulls().create();

错误的反序列化列表<object>与 gson<div id="text_translate"><p> 我用List&lt;Object&gt;调试CUSTOMER object:</p><p> <a href="https://i.stack.imgur.com/Gh2Mx.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Gh2Mx.png" alt="在此处输入图像描述"></a></p><p> 这是 CUSTOMER.class:</p><pre> public class CUSTOMER { @XmlElements({ @XmlElement(name = "ADDRESS", type = ADDRESS.class), @XmlElement(name = "ZIP", type = ZIP.class), @XmlElement(name = "CITY", type = CITY.class), @XmlElement(name = "COUNTRY", type = COUNTRY.class), }) protected List&lt;Object&gt; addressAndZIPAndCITY; // other fields }</pre><p> 但是当我反序列化并从中创建 json 时,它仅包含:</p><pre> { "addressAndZIPAndCITY": [ { "value": "some value", "type": "some type" }, { "value": "some value 2", "type": "some type 2" }] }</pre><p> 缺少 ADRESS、ZIP、CITY 和 COUNTRY 对象标题。 所以反序列化不好。</p><p> 我无法更改List&lt;Object&gt;声明。 是否可以选择将其反序列化为带有 ADRESS、ZIP、CITY 等的 json? 像这样:</p><pre> { "addressAndZIPAndCITY": [{ "ADDRESS": { "value": "some value", "type": "some type" } }, { "ZIP": { "value": "some value 2", "type": "some type 2" } } ] }</pre><p> 编辑:我的意思是它看起来像 GSON 不知道哪个 object 在那里,但可能你知道如何向 model 添加一些注释或其他东西来识别它?</p></div></object> - Wrong deserializing List<Object> with gson

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用 Gson 或 Jackson 反序列化 JSON 时忽略空字段 - Ignore null fields when DEserializing JSON with Gson or Jackson 使用数组反序列化对象会使用 GSON 返回 null,为什么? - Deserializing an object with an array is returning null with GSON, why? 从json字符串反序列化到对象时如何忽略null? - how to ignore null when deserializing from json string to object? Gson重建反序列化对象时丢失数据 - Gson losing data when reconstructing deserializing object GSON将瞬态反序列化为null - GSON Deserializing transients as null gson 将字段反序列化为 null - gson deserializing a field as null 在反序列化空字符串时阻止Gson返回null - Prevent Gson from returning null when deserializing empty strings 反序列化地图 <Object, Object> 与GSon - Deserializing Map<Object, Object> with GSon 当预先知道密钥时,使用gson反序列化JSON对象 - Deserializing a JSON object using gson when keys are now known in advance 错误的反序列化列表<object>与 gson<div id="text_translate"><p> 我用List&lt;Object&gt;调试CUSTOMER object:</p><p> <a href="https://i.stack.imgur.com/Gh2Mx.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Gh2Mx.png" alt="在此处输入图像描述"></a></p><p> 这是 CUSTOMER.class:</p><pre> public class CUSTOMER { @XmlElements({ @XmlElement(name = "ADDRESS", type = ADDRESS.class), @XmlElement(name = "ZIP", type = ZIP.class), @XmlElement(name = "CITY", type = CITY.class), @XmlElement(name = "COUNTRY", type = COUNTRY.class), }) protected List&lt;Object&gt; addressAndZIPAndCITY; // other fields }</pre><p> 但是当我反序列化并从中创建 json 时,它仅包含:</p><pre> { "addressAndZIPAndCITY": [ { "value": "some value", "type": "some type" }, { "value": "some value 2", "type": "some type 2" }] }</pre><p> 缺少 ADRESS、ZIP、CITY 和 COUNTRY 对象标题。 所以反序列化不好。</p><p> 我无法更改List&lt;Object&gt;声明。 是否可以选择将其反序列化为带有 ADRESS、ZIP、CITY 等的 json? 像这样:</p><pre> { "addressAndZIPAndCITY": [{ "ADDRESS": { "value": "some value", "type": "some type" } }, { "ZIP": { "value": "some value 2", "type": "some type 2" } } ] }</pre><p> 编辑:我的意思是它看起来像 GSON 不知道哪个 object 在那里,但可能你知道如何向 model 添加一些注释或其他东西来识别它?</p></div></object> - Wrong deserializing List<Object> with gson
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM