Gson ignore null when deserializing object

前端 未结 3 1599
清歌不尽
清歌不尽 2021-01-02 08:13

I want to deserialize a json string that containts a null value in Java. I want to deserialize the object to a Properties object. The json string is something l

3条回答
  •  死守一世寂寞
    2021-01-02 08:19

    The problem is indeed that Gson's default adapter tries to put null into the Properties, which is forbidden.

    To solve this, you could write your own TypeAdapter for Properties. You would then have to create Gson instances using a GsonBuilder on which you registered that type adapter.

    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. You could however replace that and delegate serialization to Gson's adapter by using Gson.getDelegateAdapter​.

    private static final TypeAdapter PROPERTIES_ADAPTER = new TypeAdapter() {
        @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 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));
    }
    

提交回复
热议问题