我想反序列化一个包含Java中空值的json字符串。我想将对象反序列化为Properties
对象。 json字符串类似于:
{"prop1":null, "propr2":"fancy value"}
使用
进行反序列化时String json = //
new Gson().fromJson(json, Properties.class);
由于进入Hastable
对象的Properties
,我得到一个空指针异常。如何指示Gson忽略空值的反序列化?
答案 0 :(得分:0)
我们有以下解决方案:
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()
答案 1 :(得分:0)
问题确实是Gson的默认适配器试图将null
放入Properties
中,这是禁止的。
要解决此问题,您可以为Properties
编写自己的TypeAdapter
。然后,您将不得不使用registered在其上键入适配器的GsonBuilder
创建Gson实例。
下面显示了这样的适配器的外观。稍微严格一点是因为它会在序列化过程中防止非字符串键和值(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));
}
答案 2 :(得分:-4)
请参阅http://sites.google.com/site/gson/gson-user-guide#TOC-Null-Object-Support:
Gson gson = new GsonBuilder().serializeNulls().create();