Gson Deserialize Interface To Its Class Implementation
Solution 1:
I am assuming that you want to create a single deserializer for all of your interfaces and their respective implementations. Follow these steps please:
1. Create a base interface that will be extended by your other app interfaces. It is required to create a single deserializer for all of your interfaces and implementation classes.
publicinterfaceConvertable {
String getClassName();
}
2. Create your feature interface and implementation class. As an example, lets name them FooInterface and FooClass. FooInterface should extend Convertable interface.
FooInterface
publicinterfaceFooInterfaceextendsConvertable {
}
FooClass
publicclassFooClassimplementsFooInterface {
// DISCRIMINATOR FIELDprivate final String className;
privateString field1;
privateString field2;
publicFooClass() {
this.className = getClass().getName();
}
publicStringgetClassName() {
return className;
}
publicStringgetField1() {
return field1;
}
publicvoidsetField1(String field1) {
this.field1 = field1;
}
publicStringgetField2() {
return field2;
}
publicvoidsetField2(String field2) {
this.field2 = field2;
}
}
Note that the value returned by getClassName() is used as discriminator field that will be used in Gson Deserializer (next step) to initialize returnable instance. I am assuming that your serializer and deserializer class will reside in the same package even if they are in different client and server applications. If not, then you will need to change getClassInstance() implementation, but would be pretty simple to do so.
3. Implement a custom Gson Serializer for all of your application
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
publicclassConvertableDeserializer<T extendsConvertable> implementsJsonDeserializer<T> {
privatestaticfinalStringCLASSNAME="className";
public T deserialize(final JsonElement jsonElement, final Type type,
final JsonDeserializationContext deserializationContext
)throws JsonParseException {
finalJsonObjectjsonObject= jsonElement.getAsJsonObject();
finalJsonPrimitiveprim= (JsonPrimitive) jsonObject.get(CLASSNAME);
finalStringclassName= prim.getAsString();
final Class<T> clazz = getClassInstance(className);
return deserializationContext.deserialize(jsonObject, clazz);
}
@SuppressWarnings("unchecked")public Class<T> getClassInstance(String className) {
try {
return (Class<T>) Class.forName(className);
} catch (ClassNotFoundException cnfe) {
thrownewJsonParseException(cnfe.getMessage());
}
}
}
4. Register Deserializer with Gson and initialize retrofit
privatestatic GsonConverterFactory buildGsonConverter() {
finalGsonBuilderbuilder=newGsonBuilder();
// Adding custom deserializers
builder.registerTypeAdapter(FooInterface.class,
newConvertableDeserializer<FooInterface>());
finalGsongson= builder.create();
return GsonConverterFactory.create(myGson);
}
publicvoidinitRetrofit() {
Retrofitretrofit=newRetrofit.Builder()
.baseUrl("REST_ENDPOINT")
.addConverterFactory(buildGsonConverter())
.client(httpClient)
.build();
}
You may register the adapter for all of your implementations if you want, using:
builder.registerTypeAdapter(Convertable.class, newConvertableDeserializer<Convertable>());
Solution 2:
Because you are willing to take the effort to almost duplicate your entire domain layer using interfaces to hide the implementation detail of your models, I think you will find my answer refresing ;)
You should use AutoValue in order to hide any implementation detail in your models. The way it works is pretty simple:
You write an abstract class, and AutoValue implements it. That is all there is to it; there is literally no configuration.
Adopting this approach you won’t need to create such amount of boilerplate.
And there is this AutoValue Extension called auto-value-gson, which adds Gson De/Serializer support out of box.
With these simple steps I think your code base will improve substantially.
Post a Comment for "Gson Deserialize Interface To Its Class Implementation"