Как десериализовать пустое значение строки JSON равным null для java.lang.String?
Я пытаюсь простой JSON для де-сериализации в java-объект. Однако я получаю пустые значения String для значений свойства java.lang.String
. В остальной части свойств пустые значения преобразуются в нулевые значения (это то, что я хочу).
Мой JSON и связанный с ним класс Java перечислены ниже.
Строка JSON:
{
"eventId" : 1,
"title" : "sample event",
"location" : ""
}
Класс EventBean POJO:
public class EventBean {
public Long eventId;
public String title;
public String location;
}
Мой основной код:
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
try {
File file = new File(JsonTest.class.getClassLoader().getResource("event.txt").getFile());
JsonNode root = mapper.readTree(file);
// find out the applicationId
EventBean e = mapper.treeToValue(root, EventBean.class);
System.out.println("It is " + e.location);
}
Я ожидал печати "Это нуль". Вместо этого я получаю "Это". Очевидно, что Джексон не обрабатывает пустые значения String как NULL при преобразовании в мой тип объекта String.
Я где-то читал, что это ожидалось. Тем не менее, это то, чего я хочу избежать для java.lang.String тоже. Есть простой способ?
Ответы
Ответ 1
Джексон даст вам null для других объектов, но для String он даст пустую строку.
Но вы можете использовать Custom JsonDeserializer
для этого:
class CustomDeserializer extends JsonDeserializer<String> {
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException, JsonProcessingException {
JsonNode node = jsonParser.readValueAsTree();
if (node.asText().isEmpty()) {
return null;
}
return node.toString();
}
}
В классе вы должны использовать его для поля местоположения:
class EventBean {
public Long eventId;
public String title;
@JsonDeserialize(using = CustomDeserializer.class)
public String location;
}
Ответ 2
Можно определить собственный десериализатор для типа String, переопределив стандартный десериализатор строк:
this.mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(String.class, new StdDeserializer<String>(String.class) {
@Override
public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
String result = StringDeserializer.instance.deserialize(p, ctxt);
if (StringUtils.isEmpty(result)) {
return null;
}
return result;
}
});
mapper.registerModule(module);
Таким образом, все строковые поля будут вести себя одинаково.
Ответ 3
Для тех, кто использует Spring Boot: ответ от jgesser был самым полезным для меня, но я потратил некоторое время, пытаясь разработать лучший способ настроить его в Spring Boot.
Фактически, в документации говорится:
Любые компоненты типа com.fasterxml.jackson.databind.Module автоматически регистрируются с помощью автоконфигурированного Jackson2ObjectMapperBuilder и применяются к любым экземплярам ObjectMapper, которые он создает.
Итак, здесь jgesser answer расширился на то, что вы можете скопировать-вставить в новый класс в приложении Spring Boot
@Configuration
public class EmptyStringAsNullJacksonConfiguration {
@Bean
SimpleModule emptyStringAsNullModule() {
SimpleModule module = new SimpleModule();
module.addDeserializer(
String.class,
new StdDeserializer<String>(String.class) {
@Override
public String deserialize(JsonParser parser, DeserializationContext context)
throws IOException {
String result = StringDeserializer.instance.deserialize(parser, context);
if (StringUtils.isEmpty(result)) {
return null;
}
return result;
}
});
return module;
}
}