Sérialisation Jackson: ignorez les valeurs vides (ou nulles)

139

J'utilise actuellement jackson 2.1.4 et j'ai du mal à ignorer les champs lorsque je convertis un objet en chaîne JSON.

Voici ma classe qui fait office d'objet à convertir:

public class JsonOperation {

public static class Request {
    @JsonInclude(Include.NON_EMPTY)
    String requestType;
    Data data = new Data();

    public static class Data {
        @JsonInclude(Include.NON_EMPTY)
        String username;
        String email;
        String password;
        String birthday;
        String coinsPackage;
        String coins;
        String transactionId;
        boolean isLoggedIn;
    }
}

public static class Response {
    @JsonInclude(Include.NON_EMPTY)
    String requestType = null;
    Data data = new Data();

    public static class Data {
        @JsonInclude(Include.NON_EMPTY)
        enum ErrorCode { ERROR_INVALID_LOGIN, ERROR_USERNAME_ALREADY_TAKEN, ERROR_EMAIL_ALREADY_TAKEN };
        enum Status { ok, error };

        Status status;
        ErrorCode errorCode;
        String expiry;
        int coins;
        String email;
        String birthday;
        String pictureUrl;
        ArrayList <Performer> performer;
    }
}
}

Et voici comment je le convertis:

ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);

JsonOperation subscribe = new JsonOperation();

subscribe.request.requestType = "login";

subscribe.request.data.username = "Vincent";
subscribe.request.data.password = "test";


Writer strWriter = new StringWriter();
try {
    mapper.writeValue(strWriter, subscribe.request);
} catch (JsonGenerationException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (JsonMappingException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

Log.d("JSON", strWriter.toString())

Voici le résultat:

{"data":{"birthday":null,"coins":null,"coinsPackage":null,"email":null,"username":"Vincent","password":"test","transactionId":null,"isLoggedIn":false},"requestType":"login"}

Comment éviter ces valeurs nulles? Je ne veux prendre les informations requises que dans le but «d'abonnement»!

Voici exactement la sortie que je recherche:

{"data":{"username":"Vincent","password":"test"},"requestType":"login"}

J'ai aussi essayé @JsonInclude (Include.NON_NULL) et mis toutes mes variables à null, mais cela n'a pas fonctionné non plus! Merci pour votre aide les gars!

Shinnyx
la source

Réponses:

247

Vous avez l'annotation au mauvais endroit - elle doit être sur la classe, pas sur le champ. c'est à dire:

@JsonInclude(Include.NON_NULL) //or Include.NON_EMPTY, if that fits your use case 
public static class Request {
  // ...
}

Comme indiqué dans les commentaires, dans les versions inférieures à 2.x, la syntaxe de cette annotation est:

@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) // or JsonSerialize.Inclusion.NON_EMPTY

L'autre option est de configurer le ObjectMapperdirectement, simplement en appelant mapper.setSerializationInclusion(Include.NON_NULL);

(pour mémoire, je pense que la popularité de cette réponse est une indication que cette annotation devrait être applicable champ par champ, @fasterxml)

dessiné moore
la source
Il n'y a vraiment aucun moyen de faire fonctionner l'annotation include.NON_NULL? Ou celui NON_EMTPY? Parce que je sais lequel sera nul, mais cela dépend de la situation. J'utilise la même classe "JsonOperation" pour chaque objet que je veux sérialiser / désérialiser et je n'initialise que les variables que je dois utiliser en fonction de la situation. Est-ce un bon moyen de le faire ou je devrais faire plusieurs classes contenant uniquement les variables dont j'ai besoin (de cette façon, je n'aurais pas à utiliser d'annotation, car il n'y aura jamais de variable nulle / vide)
Shinnyx
26
La syntaxe a changé dans la version la plus récente en @JsonSerialize (include = JsonSerialize.Inclusion.NON_NULL) et @JsonSerialize (include = JsonSerialize.Inclusion.NON_EMPTY Si vous avez besoin à la fois de non-null et non-empty, utilisez @JsonSerialize (include = JsonSerialize .Inclusion.NON_DEFAULT)
Maciej
1
Utilisez @JsonSerialize (include = Inclusion.NON_NULL) avant la classe ou avant la propriété, cela a fonctionné ...
swan
1
@drewmoore s'il vous plaît vérifier à nouveau, @JsonInclude(JsonSerialize.Inclusion.NON_NULL) devrait être @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)et c'est aussi l'ancienne méthode obsolète. vous devriez donc écrire "dans la version inférieure à 2.x", pas "dans la version 2.x +"
WestFarmer
2
2. + utilisation@JsonInclude(Include.NON_NULL)
Honghe.Wu
48

Vous pouvez également définir l'option globale:

objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
nomade
la source
15

Vous pouvez également essayer d'utiliser

@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)

si vous avez affaire à jackson avec une version inférieure à 2+ (1.9.5) je l'ai testé, vous pouvez facilement utiliser cette annotation au-dessus de la classe. Pas pour spécifié pour les attributs, juste pour la déclération de classe.

Erhanasikoglu
la source
2
L'attribut include de JsonSerialize est obsolète en faveur de JsonInclude
fd8s0
2
comme je l'ai dit: avec jackson avec version inférieure à 2+ (1.9.5)
erhanasikoglu
la question porte sur une version particulière 2.1.4
fd8s0
14

Vous devez ajouter import com.fasterxml.jackson.annotation.JsonInclude;

Ajouter

@JsonInclude(JsonInclude.Include.NON_NULL)

au dessus de POJO

Si vous avez imbriqué POJO,

@JsonInclude(JsonInclude.Include.NON_NULL)

besoin d'ajouter toutes les valeurs.

REMARQUE: JAXRS (Jersey) gère automatiquement ce scénario 2.6 et supérieur.

vaquar khan
la source
existe-t-il une fonctionnalité similaire lors de l'utilisation de l'ancien package org.codehaus.jackson.annotate?
pkran
Oui, vous pouvez ajouter en haut de l'exemple de méthode getter private int id; @JsonIgnore public int getId () {return id; }
vaquar khan
1
Identique aux réponses existantes
Karl Richter
4

Pour jackson 2.x

@JsonInclude(JsonInclude.Include.NON_NULL)

juste avant le terrain.

Gere
la source
2
Identique aux réponses existantes
Karl Richter
2

J'avais un problème similaire récemment avec la version 2.6.6.

@JsonInclude(JsonInclude.Include.NON_NULL)

L'utilisation de l'annotation ci-dessus au niveau du fichier ou de la classe ne fonctionnait pas comme prévu. Le POJO était modifiable là où j'appliquais l'annotation. Quand j'ai changé le comportement du POJO pour qu'il soit immuable, l'annotation a fait sa magie.

Je ne suis pas sûr que la nouvelle version ou les versions précédentes de cette bibliothèque aient un comportement similaire, mais pour la version 2.6.6, vous devez certainement avoir un POJO immuable pour que l'annotation fonctionne.

objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

L'option ci-dessus mentionnée dans diverses réponses sur la définition de l'inclusion de la sérialisation dans ObjectMapper directement au niveau mondial fonctionne également, mais je préfère la contrôler au niveau de la classe ou du fichier.

Donc, si vous voulez que tous les champs nuls soient ignorés lors de la sérialisation JSON, utilisez l'annotation au niveau de la classe, mais si vous voulez que seuls quelques champs soient ignorés dans une classe, utilisez-la sur ces champs spécifiques. De cette façon, il est plus lisible et facile à entretenir si vous souhaitez changer de comportement pour une réponse spécifique.

Amrut
la source
2

Vous pouvez également utiliser GSON [ https://code.google.com/p/google-gson/ ], où ces champs nuls seront automatiquement supprimés.

SampleDTO.java

public class SampleDTO {

    String username;
    String email;
    String password;
    String birthday;
    String coinsPackage;
    String coins;
    String transactionId;
    boolean isLoggedIn;

    // getters/setters
}

Test.java

import com.google.gson.Gson;

public class Test {

    public static void main(String[] args) {
        SampleDTO objSampleDTO = new SampleDTO();
        Gson objGson = new Gson();
        System.out.println(objGson.toJson(objSampleDTO));
    }
}

PRODUCTION:

{"isLoggedIn":false}

J'ai utilisé gson-2.2.4

anij
la source
-1

Le code ci-dessous peut vous aider si vous souhaitez exclure le type booléen de la sérialisation:

@JsonInclude(JsonInclude.Include.NON_ABSENT)
Alexandre
la source
1
Identique aux réponses existantes
Karl Richter