有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Jackson反序列化将空值映射为空字符串

我试图为所有json Map<String, String>找到一个全局ObjectMapper配置(或任何其他定制),以便反序列化到没有null值的映射中(应该有一个空字符串)

例如

class MyClass {
  Map<String, String> dict;

  String str;

  public MyClass() {
  }

  public MyClass(Map<String, String> dict, String str) {
    this.dict = dict;
    this.str = str;
  }

  public Map<String, String> getDict() {
    return dict;
  }

  public String getStr() {
    return str;
  }
}
...

final Map<String, String> dict = new HashMap<>();
dict.put("k1", "v1");
dict.put("k2", null);
final MyClass myClass = new MyClass(dict);
final String valueAsString = objectMapper.writeValueAsString(myClass);
final MyClass deserialized = objectMapper.readValue(valueAsString, MyClass.class);
deserialized.getDict().get("k2"); // = "" (empty String)
deserialized.getStr(); // = null

我知道我可以通过用@JsonDeserialize(using = MyDeserializer.class)注释我的类来实现每个POJO 但我希望它对所有地图都有效

我还试图调整这个solution来实现反序列化,但它抛出NullPointerException


更新:“null到empty”转换只需要在映射上工作(使用字符串值)。(见上面更新的示例)


共 (2) 个答案

  1. # 1 楼答案

    看,这对我有用:

    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    
    import org.junit.Test;
    
    import com.fasterxml.jackson.core.JsonGenerator;
    import com.fasterxml.jackson.databind.JsonSerializer;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.SerializerProvider;
    import com.fasterxml.jackson.databind.ser.DefaultSerializerProvider;
    
    public class TestTest {
    
        @Test
        public void test_Map_null_EmptyString_() throws IOException {    
            ObjectMapper mapper = new ObjectMapper();
            DefaultSerializerProvider sp = new DefaultSerializerProvider.Impl();
            sp.setNullValueSerializer(new NullSerializer());
            mapper.setSerializerProvider(sp);
    
            final Map<String, String> dict = new HashMap<>();
            dict.put("k1", "v1");
            dict.put("k2", null);
            final MyClass myClass = new MyClass(dict);
            final String valueAsString = mapper.writeValueAsString(myClass);
            System.out.println(valueAsString);
            final MyClass deserialized = mapper.readValue(valueAsString, MyClass.class);
            System.out.println(deserialized.getDict().get("k2")); // = "" (empty String)
        }
    
        public class NullSerializer extends JsonSerializer<Object> {
            public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
                jgen.writeString("");
            }
        }
    }
    
    class MyClass {
        Map<String, String> dict;
    
        public MyClass() {
        }
    
        public MyClass(Map<String, String> dict) {
            this.dict = dict;
        }
    
        public Map<String, String> getDict() {
            return dict;
        }
    }
    
  2. # 2 楼答案

    我最终使用了反序列化修改器技术,如下所示:

    static class MapCustomDeserializerModifier extends BeanDeserializerModifier {
    
      @Override
      public JsonDeserializer<?> modifyMapDeserializer(DeserializationConfig config, MapType type, BeanDescription beanDesc, JsonDeserializer<?> deserializer {
    
        final JsonDeserializer<?> jsonDeserializer = super.modifyMapDeserializer(config, type, beanDesc, deserializer);
        if (type.getKeyType().isTypeOrSubTypeOf(String.class) && type.getContentType().isTypeOrSubTypeOf(String.class)) {
          return new MapCustomDeserializer();
        }
    
        return jsonDeserializer;
      }
    
    }
    
    static class MapCustomDeserializer extends JsonDeserializer<Map<String, String>> {
    
      @Override
      public Map<String, String> deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
    
        final Map<String, String> map = jsonParser.readValueAs(Map.class);
    
        if (map != null) {
          map.replaceAll((key, value) -> Strings.nullToEmpty(value));
        }
        return map;
      }
    }