ลำดับการแจ็กสัน: ละเว้นค่าว่าง (หรือ null)


138

ขณะนี้ฉันกำลังใช้แจ็คสัน 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"}

ฉันจะหลีกเลี่ยงค่า Null เหล่านั้นได้อย่างไร ฉันต้องการรับข้อมูลที่จำเป็นเพื่อการสมัครสมาชิกเท่านั้น!

นี่คือผลลัพธ์ที่ฉันกำลังมองหา:

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

ฉันยังลอง @JsonInclude (Include.NON_NULL) และทำให้ตัวแปรทั้งหมดของฉันเป็นโมฆะ แต่ก็ไม่ได้ผลเช่นกัน! ขอบคุณสำหรับความช่วยเหลือของคุณ!


คำตอบ:


247

คุณมีคำอธิบายประกอบในสถานที่ที่ไม่ถูกต้อง - มันต้องอยู่ในชั้นเรียนไม่ใช่ในสนาม เช่น:

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


ไม่มีวิธีที่จะทำให้คำอธิบายประกอบแบบรวม NON_NULL ทำงานหรือไม่ หรือหนึ่ง NON_EMTPY เพราะฉันรู้ว่าอันไหนจะเป็นโมฆะ แต่ขึ้นอยู่กับสถานการณ์ ฉันใช้คลาส "JsonOperation" เดียวกันสำหรับทุกวัตถุที่ฉันต้องการทำให้เป็นอนุกรม / ดีซีเรียลไลซ์และฉันก็แค่เริ่มต้นตัวแปรที่ฉันต้องใช้ขึ้นอยู่กับสถานการณ์ นี่เป็นวิธีที่ดีในการทำหรือฉันควรจะตัดคลาสที่มีเฉพาะตัวแปรที่ฉันต้องการ (ด้วยวิธีที่ฉันไม่ต้องใช้คำอธิบายประกอบใด ๆ เนื่องจากจะไม่มีตัวแปรว่างเปล่า / ว่างเปล่า)
Shinnyx

26
ไวยากรณ์มีการเปลี่ยนแปลงในเวอร์ชันล่าสุดเป็น @JsonSerialize (รวมถึง = JsonSerialize.Inclusion.NON_NULL) และ @JsonSerialize (รวมถึง = JsonSerialize.Inclusion.NON_EMPTY หากคุณต้องการทั้งที่ไม่ใช่โมฆะและไม่ว่างเปล่าให้ใช้ @JsonSerialize.Inclusion.NON_NULL) .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.x" ไม่ใช่ "ในเวอร์ชัน 2.x +"
WestFarmer

2
2. + ใช้@JsonInclude(Include.NON_NULL)
Honghe.Wu


15

นอกจากนี้คุณสามารถลองใช้

@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)

หากคุณกำลังจัดการกับแจ็คสันที่มีเวอร์ชันต่ำกว่า 2+ (1.9.5) ฉันทดสอบแล้วคุณสามารถใช้คำอธิบายประกอบนี้ได้อย่างง่ายดายเหนือชั้นเรียน ไม่ได้ระบุไว้สำหรับแอททริบิวต์เพียงคลาส decleration


2
รวมถึงคุณลักษณะของ 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 (Jersey) จัดการกับสถานการณ์นี้ 2.6 ขึ้นไปโดยอัตโนมัติ


มีฟังก์ชั่นที่คล้ายกันเมื่อใช้แพ็คเกจ org.codehaus.jackson.annotate เก่าหรือไม่
pkran

ใช่คุณสามารถเพิ่มด้านบนของวิธีการทะเลาะเช่นส่วนตัว int id; @JsonIgnore public int getId () {return id; }
vaquar khan

1
เช่นเดียวกับคำตอบที่มีอยู่
Karl Richter


2

ฉันมีปัญหาที่คล้ายกันเมื่อเร็ว ๆ นี้กับรุ่น 2.6.6

@JsonInclude(JsonInclude.Include.NON_NULL)

การใช้คำอธิบายประกอบด้านบนไม่ว่าจะเป็นในระดับที่ยื่นหรือระดับที่ไม่ทำงานตามที่คาด POJO ไม่แน่นอนที่ฉันใช้การเพิ่มความคิดเห็น เมื่อฉันเปลี่ยนพฤติกรรมของ POJO ให้ไม่เปลี่ยนแปลงคำอธิบายประกอบนั้นใช้เวทย์มนตร์ของมัน

ฉันไม่แน่ใจว่ามันลงไปเป็นเวอร์ชั่นใหม่หรือเวอร์ชั่นก่อนหน้าของ lib นี้มีพฤติกรรมคล้ายกันหรือไม่ แต่สำหรับ 2.6.6 แน่นอนคุณต้องมี POJO ที่ไม่เปลี่ยนรูปเพื่อให้คำอธิบายประกอบทำงานได้

objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

ตัวเลือกข้างต้นที่กล่าวถึงในคำตอบต่าง ๆ ของการตั้งค่าการรวมเป็นอนุกรมใน ObjectMapper โดยตรงในระดับโลกทำงานได้ดี แต่ฉันชอบการควบคุมที่ระดับหรือระดับยื่น

ดังนั้นหากคุณต้องการให้เขตข้อมูล null ทั้งหมดถูกละเว้นในขณะที่การทำให้เป็นอันดับ 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
เช่นเดียวกับคำตอบที่มีอยู่
Karl Richter
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.