Nextrp [CPP] RU + Many GEOs Игра на карте России | NEXTRP

Gson: Как исключить определенные поля из сериализации без аннотаций

java json serialization gson

268471 просмотра

13 ответа

20024 Репутация автора

Я пытаюсь узнать Гссона, и я борюсь с полевыми исключениями. Вот мои классы

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 для фильтрации полей.

Спасибо

Edit : Я пытаюсь понять, можно ли эмулировать поведение плагина 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. Я также не хочу исключать страну как тип. Таким образом, типы одинаковы, это фактическое место в графе объектов, которое я хочу точно определить и исключить.

Автор: Liviu T. Источник Размещён: 26.01.2011 09:19

Ответы (13)


210 плюса

40577 Репутация автора

Итак, вы хотите исключить firstName и country.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"));
        }

    }

Если вы видите близко он возвращается trueк Student.firstNameи Country.name, что то , что вы хотите исключить.

Вам нужно применить это 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", "инициалы": "ПФ", "LastName": "Фрай", "страна": { "ID": 91}}

Я предполагаю, что объект страны инициализируется id = 91Lв классе ученика.


Вы можете получить фантазию. Например, вы не хотите сериализовать любое поле, содержащее «имя» в его имени. Сделай это:

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

Это вернет:

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

EDIT: добавлено больше информации по запросу.

Это 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 }}
Автор: Nishant Размещён: 26.01.2011 10:13

567 плюса

5777 Репутация автора

Любые поля, которые вы не хотите сериализовать в целом, должны использовать модификатор «переходный», и это также относится к сериализаторам json (по крайней мере, это относится к нескольким, которые я использовал, включая gson).

Если вы не хотите, чтобы имя отображалось в сериализованном json, дайте ему ключевое слово переходного процесса, например:

private transient String name;

Более подробная информация в документации Gson

Автор: Chris Seline Размещён: 04.05.2011 08:40

293 плюса

5170 Репутация автора

Нишант обеспечил хорошее решение, но есть более простой способ. Просто пометьте нужные поля аннотацией @Expose, например:

@Expose private Long id;

Оставьте все поля, которые вы не хотите сериализовать. Затем просто создайте объект Gson таким образом:

Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
Автор: JayPea Размещён: 18.10.2011 05:26

16 плюса

3527 Репутация автора

Я придумал фабрику классов для поддержки этой функциональности. Передайте любую комбинацию полей или классов, которые вы хотите исключить.

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);
}
Автор: Domenic D. Размещён: 26.04.2012 06:03

9 плюса

1177 Репутация автора

Или можете сказать, что поля не будут отображаться:

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

на свой класс по атрибуту:

private **transient** boolean nameAttribute;
Автор: lucasddaniel Размещён: 02.06.2013 08:42

73 плюса

1415 Репутация автора

Я столкнулся с этой проблемой, в которой у меня было небольшое количество полей, которые я хотел исключить только из сериализации, поэтому я разработал довольно простое решение, которое использует @Exposeаннотацию Gson с пользовательскими стратегиями исключения.

Единственный встроенный способ использования @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вместо этого (которое все еще вступает в силу с этими пользовательскими стратегиями исключения).

Автор: Derek Shockey Размещён: 18.07.2013 08:46

15 плюса

167 Репутация автора

Вы можете исследовать дерево json с помощью gson.

Попробуйте что-то вроде этого:

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

Вы также можете добавить некоторые свойства:

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

Протестировано с помощью gson 2.2.4.

Автор: Klaudia Rzewnicka Размещён: 06.02.2014 08:16

180 плюса

2816 Репутация автора

Прочитав все доступные ответы, я узнал, что наиболее гибким, в моем случае, было использование пользовательской @Excludeаннотации. Итак, я реализовал простую стратегию для этого (я не хотел отмечать все поля, использующие @Exposeи не хотел использовать, с transientкоторыми столкнулся в Serializableсериализации приложений ):

Аннотация:

@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();
Автор: pkk Размещён: 16.01.2015 03:04

6 плюса

6542 Репутация автора

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

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;
    }
}
Автор: Damian Размещён: 27.08.2015 01:53

5 плюса

400 Репутация автора

Я использовал эту стратегию: я исключил все поля, которые не отмечены аннотацией @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": "Я увижу это"}

Автор: MadMurdok Размещён: 20.07.2016 12:15

13 плюса

900 Репутация автора

Я решил эту проблему с помощью специальных аннотаций. Это мой класс аннотации «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;
}
Автор: Reyske Размещён: 12.09.2016 09:35

0 плюса

11 Репутация автора

Я работаю, просто помещая @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);
}
Автор: devitoper Размещён: 31.03.2017 04:26

0 плюса

1305 Репутация автора

У меня есть версия 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)
Автор: Michał Ziobro Размещён: 23.11.2018 09:50
Вопросы из категории :
32x32