Serialización de Jackson: ignorar valores vacíos (o nulos)

138

Actualmente estoy usando jackson 2.1.4 y tengo problemas para ignorar los campos cuando estoy convirtiendo un objeto en una cadena JSON.

Aquí está mi clase que actúa como el objeto a 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;
    }
}
}

Y así es como lo convierto:

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())

Aquí está la salida:

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

¿Cómo puedo evitar esos valores nulos? ¡Solo quiero tomar la información requerida para el propósito de "suscripción"!

Aquí está exactamente el resultado que estoy buscando:

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

También probé @JsonInclude (Include.NON_NULL) y puse todas mis variables en nulo, ¡pero tampoco funcionó! ¡Gracias por su ayuda chicos!

Shinnyx
fuente

Respuestas:

247

Tiene la anotación en el lugar equivocado: debe estar en la clase, no en el campo. es decir:

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

Como se señaló en los comentarios, en las versiones inferiores a 2.x la sintaxis para esta anotación es:

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

La otra opción es configurar el ObjectMapperdirectamente, simplemente llamando mapper.setSerializationInclusion(Include.NON_NULL);

(para el registro, creo que la popularidad de esta respuesta es una indicación de que esta anotación debería ser aplicable campo por campo, @fasterxml)

dibujó más
fuente
Realmente no hay forma de hacer que la anotación include.NON_NULL funcione? ¿O el NON_EMTPY? Porque sé cuál será nulo, pero depende de la situación. Estoy usando la misma clase "JsonOperation" para cada objeto que quiero serializar / deserializar y solo estoy inicializando las variables que necesito usar dependiendo de la situación. ¿Es esta una buena manera de hacerlo o debería hacer varias clases que contienen solo las variables que necesito (de esa manera no tendría que usar ninguna anotación, ya que nunca habrá una variable nula / vacía)
Shinnyx
26
La sintaxis ha cambiado en la versión más reciente a @JsonSerialize (include = JsonSerialize.Inclusion.NON_NULL) y @JsonSerialize (include = JsonSerialize.Inclusion.NON_EMPTY Si necesita tanto no nulo como no vacío, use @JsonSerialize (include = JsonSerialize .Inclusion.NON_DEFAULT)
Maciej
1
Use @JsonSerialize (include = Inclusion.NON_NULL) antes de la clase o antes de la propiedad que funcionó ...
cisne
1
@drewmoore, por favor verifique nuevamente, @JsonInclude(JsonSerialize.Inclusion.NON_NULL) debería ser @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)y también es la antigua forma obsoleta. por lo que debe escribir "en la versión inferior a 2.x", no "en la versión 2.x +"
WestFarmer
2
2. + uso@JsonInclude(Include.NON_NULL)
Honghe.Wu
48

También puede configurar la opción global:

objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
nómada
fuente
15

También puedes intentar usar

@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)

Si está tratando con Jackson con una versión inferior a 2+ (1.9.5) que lo probé, puede usar fácilmente esta anotación por encima de la clase. No se especifica para los atributos, solo para la declinación de clase.

erhanasikoglu
fuente
2
incluir atributo de JsonSerialize es obsoleto a favor de JsonInclude
fd8s0
2
como dije: con jackson con versión inferior a 2+ (1.9.5)
erhanasikoglu
la pregunta se refiere a una versión particular 2.1.4
fd8s0
14

Necesitas agregar import com.fasterxml.jackson.annotation.JsonInclude;

Añadir

@JsonInclude(JsonInclude.Include.NON_NULL)

encima de POJO

Si ha anidado POJO entonces

@JsonInclude(JsonInclude.Include.NON_NULL)

Es necesario agregar todos los valores.

NOTA: JAXRS (Jersey) maneja automáticamente este escenario 2.6 y superior.

Vaquar Khan
fuente
¿Existe una funcionalidad similar al usar el antiguo paquete org.codehaus.jackson.annotate?
pkran
Sí, puede agregar encima del ejemplo del método getter private int id; @JsonIgnore public int getId () {return id; }
vaquar khan
1
Igual que las respuestas existentes
Karl Richter
4

Para jackson 2.x

@JsonInclude(JsonInclude.Include.NON_NULL)

justo antes del campo.

Gere
fuente
2
Igual que las respuestas existentes
Karl Richter
2

Estaba teniendo un problema similar recientemente con la versión 2.6.6.

@JsonInclude(JsonInclude.Include.NON_NULL)

El uso de la anotación anterior ya sea en el nivel archivado o de clase no funcionaba como se esperaba. El POJO era mutable donde estaba aplicando la anotación. Cuando cambié el comportamiento del POJO para que fuera inmutable, la anotación funcionó mágicamente.

No estoy seguro de si su versión anterior o las versiones anteriores de esta lib tuvieron un comportamiento similar, pero para 2.6.6 ciertamente necesita tener POJO inmutable para que la anotación funcione.

objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

La opción anterior mencionada en varias respuestas de configurar la inclusión de serialización en ObjectMapper directamente a nivel global también funciona, pero prefiero controlarla a nivel de clase o archivado.

Entonces, si desea que se ignoren todos los campos nulos durante la serialización JSON, use la anotación a nivel de clase, pero si desea que solo se ignoren algunos campos en una clase, úsela sobre esos campos específicos. De esta manera, es más fácil de leer y fácil de mantener si desea cambiar el comportamiento para obtener una respuesta específica.

Amrut
fuente
2

O puede usar GSON [ https://code.google.com/p/google-gson/ ], donde estos campos nulos se eliminarán automáticamente.

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

SALIDA:

{"isLoggedIn":false}

Yo solía GSON-2.2.4

anij
fuente
-1

El siguiente código puede ayudar si desea excluir el tipo booleano de la serialización:

@JsonInclude(JsonInclude.Include.NON_ABSENT)
Alejandro
fuente
1
Igual que las respuestas existentes
Karl Richter