serializar recorrer partir objeto manipular leer ejemplos crear convertir con como java json serialization gson

java - recorrer - Gson: cómo excluir campos específicos de la serialización sin anotaciones



manipular json con gson (12)

Cualquier campo que no desee que sea serializado en general, debe usar el modificador "transitorio", y esto también se aplica a los serializadores json (al menos a algunos que he usado, incluido gson).

Si no quieres que aparezca el nombre en el json serializado, dale una palabra clave transitoria, por ejemplo:

private transient String name;

Más detalles en la documentación de Gson.

Estoy tratando de aprender Gson y estoy luchando con la exclusión de campo. Aqui estan mis clases

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

Puedo usar GsonBuilder y agregar una ExclusionStrategy para un nombre de campo como primer nombre o country pero parece que no logro excluir las propiedades de ciertos campos como country.name .

Usando el método public boolean shouldSkipField(FieldAttributes fa) , FieldAttributes no contiene suficiente información para hacer coincidir el campo con un filtro como country.name .

Agradecería cualquier ayuda con una solución para este problema.

PD: quiero evitar las anotaciones ya que quiero mejorar esto y usar RegEx para filtrar los campos.

Gracias

Edición : estoy intentando ver si es posible emular el comportamiento del complemento JSON de Struts2

usando Gson

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

Edición: reabrí la pregunta con la siguiente adición:

Agregué un segundo campo con el mismo tipo para aclarar más este problema. Básicamente quiero excluir country.name pero no countrOfBirth.name . Tampoco quiero excluir País como un tipo. Así que los tipos son los mismos: es el lugar real en el gráfico de objetos que quiero identificar y excluir.


Después de leer todas las respuestas disponibles, descubrí que lo más flexible, en mi caso, era utilizar la anotación personalizada @Exclude . Entonces, implementé una estrategia simple para esto (no quise marcar todos los campos usando @Expose ni quise usar transient que entró en conflicto con la serialización Serializable aplicación):

Anotación:

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

Estrategia:

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

Uso:

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


Estoy trabajando simplemente poniendo la anotación @Expose , aquí está mi versión que uso

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

En clase de Model :

@Expose int number; public class AdapterRestApi {

En la clase 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); }


Me encontré con este problema, en el que tenía un pequeño número de campos que quería excluir solo de la serialización, así que desarrollé una solución bastante simple que utiliza la anotación @Expose de Gson con estrategias de exclusión personalizadas.

La única forma integrada de usar @Expose es configurando GsonBuilder.excludeFieldsWithoutExposeAnnotation() , pero como su nombre lo indica, los campos sin un @Expose explícito se ignoran. Como solo tenía unos pocos campos que quería excluir, encontré la posibilidad de agregar la anotación a cada campo muy engorroso.

De hecho, quería el inverso, en el que todo estaba incluido a menos que usara explícitamente @Expose para excluirlo. Usé las siguientes estrategias de exclusión para lograr esto:

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

Ahora puedo excluir fácilmente algunos campos con las @Expose(serialize = false) o @Expose(deserialize = false) (tenga en cuenta que el valor predeterminado para ambos atributos de @Expose es true ). Por supuesto, puede usar @Expose(serialize = false, deserialize = false) , pero esto se logra de manera más concisa declarando que el campo es transient (que aún tiene efecto con estas estrategias de exclusión personalizadas).


Nishant proporcionó una buena solución, pero hay una manera más fácil. Simplemente marque los campos deseados con la anotación @Expose, como por ejemplo:

@Expose private Long id;

Deje fuera cualquier campo que no quiera serializar. Entonces simplemente crea tu objeto Gson de esta manera:

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


O puede decir qué campos no se expondrán con:

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

en su clase en el atributo:

private **transient** boolean nameAttribute;


Otro enfoque (especialmente útil si necesita tomar una decisión para excluir un campo en tiempo de ejecución) es registrar un TypeAdapter con su instancia de gson. Ejemplo a continuación:

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

En el caso a continuación, el servidor esperaría uno de dos valores, pero dado que ambos eran ints, gson los serializaría a ambos. Mi objetivo era omitir cualquier valor que sea cero (o menos) del json que se publica en el servidor.

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


Por lo tanto, desea excluir el nombre y el nombre de country.name . Aquí es cómo debe verse su 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")); } }

Si ve de cerca, devuelve true para Student.firstName y Country.name , que es lo que desea excluir.

Necesitas aplicar esta ExclusionStrategy como esta,

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

Esto devuelve:

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

Asumo que el objeto de país se inicializa con id = 91L en la clase de estudiante.

Usted puede ser elegante. Por ejemplo, no desea serializar ningún campo que contenga la cadena "nombre" en su nombre. Hacer esto:

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

Esto volverá:

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

EDITAR: Agregado más información según lo solicitado.

Esta ExclusionStrategy lo hará, pero debe pasar "Nombre de campo totalmente calificado". Vea abajo:

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

Aquí es cómo podemos usarlo genéricamente.

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

Vuelve:

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


Puedes explorar el árbol json con gson.

Intenta algo como esto:

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

Puedes agregar algunas propiedades también:

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

Probado con gson 2.2.4.


Resolví este problema con anotaciones personalizadas. Esta es mi clase de anotación "SkipSerialisation":

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

y este es mi 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; } });

Ejemplo:

public class User implements Serializable { public String firstName; public String lastName; @SkipSerialisation public String email; }


Se me ocurrió una fábrica de clase para soportar esta funcionalidad. Pase cualquier combinación de campos o clases que desee excluir.

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

Para usarlo, cree dos listas (cada una es opcional) y crea tu objeto 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); }


Utilicé esta estrategia: excluí todos los campos que no están marcados con la anotación @SerializedName , es decir:

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

Vuelve

{"VisibleValue": "Veré esto"}