I'm having an issue registering multiple typeAdapters with my GsonBuilder. Seems like only one will fire off and it never takes the second one into considering. If i do it with each one by itself it seems to work fine. But I need them to work with both and seems that I am doing something wrong. Also I am currently using GSON v2.2.4.
Zip Object simple form:
public class Zip {
private String zipCode;
private String city;
private String state;
public Zip(){}
}
ZipSerializer:
public class ZipSerializer implements JsonSerializer<Zip>{
@Override
public JsonElement serialize(Zip obj, Type type, JsonSerializationContext jsc) {
Gson gson = new Gson();
JsonObject jObj = (JsonObject)gson.toJsonTree(obj);
jObj.remove("state");
return jObj;
}
}
JsonResponse Object simple form:
public class JsonResponse {
private String jsonrpc = "2.0";
private Object result = null;
private String id = null;
public JsonResponse(){}
}
JsonResponseSerializer:
public class JsonResponseSerializer implements JsonSerializer<JsonResponse> {
@Override
public JsonElement serialize(JsonResponse obj, Type type, JsonSerializationContext jsc) {
Gson gson = new Gson();
JsonObject jObj = (JsonObject)gson.toJsonTree(obj);
jObj.remove("id");
return jObj;
}
}
Test Example:
public class Test {
public static void main(String[] args) {
Zip zip = new Zip();
zip.setCity("testcity");
zip.setState("OH");
zip.setZipCode("12345");
JsonResponse resp = new JsonResponse();
resp.setId("1");
resp.setResult(zip);
resp.setJsonrpc("2.0");
Gson gson1 = new GsonBuilder()
.registerTypeAdapter(JsonResponse.class, new JsonResponseSerializer())
.registerTypeAdapter(Zip.class, new ZipSerializer())
.setPrettyPrinting()
.create();
String json = gson1.toJson(resp);
System.out.println(json);
}
}
Output:
{
"jsonrpc": "2.0",
"result": {
"zipCode": "12345",
"city": "testcity",
"state": "OH"
}
}
Expected Output: (Notice ZipSerializer didn't fire off)
{
"jsonrpc": "2.0",
"result": {
"zipCode": "12345",
"city": "testcity"
}
}
I simpled down the test case for this. I know I can use exclusionStrategy in this example to achieve results but the real issue is much more complex and this was the best way for me to portray and replicate my issue.
Thanks
<---------------------------- SOLUTION ------------------------------->
I managed to read Gson custom seralizer for one variable (of many) in an object using TypeAdapter and it helped me out greatly.
I created a base customTypeAdapterFactory and then extended it for each class that needed special serialization.
CustomizedTypeAdapterFactory
public abstract class CustomizedTypeAdapterFactory<C> implements TypeAdapterFactory {
private final Class<C> customizedClass;
public CustomizedTypeAdapterFactory(Class<C> customizedClass) {
this.customizedClass = customizedClass;
}
@SuppressWarnings("unchecked") // we use a runtime check to guarantee that 'C' and 'T' are equal
public final <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
return type.getRawType() == customizedClass
? (TypeAdapter<T>) customizeMyClassAdapter(gson, (TypeToken<C>) type)
: null;
}
private TypeAdapter<C> customizeMyClassAdapter(Gson gson, TypeToken<C> type) {
final TypeAdapter<C> delegate = gson.getDelegateAdapter(this, type);
final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
return new TypeAdapter<C>() {
@Override public void write(JsonWriter out, C value) throws IOException {
JsonElement tree = delegate.toJsonTree(value);
beforeWrite(value, tree);
elementAdapter.write(out, tree);
}
@Override public C read(JsonReader in) throws IOException {
JsonElement tree = elementAdapter.read(in);
afterRead(tree);
return delegate.fromJsonTree(tree);
}
};
}
/**
* Override this to muck with {@code toSerialize} before it is written to
* the outgoing JSON stream.
*/
protected void beforeWrite(C source, JsonElement toSerialize) {
}
/**
* Override this to muck with {@code deserialized} before it parsed into
* the application type.
*/
protected void afterRead(JsonElement deserialized) {
}
}
ZipTypeAdapterFactory (Did this to with JsonResponseTypeAdapterFactory)
public class ZipTypeAdapterFactory extends CustomizedTypeAdapterFactory<Zip> {
ZipTypeAdapterFactory() {
super(Zip.class);
}
@Override
protected void beforeWrite(Zip source, JsonElement toSerialize) {
JsonObject obj = (JsonObject) toSerialize;
obj.remove("state");
}
}
Test Code:
Gson gson1 = new GsonBuilder()
.registerTypeAdapterFactory(new JsonResponseTypeAdapterFactory())
.registerTypeAdapterFactory(new ZipTypeAdapterFactory())
.setPrettyPrinting()
.create();
String json = gson1.toJson(resp);
System.out.println(json);
Thank you everyone for the help.
Problem is in your JsonResponseSerializer. You create a new Gson instance, then on this new instance ZipSerializeris not registered. That's why your second serializer is never called.
If you want to achieve delegation and complex serialization, look at TypeAdapterFactory.
As you said, if you simply want to filter fields from serialization define a ExclusionStrategy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With