J'essaye un simple JSON pour désérialiser en objet Java. Je suis cependant en train de recevoir vide String values pour les valeurs de la propriété Java.lang.String
. Dans le reste des propriétés, les valeurs vierges sont converties en null values (c'est ce que je veux).
Mon JSON et la classe Java associée sont répertoriés ci-dessous.
Chaîne JSON:
{
"eventId" : 1,
"title" : "sample event",
"location" : ""
}
EventBean class POJO:
public class EventBean {
public Long eventId;
public String title;
public String location;
}
Mon code de classe principal:
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);
}
Je m'attendais à imprimer "C'est nul". Au lieu de cela, je reçois "ça l'est". Évidemment, Jackson ne traite pas les valeurs de chaîne vierges comme NULL lors de la conversion en mon type String object.
J'ai lu quelque part que c'est prévu. Cependant, c'est quelque chose que je veux éviter pour Java.lang.String aussi. Y a-t-il un moyen simple?
Jackson vous donnera null pour les autres objets, mais pour String, il donnera String vide.
Mais vous pouvez utiliser une JsonDeserializer
personnalisée pour le faire:
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();
}
}
En classe, vous devez l'utiliser pour le champ de localisation:
class EventBean {
public Long eventId;
public String title;
@JsonDeserialize(using = CustomDeserializer.class)
public String location;
}
Il est possible de définir un désérialiseur personnalisé pour le type String, en remplaçant le désérialiseur String standard:
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);
De cette façon, tous les champs String se comporteront de la même manière.
Vous voudrez peut-être d’abord voir s’il ya eu des progrès sur le problème de Github demandant cette fonctionnalité exacte.
Pour ceux qui utilisent Spring Boot: La réponse de jgesser m'a été la plus utile, mais j'ai passé un certain temps à essayer de trouver le meilleur moyen de le configurer dans Spring Boot.
En fait, la documentation dit:
Tous les beans de type com.fasterxml.jackson.databind.Module sont automatiquement enregistrés avec Avec le Jackson2ObjectMapperBuilder auto-configuré et sont appliqués à toutes les instances ObjectMapper Créées.
Alors voici la réponse de jgesser développée en quelque chose que vous pouvez copier-coller dans une nouvelle classe dans une application 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;
}
}