我在努力学习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,并为字段名如firstName或country添加一个ExclusionStrategy,但我似乎无法排除某些字段的属性,如country.name。

使用方法public boolean shouldSkipField(FieldAttributes fa), FieldAttributes不包含足够的信息来匹配像country.name这样的过滤器。

附注:我想避免使用注释,因为我想改进这一点,并使用RegEx过滤字段。

编辑:我试着看看是否有可能模拟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。我也不想把Country排除在外。 所以类型是一样的我想要精确定位和排除的对象图中的实际位置。


当前回答

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

例如,您可以创建UserCached类并只保留您需要的字段。 之后,创建映射器来来回映射对象。Mapstruct在这方面做得很好。

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

其他回答

Kotlin的@Transientannotation显然也能做到这一点。

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

一般来说,任何你不想序列化的字段都应该使用“transient”修饰符,这也适用于json序列化器(至少对我使用过的一些json序列化器是这样,包括gson)。

如果你不想name出现在序列化的json中,给它一个transient关键字,例如:

private transient String name;

更多细节请参阅Gson文档

我只是把@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);
}

另一种方法(当您需要在运行时决定是否排除某个字段时尤其有用)是向您的gson实例注册TypeAdapter。在下面的例子:

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

在下面的例子中,服务器将期望两个值中的一个,但由于它们都是int型,因此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;
    }
}

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

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