Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Gson在反序列化对象时忽略null_Java_Json_Gson_Deserialization - Fatal编程技术网

Java Gson在反序列化对象时忽略null

Java Gson在反序列化对象时忽略null,java,json,gson,deserialization,Java,Json,Gson,Deserialization,我想反序列化一个json字符串,该字符串在Java中包含空值。我想将对象反序列化为Properties对象。json字符串类似于: {"prop1":null, "propr2":"fancy value"} 当我使用 String json = // new Gson().fromJson(json, Properties.class); 我得到一个空指针异常,因为Hastable进入Properties对象。如何指示Gson忽略空值的反序列化?请参阅: Gson Gson=new Gso

我想反序列化一个json字符串,该字符串在Java中包含空值。我想将对象反序列化为
Properties
对象。json字符串类似于:

{"prop1":null, "propr2":"fancy value"}
当我使用

String json = //
new Gson().fromJson(json, Properties.class);
我得到一个空指针异常,因为
Hastable
进入
Properties
对象。如何指示Gson忽略空值的反序列化?

请参阅:

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

我们有以下解决方案:

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()
            }
        }
    }
}
类安全反序列化器(private val gson:gson):JsonDeserializer{
重写有趣的反序列化(json:JsonElement?、typeOfT:Type?、context:JsonDeserializationContext?):T{
val jsonObject=json作为jsonObject
removeNullsFromJson(jsonObject)
返回gson.fromJson(jsonObject,typeOfT)
}
private fun removeNullsFromJson(jsonObject:jsonObject){
val iterator=jsonObject.keySet().iterator()
while(iterator.hasNext()){
val key=iterator.next()
当(val json=jsonObject[key]){
是JsonObject->removeNullsFromJson(json)
是JsonNull->iterator.remove()
}
}
}
}
3。并在您的GSON实例中注册它

val gson = Gson().newBuilder()
                .registerTypeHierarchyAdapter(PoJoClass::class.java, SafeDeserializer<PoJoClass>(Gson()))
                .create()
val gson=gson().newBuilder()
.registerTypeHierarchyAdapter(PoJoClass::class.java,安全反序列化器(Gson())
.create()

问题确实在于Gson的默认适配器试图将
null
放入
属性中,这是被禁止的

要解决这个问题,您可以为
属性
编写自己的。然后,您必须使用
GsonBuilder
创建Gson实例,在该实例上输入适配器

下面显示了这样一个适配器的外观。更严格的是,它在序列化过程中防止非字符串键和值(Gson的默认适配器不这样做),因为它们在反序列化过程中会导致问题。但是,您可以使用替换它并将序列化委托给Gson的适配器

private static final TypeAdapter PROPERTIES\u ADAPTER=new TypeAdapter(){
@凌驾
公共属性读取(JsonReader in)引发IOException{
in.beginObject();
属性=新属性();
while(在.hasNext()中){
String name=in.nextName();
JsonToken peek=in.peek();
//忽略空值
if(peek==JsonToken.NULL){
in.nextNull();
继续;
}
//允许Json布尔值
else if(peek==JsonToken.BOOLEAN){
setProperty(名称,Boolean.toString(in.nextBoolean());
}
//应为字符串或数字
否则{
setProperty(名称,在.nextString()中);
}
}
in.endObject();
归还财产;
}
私有字符串关联(对象obj){
if(obj.getClass()!=String.class){
抛出新的IllegalArgumentException(“属性包含非字符串对象”+obj);
}
返回(字符串)对象;
}
/*
*还可以委托给Gson的实现进行序列化。
*但是,如果属性包含非字符串值,则不会失败,
*这将导致再次反序列化Json时出现问题。
*/
@凌驾
public void write(JsonWriter out,Properties)抛出IOException{
out.beginObject();
对于(Map.Entry:properties.entrySet()){
//确保键是字符串,否则为属性
//无法再次反序列化
out.name(asString(entry.getKey());
对象值=entry.getValue();
//要宽容,允许数字和布尔值作为值
if(值instanceof Number){
输出值((数字)值);
}else if(布尔值实例){
out.value((布尔)值);
}否则{
//要求该值为字符串
out.value(asString(value));
}
}
out.endObject();
}
}.nullSafe();//处理null属性,例如`Properties props=null`
公共静态void main(字符串[]args)引发IOException{
Gson Gson=new GsonBuilder()
//注册自定义类型适配器
.registerTypeAdapter(Properties.class,Properties\u适配器)
.create();
字符串json=“{\'prop1\':true,\'prop2\':\'text\',\'prop3\':null}”;
属性反序列化=gson.fromJson(json,Properties.class);
System.out.println(“反序列化:+反序列化”);
属性=新属性();
属性。设置属性(“属性”、“文本”);
//不鼓励放置非字符串,但类型适配器支持这些
properties.put(“布尔”,true);
物业。出售(“编号”,1234);
System.out.println(“序列化:+gson.toJson(属性));
}

这是用于序列化的。我需要反序列化我看到它是用于序列化的,但我想反序列化也会起作用。假设gson产生了一些可以再次反序列化的东西,我也遇到了同样的问题,即使是使用自定义反序列化程序。我可以检查空值,但这需要很多检查。api中有什么可以用来检查属性是否存在以及值是否为非空值的内容吗?有时我认为提供属性扩展会更简单。@mat_boy您介意将标题更改为“在反序列化属性对象时Gson忽略空值”之类的内容吗?因为这似乎就是你的问题所在。忽略
null
值通常是可能的
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));
}