Gson在反序列化对象时忽略空值

jm81lzqq  于 2022-11-06  发布在  其他
关注(0)|答案(3)|浏览(467)

我想在Java中反序列化一个包含空值的json字符串。我想将该对象反序列化为Properties对象。json字符串如下所示:

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

当我使用

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

我得到了一个空指针异常,因为Hastable进入了Properties对象。我如何指示Gson忽略空值的反序列化?

cgh8pdjw

cgh8pdjw1#

问题确实是Gson的默认适配器试图将null放入Properties,这是被禁止的。
要解决这个问题,可以为Properties编写自己的TypeAdapter,然后必须使用注册了该类型适配器的GsonBuilder创建Gson示例。
下面显示了这样一个适配器的外观。它稍微严格一点,因为它在序列化过程中阻止非String键和值(Gson的默认适配器不这样做),因为它们会在反序列化过程中导致问题。但是,您可以使用Gson.getDelegateAdapter替换它,并将序列化委托给Gson的适配器。

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));
}
s4n0splo

s4n0splo2#

我们有这样的解决方案:

1.您的所有数据类都需要扩展抽象类

abstract class PoJoClass

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.并将其注册到GSON示例中

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

kyks70gy3#

请访问http://sites.google.com/site/gson/gson-user-guide#TOC-Null-Object-Support:
Gson gson = new GsonBuilder().serializeNulls().create();

相关问题