Gson:如何在没有注释的情况下从序列化中排除特定字段

发布于 2024-10-14 00:20:37 字数 1533 浏览 3 评论 0原文

我正在努力学习 Gson,但我正在与字段排除作斗争。这是我的类,

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

我可以使用 GsonBuilder 并为 firstNamecountry 等字段名称添加 ExclusionStrategy,但我似乎无法设法排除某些字段的属性,例如国家/地区.名称

使用 public boolean shouldSkipField(FieldAttributes fa) 方法时,FieldAttributes 未包含足够的信息来将字段与 country.name 等过滤器相匹配。

PS:我想避免注释,因为我想改进这一点并使用正则表达式来过滤字段。

编辑:我试图看看是否可以模拟 Struts2 JSON 插件

使用 Gson

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

编辑: 我重新打开了这个问题,添加了以下内容:

我添加了第二个具有相同类型的字段来进一步澄清这个问题。基本上我想排除 country.name 但不排除 countrOfBirth.name。我也不想排除国家作为一种类型。 所以类型是相同的,这是我想要查明和排除的对象图中的实际位置。

I'm trying to learn Gson and I'm struggling with field exclusion. Here are my classes

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

I can use the GsonBuilder and add an ExclusionStrategy for a field name like firstName or country but I can't seem to manage to exclude properties of certain fields like country.name.

Using the method public boolean shouldSkipField(FieldAttributes fa), FieldAttributes doesn't contain enough information to match the field with a filter like country.name.

P.S: I want to avoid annotations since I want to improve on this and use RegEx to filter fields out.

Edit: I'm trying to see if it's possible to emulate the behavior of Struts2 JSON plugin

using Gson

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

Edit:
I reopened the question with the following addition:

I added a second field with the same type to futher clarify this problem. Basically I want to exclude country.name but not countrOfBirth.name. I also don't want to exclude Country as a type.
So the types are the same it's the actual place in the object graph that I want to pinpoint and exclude.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(17

尤怨 2024-10-21 00:20:37

一般情况下,您不希望序列化的任何字段都应该使用“transient”修饰符,这也适用于 json 序列化器(至少它适用于我使用过的一些序列化器,包括 gson)。

如果您不希望名称显示在序列化的 json 中,请给它一个瞬态关键字,例如:

private transient String name;

Gson 文档中的更多详细信息

Any fields you don't want serialized in general you should use the "transient" modifier, and this also applies to json serializers (at least it does to a few that I have used, including gson).

If you don't want name to show up in the serialized json give it a transient keyword, eg:

private transient String name;

More details in the Gson documentation

友谊不毕业 2024-10-21 00:20:37

Nishant 提供了一个很好的解决方案,但还有一种更简单的方法。只需使用 @Expose 注解标记所需的字段,例如:

@Expose private Long id;

忽略任何不想序列化的字段。然后以这种方式创建你的 Gson 对象:

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

Nishant provided a good solution, but there's an easier way. Simply mark the desired fields with the @Expose annotation, such as:

@Expose private Long id;

Leave out any fields that you do not want to serialize. Then just create your Gson object this way:

Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
执手闯天涯 2024-10-21 00:20:37

因此,您想要排除 firstNamecountry.name。这是您的 ExclusionStrategy 的样子。

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

    }

如果您仔细观察,它会为 Student.firstNameCountry.name 返回 true >,这是您要排除的内容。

您需要像这样应用此 ExclusionStrategy

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

这将返回:

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

我假设国家对象是在学生班级中使用 id = 91L 初始化的。


你可能会喜欢。例如,您不想序列化名称中包含“name”字符串的任何字段。执行此操作:

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

这将返回:

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

编辑:根据要求添加了更多信息。

ExclusionStrategy 可以完成此操作,但您需要传递“完全限定字段名称”。见下文:

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

    }

这是我们如何通用地使用它。

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

它返回:

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

So, you want to exclude firstName and country.name. Here is what your ExclusionStrategy should look like

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

    }

If you see closely it returns true for Student.firstName and Country.name, which is what you want to exclude.

You need to apply this ExclusionStrategy like this,

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

This returns:

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

I assume the country object is initialized with id = 91L in student class.


You may get fancy. For example, you do not want to serialize any field that contains "name" string in its name. Do this:

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

This will return:

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

EDIT: Added more info as requested.

This ExclusionStrategy will do the thing, but you need to pass "Fully Qualified Field Name". See below:

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

    }

Here is how we can use it generically.

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

It returns:

{ "firstName": "Philip" , "middleName": "J.", "initials": "P.F", "lastName": "Fry", "country": { "id": 91 }}
早茶月光 2024-10-21 00:20:37

在阅读了所有可用的答案后,我发现,就我而言,最灵活的是使用自定义 @Exclude 注释。因此,我为此实现了简单的策略(我不想使用 @Expose 标记所有字段,也不想使用与应用程序中的 Serialized 冲突的 transient 序列化):

注释:

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

策略:

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

用法:

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

After reading all available answers I found out, that most flexible, in my case, was to use custom @Exclude annotation. So, I implemented simple strategy for this (I didn't want to mark all fields using @Expose nor I wanted to use transient which conflicted with in app Serializable serialization) :

Annotation:

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

Strategy:

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

Usage:

new GsonBuilder().setExclusionStrategies(new AnnotationExclusionStrategy()).create();
半夏半凉 2024-10-21 00:20:37

我遇到了这个问题,其中我只想从序列化中排除少量字段,因此我开发了一个相当简单的解决方案,该解决方案使用 Gson 的 @Expose 注释和自定义排除策略。

使用 @Expose 的唯一内置方法是通过设置 GsonBuilder.excludeFieldsWithoutExposeAnnotation(),但正如名称所示,没有显式 @Expose 的字段代码> 被忽略。由于我只有几个想要排除的字段,因此我发现向每个字段添加注释的前景非常麻烦。

我实际上想要相反的情况,其中包含所有内容,除非我明确使用 @Expose 来排除它。我使用以下排除策略来实现此目的:

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

现在我可以使用 @Expose(serialize = false)@Expose(deserialize = false) 注释轻松排除一些字段(请注意,两个 @Expose 属性的默认值为 true)。您当然可以使用 @Expose(serialize = false, deserialize = false) ,但是通过声明字段 transient 可以更简洁地实现这一点(它仍然在以下情况下生效)这些自定义排除策略)。

I ran into this issue, in which I had a small number of fields I wanted to exclude only from serialization, so I developed a fairly simple solution that uses Gson's @Expose annotation with custom exclusion strategies.

The only built-in way to use @Expose is by setting GsonBuilder.excludeFieldsWithoutExposeAnnotation(), but as the name indicates, fields without an explicit @Expose are ignored. As I only had a few fields I wanted to exclude, I found the prospect of adding the annotation to every field very cumbersome.

I effectively wanted the inverse, in which everything was included unless I explicitly used @Expose to exclude it. I used the following exclusion strategies to accomplish this:

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

Now I can easily exclude a few fields with @Expose(serialize = false) or @Expose(deserialize = false) annotations (note that the default value for both @Expose attributes is true). You can of course use @Expose(serialize = false, deserialize = false), but that is more concisely accomplished by declaring the field transient instead (which does still take effect with these custom exclusion strategies).

我的鱼塘能养鲲 2024-10-21 00:20:37

您可以使用 gson 探索 json 树。

尝试这样的事情:

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

您还可以添加一些属性:

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

使用 gson 2.2.4 进行测试。

You can explore the json tree with gson.

Try something like this :

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

You can add some properties also :

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

Tested with gson 2.2.4.

以为你会在 2024-10-21 00:20:37

我想出了一个类工厂来支持此功能。传递您想要排除的字段或类的任意组合。

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

    }
}

要使用,请创建两个列表(每个列表都是可选的),然后创建 GSON 对象:

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

I came up with a class factory to support this functionality. Pass in any combination of either fields or classes you want to exclude.

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

    }
}

To use, create two lists (each is optional), and create your GSON object:

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);
}
江城子 2024-10-21 00:20:37

我通过自定义注释解决了这个问题。
这是我的“SkipSerialization”注释类:

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

}

这是我的 GsonBuilder:

gsonBuilder.addSerializationExclusionStrategy(new ExclusionStrategy() {

  @Override public boolean shouldSkipField (FieldAttributes f) {

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

  }

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

    return false;
  }
});

示例:

public class User implements Serializable {

  public String firstName;

  public String lastName;

  @SkipSerialisation
  public String email;
}

I solved this problem with custom annotations.
This is my "SkipSerialisation" Annotation class:

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

}

and this is my GsonBuilder:

gsonBuilder.addSerializationExclusionStrategy(new ExclusionStrategy() {

  @Override public boolean shouldSkipField (FieldAttributes f) {

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

  }

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

    return false;
  }
});

Example :

public class User implements Serializable {

  public String firstName;

  public String lastName;

  @SkipSerialisation
  public String email;
}
多孤肩上扛 2024-10-21 00:20:37

Kotlin 的 @Transient 注解显然也能达到这个目的。

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

输出:

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

Kotlin's @Transientannotation also does the trick apparently.

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

Output:

{"serialized_field_1":"VALUE1","serialized_field_2":"VALUE2"}
无可置疑 2024-10-21 00:20:37

或者可以说什么字段不会公开:

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

在您的类属性上:

private **transient** boolean nameAttribute;

Or can say whats fields not will expose with:

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

on your class on attribute:

private **transient** boolean nameAttribute;
一百个冬季 2024-10-21 00:20:37

我使用了这个策略:
我排除了每个标记有@SerializedName注释的字段,即:

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

它返回

{"VisibleValue":"我会看到这个"}

I used this strategy:
i excluded every field which is not marked with @SerializedName annotation, i.e.:

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

It returns

{"VisibleValue":"I will see this"}

捂风挽笑 2024-10-21 00:20:37

另一种方法(如果您需要在运行时决定排除某个字段,则特别有用)是向您的 gson 实例注册 TypeAdapter。下面的示例:

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

在下面的情况下,服务器将期望两个值之一,但由于它们都是整数,因此 gson 会将它们都序列化。我的目标是省略发布到服务器的 json 中任何为零(或更少)的值。

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

Another approach (especially useful if you need to make a decision to exclude a field at runtime) is to register a TypeAdapter with your gson instance. Example below:

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

In the case below, the server would expect one of two values but since they were both ints then gson would serialize them both. My goal was to omit any value that is zero (or less) from the json that is posted to the server.

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;
    }
}
关于从前 2024-10-21 00:20:37

在 kotlin 中可以使用 @Transient 来忽略该字段...例如。

data class MyClass{
@Transient var  myVar: Boolean
//....
}

in kotlin can use @Transient to ignore the field... eg.

data class MyClass{
@Transient var  myVar: Boolean
//....
}
⊕婉儿 2024-10-21 00:20:37

我只是通过添加 @Expose 注释来工作,这里是我

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

在 Model 类中使用的版本:

@Expose
int number;

public class AdapterRestApi {

在 Adapter 类中:

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

I'm working just by putting the @Expose annotation, here my version that I use

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

In Model class:

@Expose
int number;

public class AdapterRestApi {

In the Adapter class:

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);
}
执笔绘流年 2024-10-21 00:20:37

我有 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
    }
}

以及如何将其添加到 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)

I have Kotlin version

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

and how You can add this to 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)
月光色 2024-10-21 00:20:37

这是我经常使用的:

Gson 中实现的默认行为是忽略空对象字段。

意味着 Gson 对象不会将空值字段序列化为 JSON。如果 Java 对象中的某个字段为 null,Gson 会将其排除。

您可以使用此函数将某些对象转换为 null 或由您自己设置

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

This what I always use:

The default behaviour implemented in Gson is that null object fields are ignored.

Means Gson object does not serialize fields with null values to JSON. If a field in a Java object is null, Gson excludes it.

You can use this function to convert some object to null or well set by your own

     /**
   * 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);
  }
无所谓啦 2024-10-21 00:20:37

对缓存对象使用不同的 DTO。

例如,您可以创建 UserCached 类并仅保留您需要的字段。
之后,创建映射器以将对象映射回来并进行映射。四。 Mapstruct 对此很有用。

这种方法可以解决问题,解耦应用程序,并使主 DTO 中的更改更安全。

Use different DTO for cached object.

For example, you can create UserCached class and keep there only fields you need.
After that, create mapper to map objects back & forth. Mapstruct is good for that.

Such approach solves the problem, decouples your application, and makes changes in your primary DTO more safe to make.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文