Джексон десериализует нулевые значения карты в пустую строку - PullRequest
0 голосов
/ 13 декабря 2018

Я пытаюсь найти глобальную ObjectMapper конфигурацию (или любую другую настройку) для всех json Map<String, String>, чтобы десериализовать ее в карту без значений 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

Я знаю, что могу сделать это за POJO, пометив свой класс с помощью @JsonDeserialize(using = MyDeserializer.class), но я хочу, чтобы он работал для всех карт.

Я также пытался настроить это решение для работы с десериализацией, но оно выбрасывает NullPointerException


update: преобразование "ноль в пусто" должноработа только на картах (со строковым значением).(см. обновленный пример выше)

Ответы [ 2 ]

0 голосов
/ 16 декабря 2018

В итоге я применил метод DeserializerModifier следующим образом:

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;
  }
}
0 голосов
/ 14 декабря 2018

Смотри, у меня это работает:

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;
    }
}
...