Java Gson Exclude fields during serialization
In order to get this result, you need to annotate all the fields with the @Expose
:
public class ConfigInstance {
@Expose
public String database_address;
@Expose
public int database_port;
@Expose
public String database_user;
@Expose(serialize = false)
private String database_pass;
@Expose
public String database_pass_hash;
And configure Gson to only expose fields that are annotated and ignore the rest as shown in the following:
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().setPrettyPrinting().create();
Then, you'll get:
{
"database_address": "127.0.0.1",
"database_port": 1521,
"database_user": "test",
"database_pass_hash": "B9FE2C011B59F0D0D383D70073E48A19"
}
Also, when deserialising the string you'll still have the password attribute as well.
Still, you have the possibility to configure a Gson Serializer to accomplish this.
How to exclude fields during serialization of gson
I believe it has not much with Hibernate, but more with GSON. You should define serialization/deserialization rule.
Easiest way is to use @Expose
annotation, to include/exclude given property from serialization/deserialization:
@Expose(serialize = false, deserialize = false)
Another way is to define custom adapters for givem class. WIth Adapter you can completely override the way GSON serialize or deserialize object.
For example:
public class YourAdapter implements JsonDeserializer<Order>, JsonSerializer<Order> {
@Override
public Orderde serialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
// your logic
}
@Override
public JsonElement serialize(Ordersrc, Type typeOfSrc, JsonSerializationContext context) {
// your logic
}
}
Finally initialize instance of your Gson parser:
Gson gson = new GsonBuilder()
.registerTypeAdapter(Order.class, new YourAdapter())
.build();
If you want to avoid writting whole serialization, you could exclude your field by using @Expose
, and then write adapter with pure instance of GSON in it, serialize/deserialize using that pure one and manually add that one field.
Another way of dealing with serialization/deserialization problem is to use ExclusionStrategy
described here: https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/ExclusionStrategy.html
Gson serialization: exclude SOME fields if null but not all of them
Using ExclusionStrategy, I can define the field, but I cannot seem to find a way to get the value.
Yes, it does not provide a way of determining the current field value. This is because of how Gson ReflectiveTypeAdapterFactory
works internally (the BoundField.serialized
is final
and only resolved once):
@Override public boolean writeField(Object value) throws IOException, IllegalAccessException {
if (!serialized) return false;
Object fieldValue = field.get(value);
return fieldValue != value; // avoid recursion for example for Throwable.cause
}
for (BoundField boundField : boundFields.values()) {
if (boundField.writeField(value)) {
out.name(boundField.name);
boundField.write(out, value);
}
}
This behavior cannot be changed, but I believe it's a good design choice to segregate application objects and their serialized representations (see the Data Transfer Object pattern) in order not to mix concepts and make applicaiton components loosely coupled (migrating from Gson someday would take only modifications for the respective DTO classes only).
If you're fine with having DTOs introduced to your application, then you could create separate DTO classes for both scenarios: preserving phone
and discarding fax
depending on the fax
field value.
class PersonDto {
@Expose String name;
@Expose String phone;
PersonDto(final Person person) {
name = person.name;
phone = person.phone;
}
}
class PersonDtoWithFax extends PersonDto {
@Expose String fax;
PersonDtoWithFax(final Person person) {
super(person);
fax = person.fax;
}
}
In this case the serialization is straight-forward:
final Gson gson = new GsonBuilder()
.serializeNulls()
.create();
final Person person = new Person();
person.name = "John";
final PersonDto personDto = person.fax == null
? new PersonDto(person)
: new PersonDtoWithFax(person);
System.out.println(gson.toJson(personDto));
If you don't want to introduce the segregated DTO concept per se, you probably might want to implement a custom serializer that is somewhat more complicated in implementation and probably somewhat error-prone due to property names hardcoding (but you can have good tests, of course, or extract the names from java.lang.reflect.Field
instances).
final class SpecialJsonSerializer<T>
implements JsonSerializer<T> {
private final Gson gson; // Unfortunately, Gson does not provide much from JsonSerialiationContext, so we have to get it ourselves
private final Iterable<String> excludeIfNull;
private SpecialJsonSerializer(final Gson gson, final Iterable<String> excludeIfNull) {
this.gson = gson;
this.excludeIfNull = excludeIfNull;
}
static <T> JsonSerializer<T> getSpecialJsonSerializer(final Gson gson, final Iterable<String> excludeIfNull) {
return new SpecialJsonSerializer<>(gson, excludeIfNull);
}
@Override
public JsonElement serialize(final T object, final Type type, final JsonSerializationContext context) {
// context.serialize(person, type) cannot work due to infinite recursive serialization
// therefore the backing Gson instance is used
final JsonObject jsonObject = gson.toJsonTree(object, type).getAsJsonObject();
for ( final String propertyName : excludeIfNull ) {
final JsonElement property = jsonObject.get(propertyName);
if ( property != null && property.isJsonNull() ) {
jsonObject.remove(propertyName);
}
}
return jsonObject;
}
}
I'm not really sure, but I think that creating JSON trees for serialization purposes rather than using DTOs may be slightly more expensive from the memory consumption point of view (at least because of more complicated JsonElement
structure).
// Both Gson instances must have serializeNulls()
final Gson gson = new GsonBuilder()
.serializeNulls()
.create();
final Gson gsonWrapper = new GsonBuilder()
.serializeNulls()
.registerTypeAdapter(Person.class, getSpecialJsonSerializer(gson, singletonList("fax")))
.create();
final Person person = new Person();
person.name = "John";
System.out.println(gsonWrapper.toJson(person));
Both solutions output:
{"name":"John","phone":null}
Gson ignore field on serialization under condition
You might be looking for Exclusion Strategies - Look at the following link to the GSON documentation for further details: https://howtodoinjava.com/gson/gson-exclude-or-ignore-fields/ :)
Excluding certain fields from Serialization based on value in GSON
The way to achieve this is by creating custom serializer for the class in question. After allowing Gson to create a JSON object in default fashion, remove the property that you want to exclude based on its value.
public class SerializerForMyClass implements JsonSerializer<MyClass> {
@Override
public JsonElement serialize(MyClass obj, Type type, JsonSerializationContext jsc) {
Gson gson = new Gson();
JsonObject jObj = (JsonObject)gson.toJsonTree(obj);
if(obj.getMyProperty()==0){
jObj.remove("myProperty");
}
return jObj;
}
}
And registering the new serializer in the Gson object that you use for serialization in the application for this class.
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(MyClass.class, new SerializerForMyClass());
Gson gson=gsonBuilder.create();
gson.toJson(myObjectOfTypeMyClass);
Related Topics
Java Switch Statement: Constant Expression Required, But It Is Constant
Recyclerview Horizontal Scrolling to Left
Android - Span_Exclusive_Exclusive Spans Cannot Have a Zero Length
Can't Start Cassandra (Single-Node Cluster on Centos7)
Why Parallel Execution on Java Compile Take Linear Growth in Time
One to One Mapping of Java Thread to Linux Thread (Lwp)
Where to Install the Import Modules Used in a Java Program
Fill an Array With Random Numbers
Why Isn't Calling a Static Method by Way of an Instance an Error For the Java Compiler
Android: How to Enable/Disable Wifi or Internet Connection Programmatically
Directory Creation Not Working in Marshmallow Android
Launching Activities Within a Tab in Android
Tomcat 7: How to Set Initial Heap Size Correctly
Accessing Linux Local File System from Java Web Application