Gson: Как исключить определенные поля из сериализации без аннотаций - PullRequest
396 голосов
/ 26 января 2011

Я пытаюсь выучить 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 и добавить ExclusionStrategy для имени поля, например firstName или country, но мне не удается исключить свойства определенных полей, таких как country.name.

Используя метод public boolean shouldSkipField(FieldAttributes fa), FieldAttributes не содержит достаточно информации, чтобы сопоставить поле с фильтром, подобным country.name.

. Буду признателен за любую помощь с решением дляэта проблема.

PS: я хочу избежать аннотаций, поскольку я хочу улучшить это и использовать RegEx для фильтрации полей.

Спасибо

Редактировать : я пытаюсь понять, возможно ли имитировать поведение JSON-плагина Struts2

с использованием Gson

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

Редактировать: Я вновь открыл вопрос со следующим дополнением:

Я добавил второе поле того же типа, чтобы еще больше прояснить эту проблему.В основном я хочу исключить country.name, но не countrOfBirth.name.Я также не хочу исключать страну как тип.Таким образом, типы совпадают, это фактическое место в графе объектов, которое я хочу точно определить и исключить.

Ответы [ 15 ]

6 голосов
/ 27 августа 2015

Другой подход (особенно полезный, если вам необходимо принять решение об исключении поля во время выполнения) - это регистрация TypeAdapter в вашем экземпляре gson. Пример ниже:

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;
    }
}
2 голосов
/ 30 декабря 2018

Замечание Котлина @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"}
1 голос
/ 23 ноября 2018

У меня есть версия 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
    }
}

и как вы можете добавить это в модификацию 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)
1 голос
/ 31 марта 2017

Я работаю, просто добавив аннотацию @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);
}
0 голосов
/ 09 апреля 2019

Это то, что я всегда использую:

Поведение по умолчанию, реализованное в 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);
  }
...