I'm implementing a Gson TypeAdapter for two dependend generic models.
interface ModelA<T> {}
interface ModelB<T> extends ModelA<List<T>> {}
For this I need to get the TypeToken and TypeAdapter. By doing
Type type = ((ParameterizedType) type).getActualTypeArguments()[0];
TypeToken<?> token = TypeToken.get(type);
TypeAdapter<?> adapter = gson.getAdapter(token);
I get a type token for both models of any given type AnyType and the correlating adapter. This is what I need for ModelA, but for ModelB I'd need the adapter for List<AnyType> instead, which is the result of using ModelA<List<AnyType>> directly.
Using the interface of the raw type of the original type token passed
token.getRawType().getGenericInterfaces()[0]
I only seem to get the type erased type of List.
How can I combine these two informations to get the generic List<AnyType> type or create it directly? As input it only has the type token for ModelB<AnyType>.
For the given behavior I implemented a simple test showing the differences. I've taken the expected part from the answer by hahn, using the Gson internal non-API class $Gson$Types.
public class TypeTokenValidate {
public interface ModelA<T> {}
public interface ModelB<T> extends ModelA<List<T>> {}
@Test
public void genericToken() throws Exception {
TypeToken<ModelB<String>> token = new TypeToken<ModelB<String>>() {};
ModelB<String> m = new ModelB<String>() {};
Type expected = $Gson$Types.resolve(ModelB.class, m.getClass(),
ModelA.class.getTypeParameters()[0]);
assertEquals(expected, getActual(token));
}
private static Type getActual(TypeToken<?> token) {
Type type = token.getType();
//type = token.getRawType().getGenericInterfaces()[0];
type = ((ParameterizedType) type).getActualTypeArguments()[0];
return TypeToken.get(type).getType();
}
}
Forces clients to create a subclass of this class which enables retrieval the type information even at runtime.
Like C++, we use <> to specify parameter types in generic class creation. To create objects of a generic class, we use the following syntax. Note: In Parameter type we can not use primitives like 'int','char' or 'double'.
A generic type is like a template. You cannot create instances of it unless you specify real types for its generic type parameters. To do this at run time, using reflection, requires the MakeGenericType method.
There is a $Gson$Types that you can utilize to retrieve Type of typed List. For example having:
ModelB<String> m = new ModelB<String>() {};
Type resolve = $Gson$Types.resolve(m.getClass(), m.getClass(), ModelA.class.getTypeParameters()[0]);
would return Type with rawType set to List and with typeArguments of [String]. Thus preserving the types as you need.
and then executing this block
TypeToken<?> token = TypeToken.get(resolve);
TypeAdapter<?> adapter = gson.getAdapter(token);
would result with adaptor of CollectionTypeAdaptorFactory with elementTypeAdapter.type set to class String.
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