Сериализация Джексона: игнорировать пустые значения (или ноль)


142

В настоящее время я использую jackson 2.1.4, и у меня возникают проблемы с игнорированием полей при преобразовании объекта в строку JSON.

Вот мой класс, который действует как объект, который нужно преобразовать:

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

И вот как я его конвертирую:

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

Вот результат:

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

Как я могу избежать этих нулевых значений? Я хочу взять необходимую информацию только для "подписки"!

Вот именно тот результат, который я ищу:

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

Я также попробовал @JsonInclude (Include.NON_NULL) и поместил все свои переменные в null, но это тоже не сработало! Спасибо за помощь ребята!


Ответы:


254

У вас есть аннотация не в том месте - она ​​должна быть в классе, а не в поле. то есть:

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

Как отмечено в комментариях, в версиях ниже 2.x синтаксис этой аннотации:

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

Другой вариант - настроить ObjectMapperнапрямую, просто позвонив mapper.setSerializationInclusion(Include.NON_NULL);

(для записи, я думаю, что популярность этого ответа является признаком того, что эта аннотация должна применяться для каждого поля, @fasterxml)


Неужели нет способа заставить работать аннотацию include.NON_NULL? Или NON_EMTPY? Потому что я знаю, какой из них будет нулевым, но это зависит от ситуации. Я использую один и тот же класс «JsonOperation» для каждого объекта, который хочу сериализовать / десериализовать, и я инициализирую только те переменные, которые мне нужно использовать в зависимости от ситуации. Это хороший способ сделать это, или я должен сделать несколько классов, содержащих только те переменные, которые мне нужны (в этом случае мне не пришлось бы использовать какую-либо аннотацию, поскольку никогда не будет нулевой / пустой переменной)
Shinnyx

28
В последней версии синтаксис был изменен на @JsonSerialize (include = JsonSerialize.Inclusion.NON_NULL) и @JsonSerialize (include = JsonSerialize.Inclusion.NON_EMPTY) Если вам нужны как ненулевые, так и непустые, используйте @JsonSerialize (include = JsonSerialize .Inclusion.NON_DEFAULT)
Maciej

1
Используйте @JsonSerialize (include = Inclusion.NON_NULL) перед классом или перед тем, как свойство сработало ...
swan

1
@drewmoore, пожалуйста, проверьте еще раз, @JsonInclude(JsonSerialize.Inclusion.NON_NULL) должно быть, @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)и это старый устаревший способ. поэтому вы должны
написать

2
2. + использование@JsonInclude(Include.NON_NULL)
Honghe.Wu 03

48

Вы также можете установить глобальную опцию:

objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

15

Также вы можете попробовать использовать

@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)

Если вы имеете дело с Джексоном с версией ниже 2+ (1.9.5), которую я тестировал, вы можете легко использовать эту аннотацию над классом. Не для указанных атрибутов, только для отмены класса.


2
Атрибут include для JsonSerialize устарел в пользу JsonInclude
fd8s0

2
как я уже сказал: с Джексоном с версией ниже 2+ (1.9.5)
erhanasikoglu

вопрос спрашивает о конкретной версии 2.1.4
fd8s0

14

Вам нужно добавить import com.fasterxml.jackson.annotation.JsonInclude;

Добавить

@JsonInclude(JsonInclude.Include.NON_NULL)

поверх POJO

Если у вас есть вложенный POJO, тогда

@JsonInclude(JsonInclude.Include.NON_NULL)

нужно добавить все значения.

ПРИМЕЧАНИЕ: JAXRS (Джерси) автоматически обрабатывает этот сценарий 2.6 и выше.


есть ли аналогичная функциональность при использовании старого пакета org.codehaus.jackson.annotate?
pkran

Да, вы можете добавить поверх примера метода получения private int id; @JsonIgnore public int getId () {идентификатор возврата; }
vaquar khan

1
То же, что и существующие ответы
Карл Рихтер


2

Недавно у меня была аналогичная проблема с версией 2.6.6.

@JsonInclude(JsonInclude.Include.NON_NULL)

Использование вышеуказанной аннотации на уровне поля или класса не работало должным образом. POJO был изменен там, где я применял аннотацию. Когда я изменил поведение POJO, сделав его неизменным, аннотации сработали.

Я не уверен, что до новой версии или предыдущих версий этой библиотеки было подобное поведение, но для 2.6.6, безусловно, вам понадобится Immutable POJO, чтобы аннотация работала.

objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

Вышеупомянутый вариант, упомянутый в различных ответах о настройке включения сериализации в ObjectMapper непосредственно на глобальном уровне, также работает, но я предпочитаю контролировать его на уровне класса или поля.

Поэтому, если вы хотите, чтобы все пустые поля игнорировались во время сериализации JSON, используйте аннотацию на уровне класса, но если вы хотите, чтобы в классе игнорировалось только несколько полей, используйте ее для этих конкретных полей. Таким образом, он более читабелен и прост в обслуживании, если вы хотите изменить поведение для определенного ответа.


2

Или вы можете использовать GSON [ https://code.google.com/p/google-gson/ ], где эти пустые поля будут автоматически удалены.

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

ВЫХОД:

{"isLoggedIn":false}

Я использовал gson-2.2.4


-1

Приведенный ниже код может помочь, если вы хотите исключить логический тип из сериализации:

@JsonInclude(JsonInclude.Include.NON_ABSENT)

1
То же, что и существующие ответы
Карл Рихтер
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.