Campo Gson Serialize solo si no es nulo o no está vacío

Tengo un requisito donde necesito convertir el objeto java a json.

Estoy usando Gson para eso, pero necesito el convertidor para serializar solo los valores no nulos o no vacíos.

Por ejemplo:

//my java object looks like class TestObject{ String test1; String test2; OtherObject otherObject = new OtherObject(); } 

Ahora mi instancia de Gson para convertir este objeto a json se parece a

 Gson gson = new Gson(); TestObject obj = new TestObject(); obj.test1 = "test1"; obj.test2 = ""; String jsonStr = gson.toJson(obj); println jsonStr; 

En la impresión de arriba, el resultado es

 {"test1":"test1", "test2":"", "otherObject":{}} 

Aquí solo quería que el resultado fuera

 {"test1":"test1"} 

Como el test2 está vacío y otherObject está vacío, no quiero que se serialicen a datos json.

Por cierto, estoy usando Groovy / Grails así que si hay algún complemento para esto sería bueno, si no, cualquier sugerencia para personalizar la clase de serialización gson sería buena.

Crea tu propio TypeAdapter

 public class MyTypeAdapter extends TypeAdapter() { @Override public void write(JsonWriter out, TestObject value) throws IOException { out.beginObject(); if (!Strings.isNullOrEmpty(value.test1)) { out.name("test1"); out.value(value.test1); } if (!Strings.isNullOrEmpty(value.test2)) { out.name("test2"); out.value(value.test1); } /* similar check for otherObject */ out.endObject(); } @Override public TestObject read(JsonReader in) throws IOException { // do something similar, but the other way around } } 

Luego puede registrarlo con Gson .

 Gson gson = new GsonBuilder().registerTypeAdapter(TestObject.class, new MyTypeAdapter()).create(); TestObject obj = new TestObject(); obj.test1 = "test1"; obj.test2 = ""; System.out.println(gson.toJson(obj)); 

produce

  {"test1":"test1"} 

La clase GsonBuilder tiene GsonBuilder métodos para crear sus propias estrategias de serialización / deserialización, registrar adaptadores de tipo y establecer otros parámetros.

Strings es una clase de Guava. Puedes hacer tu propio cheque si no quieres esa dependencia.

Lo que personalmente no me gusta en TypeAdapter using answer es el hecho de que necesita describir cada campo de toda su clase que podría tener, por ejemplo, 50 campos (lo que significa 50 if se TypeAdapter bloques en TypeAdapter ).
Mi solución se basa en Reflection y en un hecho, Gson no serializará campos de valores nulos por defecto.
Tengo una clase especial que contiene datos para API para crear un documento llamado DocumentModel, que tiene aproximadamente 50 campos y no me gusta enviar campos String con valores “” o matrices vacías al servidor. Así que creé un método especial que me devuelve una copia de mi objeto con todos los campos vacíos anulados. Nota: de forma predeterminada, todas las matrices en mi instancia de DocumentModel se inicializan como matrices vacías (de longitud cero) y, por lo tanto, nunca son nulas, es probable que revise las matrices en busca de valores nulos antes de verificar su longitud.

 public DocumentModel getSerializableCopy() { Field fields[] = new Field[]{}; try { // returns the array of Field objects representing the public fields fields = DocumentModel.class.getDeclaredFields(); } catch (Exception e) { e.printStackTrace(); } DocumentModel copy = new DocumentModel(); Object value; for (Field field : fields) { try { value = field.get(this); if (value instanceof String && TextUtils.isEmpty((String) value)) { field.set(copy, null); // note: here array is not being checked for null! else if (value instanceof Object[] && ((Object[]) value).length == 0) { field.set(copy, null); } else field.set(copy, value); } catch (IllegalAccessException e) { e.printStackTrace(); } } return copy; } 

Al utilizar este método, no me importa si se agregaron algunos campos después de escribir este método o lo que sea. El único problema que queda es comprobar los campos de tipo personalizado, que no son String o array, pero esto depende de una clase particular y debe codificarse extra en los bloques if / else.

Me parece que el problema no está en Gson. Gson realiza un seguimiento correcto de la diferencia entre nulo y una cadena vacía. ¿Estás seguro de que quieres borrar esa distinción? ¿Estás seguro de que a todas las clases que usan TestObject no les importa?

Lo que podría hacer si no le importa la diferencia es cambiar las cadenas vacías para anular dentro de un TestObject antes de serializarlo. O mejor, haga que los setters en TestObject sean tales que una cadena vacía se establezca en nulo; de esta forma, define rígidamente dentro de la clase que una cadena vacía es lo mismo que nulo. Tendrá que asegurarse de que los valores no se puedan establecer fuera de los setters.