![](/img/trans.png)
[英]Ignore null fields when DEserializing JSON with Gson or Jackson
[英]Gson ignore null when deserializing object
我想反序列化一个包含 Java 空值的 json 字符串。 我想将对象反序列化为Properties
对象。 json 字符串类似于:
{"prop1":null, "propr2":"fancy value"}
当我反序列化使用
String json = //
new Gson().fromJson(json, Properties.class);
由于Hastable
进入Properties
对象,我得到了一个空指针异常。 如何指示 Gson 忽略空值的反序列化?
问题确实是 Gson 的默认适配器试图将null
放入Properties
,这是被禁止的。
要解决此问题,您可以为Properties
编写自己的TypeAdapter
。 然后,您必须使用注册该类型适配器的GsonBuilder
创建 Gson 实例。
下面显示了这种适配器的外观。 它稍微更严格,因为它在序列化期间防止非字符串键和值(Gson 的默认适配器不会),因为它们会在反序列化期间导致问题。 但是,您可以替换和使用委派系列化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));
}
我们有这个解决方案:
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()
请参阅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.