Gson: Cách loại trừ các trường cụ thể khỏi Tuần tự hóa mà không cần chú thích


413

Tôi đang cố gắng học Gson và tôi đang vật lộn với loại trừ trường. Đây là lớp học của tôi

public class Student {    
  private Long                id;
  private String              firstName        = "Philip";
  private String              middleName       = "J.";
  private String              initials         = "P.F";
  private String              lastName         = "Fry";
  private Country             country;
  private Country             countryOfBirth;
}

public class Country {    
  private Long                id;
  private String              name;
  private Object              other;
}

Tôi có thể sử dụng GsonBuilder và thêm ExinatingStrargety cho một tên trường như firstNamehoặc countrynhưng dường như tôi không thể quản lý để loại trừ các thuộc tính của các trường nhất định như country.name.

Sử dụng phương thức public boolean shouldSkipField(FieldAttributes fa), FieldAttribution không chứa đủ thông tin để khớp trường với bộ lọc như thế nào country.name.

PS: Tôi muốn tránh các chú thích vì tôi muốn cải thiện điều này và sử dụng RegEx để lọc các trường.

Chỉnh sửa : Tôi đang cố gắng xem liệu có thể mô phỏng hành vi của plugin Struts2 JSON không

sử dụng Gson

<interceptor-ref name="json">
  <param name="enableSMD">true</param>
  <param name="excludeProperties">
    login.password,
    studentList.*\.sin
  </param>
</interceptor-ref>

Chỉnh sửa: Tôi mở lại câu hỏi với phần bổ sung sau:

Tôi đã thêm một trường thứ hai với cùng loại để làm rõ hơn vấn đề này. Về cơ bản tôi muốn loại trừ country.namenhưng không countrOfBirth.name. Tôi cũng không muốn loại trừ Quốc gia thành một loại. Vì vậy, các loại giống nhau, đó là vị trí thực tế trong biểu đồ đối tượng mà tôi muốn xác định và loại trừ.


1
Vẫn là phiên bản 2.2 Tôi vẫn không thể chỉ định đường dẫn đến trường để loại trừ. flexjson.sourceforge.net cảm thấy như một sự thay thế tốt.
Liviu T.

Hãy xem câu trả lời của tôi cho một câu hỏi tương tự. Nó dựa trên việc tạo một tùy chỉnh JsonSerializercho một số loại - Countrytrong trường hợp của bạn - sau đó được áp dụng một trường ExclusionStrategyquyết định những trường nào sẽ tuần tự hóa.
hải tặc

Câu trả lời:


625

Bất kỳ trường nào bạn không muốn tuần tự hóa nói chung, bạn nên sử dụng công cụ sửa đổi "tạm thời" và điều này cũng áp dụng cho trình xê-ri json (ít nhất là đối với một số mà tôi đã sử dụng, bao gồm cả gson).

Nếu bạn không muốn tên xuất hiện trong json nối tiếp, hãy đặt cho nó một từ khóa thoáng qua, ví dụ:

private transient String name;

Thêm chi tiết trong tài liệu Gson


6
nó gần giống như một chú thích loại trừ như trong nó áp dụng cho tất cả các phiên bản của lớp đó. Tôi muốn loại trừ năng động thời gian chạy. Tôi một số trường hợp tôi muốn một số trường bị loại trừ để cung cấp phản hồi nhẹ hơn / bị hạn chế và trong các trường hợp khác tôi muốn toàn bộ đối tượng được tuần tự hóa
Liviu T.

34
Một điều cần lưu ý là các hiệu ứng thoáng qua cả tuần tự hóa và giải tuần tự hóa. Nó cũng sẽ phát ra giá trị từ được tuần tự hóa vào đối tượng, ngay cả khi nó có trong JSON.
Kong

3
Vấn đề với việc sử dụng transientthay vì @Exposelà bạn vẫn phải giả lập POJO trên máy khách của mình với tất cả các trường có thể có thể tham gia. Trong trường hợp API back-end có thể được chia sẻ giữa các dự án, trong trường hợp này có thể có vấn đề các lĩnh vực bổ sung được thêm vào. Về cơ bản, nó là danh sách trắng so với danh sách đen của các lĩnh vực.
theblang

11
Cách tiếp cận này không hiệu quả với tôi, vì nó không chỉ loại trừ trường khỏi tuần tự hóa gson, mà còn loại trừ trường khỏi tuần tự hóa ứng dụng nội bộ (sử dụng giao diện Nối tiếp).
pkk

8
thoáng qua ngăn chặn SERIALIZATION và MÔ TẢ một lĩnh vực. Điều này không phù hợp với nhu cầu của tôi.
Loenix 20/07/2015

318

Nishant cung cấp một giải pháp tốt, nhưng có một cách dễ dàng hơn. Chỉ cần đánh dấu các trường mong muốn bằng chú thích @Expose, chẳng hạn như:

@Expose private Long id;

Để lại bất kỳ trường nào mà bạn không muốn tuần tự hóa. Sau đó, chỉ cần tạo đối tượng Gson của bạn theo cách này:

Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();

95
Có thể có một cái gì đó như "notExpose" và chỉ bỏ qua những cái đó cho trường hợp tất cả ngoại trừ một trường phải được tuần tự hóa và thêm chú thích cho tất cả chúng là dư thừa?
Daniil Shevelev

2
@DaSh Gần đây tôi có một kịch bản như vậy. Rất dễ dàng để viết một ExinatingStrargety tùy chỉnh đã làm chính xác điều đó. Xem câu trả lời của Nishant. Vấn đề duy nhất là bao gồm một loạt các lớp container và fiddle với Skipgroup vs Skipfield (các trường có thể là các lớp ...)
keyer

1
@DaSh Câu trả lời của tôi dưới đây thực hiện chính xác điều đó.
Derek Sh Racer

Thật là một giải pháp tuyệt vời. Tôi đã chạy vào một kịch bản trong đó tôi muốn một trường được tuần tự hóa vào đĩa nhưng bị bỏ qua khi gửi nó đến một máy chủ thông qua gson. Hoàn hảo, cảm ơn!
Slynk

1
@Danlil Bạn sẽ có thể sử dụng @Expose (serialize = false, deserialize = false)
Hrk

237

Vì vậy, bạn muốn loại trừ firstNamecountry.name. Đây là những gì bạn ExclusionStrategynên trông như thế nào

    public class TestExclStrat implements ExclusionStrategy {

        public boolean shouldSkipClass(Class<?> arg0) {
            return false;
        }

        public boolean shouldSkipField(FieldAttributes f) {

            return (f.getDeclaringClass() == Student.class && f.getName().equals("firstName"))||
            (f.getDeclaringClass() == Country.class && f.getName().equals("name"));
        }

    }

Nếu bạn thấy chặt chẽ nó sẽ trả về truecho Student.firstNameCountry.name , đó là những gì bạn muốn loại trừ.

Bạn cần áp dụng ExclusionStrategynhư thế này,

    Gson gson = new GsonBuilder()
        .setExclusionStrategies(new TestExclStrat())
        //.serializeNulls() <-- uncomment to serialize NULL fields as well
        .create();
    Student src = new Student();
    String json = gson.toJson(src);
    System.out.println(json);

Điều này trả về:

{ "middleName": "J.", "initials": "P.F", "lastName": "Fry", "country": { "id": 91}}

Tôi giả sử đối tượng quốc gia được khởi tạo id = 91Ltrong lớp học sinh.


Bạn có thể nhận được ưa thích. Ví dụ: bạn không muốn tuần tự hóa bất kỳ trường nào có chứa chuỗi "tên" trong tên của nó. Làm cái này:

public boolean shouldSkipField(FieldAttributes f) {
    return f.getName().toLowerCase().contains("name"); 
}

Điều này sẽ trở lại:

{ "initials": "P.F", "country": { "id": 91 }}

EDIT: Đã thêm thông tin theo yêu cầu.

Điều này ExclusionStrategysẽ làm điều đó, nhưng bạn cần phải vượt qua "Tên trường đủ điều kiện". Xem bên dưới:

    public class TestExclStrat implements ExclusionStrategy {

        private Class<?> c;
        private String fieldName;
        public TestExclStrat(String fqfn) throws SecurityException, NoSuchFieldException, ClassNotFoundException
        {
            this.c = Class.forName(fqfn.substring(0, fqfn.lastIndexOf(".")));
            this.fieldName = fqfn.substring(fqfn.lastIndexOf(".")+1);
        }
        public boolean shouldSkipClass(Class<?> arg0) {
            return false;
        }

        public boolean shouldSkipField(FieldAttributes f) {

            return (f.getDeclaringClass() == c && f.getName().equals(fieldName));
        }

    }

Đây là cách chúng ta có thể sử dụng nó một cách khái quát.

    Gson gson = new GsonBuilder()
        .setExclusionStrategies(new TestExclStrat("in.naishe.test.Country.name"))
        //.serializeNulls()
        .create();
    Student src = new Student();
    String json = gson.toJson(src);
    System.out.println(json); 

Nó trở lại:

{ "firstName": "Philip" , "middleName": "J.", "initials": "P.F", "lastName": "Fry", "country": { "id": 91 }}

Cảm ơn bạn đã trả lời. Điều tôi muốn là tạo ra một country.nameEx LoạiStrargety có thể lấy một chuỗi như và chỉ loại trừ trường namekhi tuần tự hóa trường country. Nó phải đủ chung chung để áp dụng cho mọi lớp có thuộc tính có tên là quốc gia của lớp Quốc gia. Tôi không muốn tạo Ex Loại trừ Chiến lược cho mọi lớp
Liviu T.

@Liviu T. Tôi đã cập nhật câu trả lời. Đó là cách tiếp cận chung chung. Bạn có thể thậm chí còn sáng tạo hơn, nhưng tôi giữ nó nguyên tố.
Nishant

Ty cho cập nhật. Những gì tôi đang cố gắng xem liệu có thể biết tôi đang ở đâu trong biểu đồ đối tượng không khi tôi gọi phương thức đó để tôi có thể loại trừ một số trường của quốc gia nhưng không phải là countryOfBirth (ví dụ) cùng một lớp nhưng thuộc tính khác nhau. Tôi đã chỉnh sửa câu hỏi của mình để làm rõ những gì tôi đang cố gắng đạt được
Liviu T.

Có cách nào để loại trừ các trường có giá trị trống không?
Yusuf K.

12
Câu trả lời này nên được đánh dấu là câu trả lời ưa thích. Không giống như các câu trả lời khác hiện có nhiều phiếu bầu hơn, giải pháp này không yêu cầu bạn phải sửa đổi lớp bean. Đây là một điểm cộng rất lớn. Điều gì sẽ xảy ra nếu người khác đang sử dụng cùng một lớp bean và bạn đã đánh dấu một trường mà họ muốn duy trì là "tạm thời"?
dùng64141

221

Sau khi đọc tất cả các câu trả lời có sẵn, tôi phát hiện ra rằng, linh hoạt nhất, trong trường hợp của tôi, là sử dụng @Excludechú thích tùy chỉnh . Vì vậy, tôi đã thực hiện chiến lược đơn giản cho việc này (tôi không muốn đánh dấu tất cả các trường bằng cách sử dụng @Exposecũng không muốn sử dụng transientxung đột trong ứng dụngSerializable tuần tự hóa ):

Chú thích:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Exclude {
}

Chiến lược:

public class AnnotationExclusionStrategy implements ExclusionStrategy {

    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return f.getAnnotation(Exclude.class) != null;
    }

    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return false;
    }
}

Sử dụng:

new GsonBuilder().setExclusionStrategies(new AnnotationExclusionStrategy()).create();

16
Như một lưu ý bổ sung, nếu bạn muốn sử dụng chiến lược loại trừ của mình chỉ để tuần tự hóa hoặc chỉ addSerializationExclusionStrategyaddDeserializationExclusionStrategysetExclusionStrategies
khử lưu huỳnh

9
Hoàn hảo! Giải pháp tạm thời không hiệu quả với tôi vì tôi đang sử dụng Realm cho DB và tôi muốn loại trừ một trường chỉ từ Gson, nhưng không phải Realm (tạm thời không hoạt động)
Marcio Granzotto

3
Đây phải là câu trả lời được chấp nhận. Để bỏ qua các trường null, chỉ cần thay đổi f.getAnnotation(Exclude.class) != nullthànhf.getAnnotation(Exclude.class) == null
Sharp Edge

3
Tuyệt vời khi bạn không thể sử dụng transientvì nhu cầu của các thư viện khác. Cảm ơn!
Martin D

1
Cũng tuyệt vời đối với tôi vì Android tuần tự hóa các lớp của tôi giữa các hoạt động, nhưng tôi chỉ muốn loại trừ chúng khi tôi sử dụng GSON. Điều này hãy để ứng dụng của tôi tiếp tục hoạt động theo cùng một cách cho đến khi nó muốn gói chúng lại để gửi cho người khác.
ThePartyTurtle

81

Tôi gặp phải vấn đề này, trong đó tôi có một số ít trường tôi chỉ muốn loại trừ khỏi việc xê-ri hóa, vì vậy tôi đã phát triển một giải pháp khá đơn giản sử dụng @Exposechú thích của Gson với các chiến lược loại trừ tùy chỉnh.

Cách tích hợp duy nhất để sử dụng @Exposelà bằng cách cài đặt GsonBuilder.excludeFieldsWithoutExposeAnnotation(), nhưng như tên cho biết, các trường không có tường minh@Expose sẽ bị bỏ qua. Vì tôi chỉ có một vài lĩnh vực mà tôi muốn loại trừ, tôi thấy triển vọng của việc thêm chú thích vào mọi lĩnh vực rất cồng kềnh.

Tôi thực sự muốn nghịch đảo, trong đó mọi thứ được bao gồm trừ khi tôi sử dụng rõ ràng @Expose để loại trừ nó. Tôi đã sử dụng các chiến lược loại trừ sau đây để thực hiện điều này:

new GsonBuilder()
        .addSerializationExclusionStrategy(new ExclusionStrategy() {
            @Override
            public boolean shouldSkipField(FieldAttributes fieldAttributes) {
                final Expose expose = fieldAttributes.getAnnotation(Expose.class);
                return expose != null && !expose.serialize();
            }

            @Override
            public boolean shouldSkipClass(Class<?> aClass) {
                return false;
            }
        })
        .addDeserializationExclusionStrategy(new ExclusionStrategy() {
            @Override
            public boolean shouldSkipField(FieldAttributes fieldAttributes) {
                final Expose expose = fieldAttributes.getAnnotation(Expose.class);
                return expose != null && !expose.deserialize();
            }

            @Override
            public boolean shouldSkipClass(Class<?> aClass) {
                return false;
            }
        })
        .create();

Bây giờ tôi có thể dễ dàng loại trừ một vài trường có @Expose(serialize = false)hoặc @Expose(deserialize = false)chú thích (lưu ý rằng giá trị mặc định cho cả hai @Exposethuộc tính là true). Tất nhiên bạn có thể sử dụng @Expose(serialize = false, deserialize = false), nhưng điều đó được thực hiện chính xác hơn bằng cách khai báo trường transientthay thế (điều này vẫn có hiệu lực với các chiến lược loại trừ tùy chỉnh này).


Để hiệu quả, tôi có thể thấy một trường hợp sử dụng @Expose (serialize = false, deserialize = false) thay vì tạm thời.
paiego

1
@paiego Bạn có thể mở rộng về điều đó? Bây giờ tôi đã bị loại bỏ khỏi việc sử dụng Gson nhiều năm và tôi không hiểu tại sao chú thích lại hiệu quả hơn là đánh dấu nó thoáng qua.
Derek Sh Racer 23/8/18

Ahh, tôi đã làm sai, cảm ơn vì đã nắm bắt điều này. Tôi nhầm lẫn dễ bay hơi cho thoáng qua. (ví dụ: Không có bộ nhớ đệm và do đó không có vấn đề liên kết bộ đệm với biến động, nhưng nó ít hiệu suất hơn) Dù sao, mã của bạn đã hoạt động rất tốt!
paiego

18

Bạn có thể khám phá cây json với gson.

Hãy thử một cái gì đó như thế này:

gson.toJsonTree(student).getAsJsonObject()
.get("country").getAsJsonObject().remove("name");

Bạn cũng có thể thêm một số thuộc tính:

gson.toJsonTree(student).getAsJsonObject().addProperty("isGoodStudent", false);

Đã thử nghiệm với gson 2.2.4.


3
Tôi tự hỏi liệu đây có phải là quá nhiều về hiệu suất nếu bạn muốn loại bỏ một thuộc tính phức tạp phải được phân tích cú pháp trước khi xóa. Suy nghĩ?
Ben

Chắc chắn không phải là một giải pháp có thể mở rộng, hãy tưởng tượng tất cả những vấn đề đau đầu bạn sẽ phải trải qua nếu bạn thay đổi cấu trúc của đối tượng hoặc thêm / xóa công cụ.
codenamezero

16

Tôi đã đưa ra một nhà máy lớp để hỗ trợ chức năng này. Vượt qua trong bất kỳ kết hợp của một trong hai lĩnh vực hoặc các lớp bạn muốn loại trừ.

public class GsonFactory {

    public static Gson build(final List<String> fieldExclusions, final List<Class<?>> classExclusions) {
        GsonBuilder b = new GsonBuilder();
        b.addSerializationExclusionStrategy(new ExclusionStrategy() {
            @Override
            public boolean shouldSkipField(FieldAttributes f) {
                return fieldExclusions == null ? false : fieldExclusions.contains(f.getName());
            }

            @Override
            public boolean shouldSkipClass(Class<?> clazz) {
                return classExclusions == null ? false : classExclusions.contains(clazz);
            }
        });
        return b.create();

    }
}

Để sử dụng, hãy tạo hai danh sách (mỗi danh sách là tùy chọn) và tạo đối tượng GSON của bạn:

static {
 List<String> fieldExclusions = new ArrayList<String>();
 fieldExclusions.add("id");
 fieldExclusions.add("provider");
 fieldExclusions.add("products");

 List<Class<?>> classExclusions = new ArrayList<Class<?>>();
 classExclusions.add(Product.class);
 GSON = GsonFactory.build(null, classExclusions);
}

private static final Gson GSON;

public String getSomeJson(){
    List<Provider> list = getEntitiesFromDatabase();
    return GSON.toJson(list);
}

Tất nhiên, điều này có thể được sửa đổi để xem xét tên đầy đủ của thuộc tính và loại trừ điều đó khi khớp ...
Domenic D.

Tôi đang làm ví dụ dưới đây. Đây không phải là làm việc. Xin đề nghị tĩnh cuối cùng Gson GSON; tĩnh {Danh sách <String> fieldExinating = new ArrayList <String> (); trườngExinating.add ("id"); GSON = GsonFactory.build (trườngExjection, null); } Chuỗi tĩnh riêng getSomeJson () {String jsonStr = "[{\" id \ ": 111, \" name \ ": \" Praveen \ ", \" age \ ": 16}, {\" id \ ": 222, \ "tên \": \ "prashant \", \ "tuổi \": 20}] "; trả về jsonStr; } static static void main (String [] args) {String jsonStr = getSomeJson (); System.out.println (GSON.toJson (jsonStr)); }
Praveen Hiremath

13

Tôi đã giải quyết vấn đề này với các chú thích tùy chỉnh. Đây là lớp chú thích "SkipSerialisation" của tôi:

@Target (ElementType.FIELD)
public @interface SkipSerialisation {

}

và đây là GsonBuilder của tôi:

gsonBuilder.addSerializationExclusionStrategy(new ExclusionStrategy() {

  @Override public boolean shouldSkipField (FieldAttributes f) {

    return f.getAnnotation(SkipSerialisation.class) != null;

  }

  @Override public boolean shouldSkipClass (Class<?> clazz) {

    return false;
  }
});

Thí dụ :

public class User implements Serializable {

  public String firstName;

  public String lastName;

  @SkipSerialisation
  public String email;
}

5
Gson: Cách loại trừ các trường cụ thể khỏi Tuần tự hóa mà không cần chú thích
Ben

3
Bạn cũng nên thêm @Retention(RetentionPolicy.RUNTIME)vào chú thích của bạn.
David Novák

9

Hoặc có thể nói trường whats sẽ không hiển thị với:

Gson gson = gsonBuilder.excludeFieldsWithModifiers(Modifier.TRANSIENT).create();

trên lớp của bạn trên thuộc tính:

private **transient** boolean nameAttribute;

17
Các trường tạm thời và tĩnh được loại trừ theo mặc định; không cần phải gọi excludeFieldsWithModifiers()cho điều đó.
Derek Sh Racer

9

Tôi đã sử dụng chiến lược này: tôi đã loại trừ mọi trường không được đánh dấu bằng chú thích @SerializedName , tức là:

public class Dummy {

    @SerializedName("VisibleValue")
    final String visibleValue;
    final String hiddenValue;

    public Dummy(String visibleValue, String hiddenValue) {
        this.visibleValue = visibleValue;
        this.hiddenValue = hiddenValue;
    }
}


public class SerializedNameOnlyStrategy implements ExclusionStrategy {

    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return f.getAnnotation(SerializedName.class) == null;
    }

    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return false;
    }
}


Gson gson = new GsonBuilder()
                .setExclusionStrategies(new SerializedNameOnlyStrategy())
                .create();

Dummy dummy = new Dummy("I will see this","I will not see this");
String json = gson.toJson(dummy);

Nó trở lại

{"VisibleValue": "Tôi sẽ thấy điều này"}


6

Một cách tiếp cận khác (đặc biệt hữu ích nếu bạn cần đưa ra quyết định loại trừ một trường trong thời gian chạy) là đăng ký TypeAd CHƯƠNG với ví dụ gson của bạn. Ví dụ dưới đây:

Gson gson = new GsonBuilder()
.registerTypeAdapter(BloodPressurePost.class, new BloodPressurePostSerializer())

Trong trường hợp dưới đây, máy chủ sẽ mong đợi một trong hai giá trị nhưng vì cả hai đều là số nguyên nên gson sẽ tuần tự hóa cả hai. Mục tiêu của tôi là bỏ qua bất kỳ giá trị nào bằng 0 (hoặc ít hơn) từ json được đăng lên máy chủ.

public class BloodPressurePostSerializer implements JsonSerializer<BloodPressurePost> {

    @Override
    public JsonElement serialize(BloodPressurePost src, Type typeOfSrc, JsonSerializationContext context) {
        final JsonObject jsonObject = new JsonObject();

        if (src.systolic > 0) {
            jsonObject.addProperty("systolic", src.systolic);
        }

        if (src.diastolic > 0) {
            jsonObject.addProperty("diastolic", src.diastolic);
        }

        jsonObject.addProperty("units", src.units);

        return jsonObject;
    }
}

6

@TransientChú thích của Kotlin cũng thực hiện thủ thuật rõ ràng.

data class Json(
    @field:SerializedName("serialized_field_1") val field1: String,
    @field:SerializedName("serialized_field_2") val field2: String,
    @Transient val field3: String
)

Đầu ra:

{"serialized_field_1":"VALUE1","serialized_field_2":"VALUE2"}

1

Tôi đang làm việc chỉ bằng cách đặt @Exposechú thích, đây là phiên bản mà tôi sử dụng

compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'

Trong Modellớp:

@Expose
int number;

public class AdapterRestApi {

Trong Adapterlớp:

public EndPointsApi connectRestApi() {
    OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(90000, TimeUnit.SECONDS)
            .readTimeout(90000,TimeUnit.SECONDS).build();

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(ConstantRestApi.ROOT_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .client(client)
            .build();

    return retrofit.create  (EndPointsApi.class);
}

1

Tôi có phiên bản Kotlin

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FIELD)
internal annotation class JsonSkip

class SkipFieldsStrategy : ExclusionStrategy {

    override fun shouldSkipClass(clazz: Class<*>): Boolean {
        return false
    }

    override fun shouldSkipField(f: FieldAttributes): Boolean {
        return f.getAnnotation(JsonSkip::class.java) != null
    }
}

và cách bạn có thể thêm phần này vào Retrofit GSONConverterFactory:

val gson = GsonBuilder()
                .setExclusionStrategies(SkipFieldsStrategy())
                //.serializeNulls()
                //.setDateFormat(DateFormat.LONG)
                //.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
                //.setPrettyPrinting()
                //.registerTypeAdapter(Id.class, IdTypeAdapter())
                .create()
        return GsonConverterFactory.create(gson)

0

Đây là những gì tôi luôn luôn sử dụng:

Hành vi mặc định được triển khai trong Gson là các trường đối tượng null bị bỏ qua.

Có nghĩa là đối tượng Gson không tuần tự hóa các trường có giá trị null thành JSON. Nếu một trường trong một đối tượng Java là null, Gson sẽ loại trừ nó.

Bạn có thể sử dụng chức năng này để chuyển đổi một số đối tượng thành null hoặc do chính bạn thiết lập

     /**
   * convert object to json
   */
  public String toJson(Object obj) {
    // Convert emtpy string and objects to null so we don't serialze them
    setEmtpyStringsAndObjectsToNull(obj);
    return gson.toJson(obj);
  }

  /**
   * Sets all empty strings and objects (all fields null) including sets to null.
   *
   * @param obj any object
   */
  public void setEmtpyStringsAndObjectsToNull(Object obj) {
    for (Field field : obj.getClass().getDeclaredFields()) {
      field.setAccessible(true);
      try {
        Object fieldObj = field.get(obj);
        if (fieldObj != null) {
          Class fieldType = field.getType();
          if (fieldType.isAssignableFrom(String.class)) {
            if(fieldObj.equals("")) {
              field.set(obj, null);
            }
          } else if (fieldType.isAssignableFrom(Set.class)) {
            for (Object item : (Set) fieldObj) {
              setEmtpyStringsAndObjectsToNull(item);
            }
            boolean setFielToNull = true;
            for (Object item : (Set) field.get(obj)) {
              if(item != null) {
                setFielToNull = false;
                break;
              }
            }
            if(setFielToNull) {
              setFieldToNull(obj, field);
            }
          } else if (!isPrimitiveOrWrapper(fieldType)) {
            setEmtpyStringsAndObjectsToNull(fieldObj);
            boolean setFielToNull = true;
            for (Field f : fieldObj.getClass().getDeclaredFields()) {
              f.setAccessible(true);
              if(f.get(fieldObj) != null) {
                setFielToNull = false;
                break;
              }
            }
            if(setFielToNull) {
              setFieldToNull(obj, field);
            }
          }
        }
      } catch (IllegalAccessException e) {
        System.err.println("Error while setting empty string or object to null: " + e.getMessage());
      }
    }
  }

  private void setFieldToNull(Object obj, Field field) throws IllegalAccessException {
    if(!Modifier.isFinal(field.getModifiers())) {
      field.set(obj, null);
    }
  }

  private boolean isPrimitiveOrWrapper(Class fieldType)  {
    return fieldType.isPrimitive()
        || fieldType.isAssignableFrom(Integer.class)
        || fieldType.isAssignableFrom(Boolean.class)
        || fieldType.isAssignableFrom(Byte.class)
        || fieldType.isAssignableFrom(Character.class)
        || fieldType.isAssignableFrom(Float.class)
        || fieldType.isAssignableFrom(Long.class)
        || fieldType.isAssignableFrom(Double.class)
        || fieldType.isAssignableFrom(Short.class);
  }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.