[英]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();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.