AutoValue Gson adapter for map <String, List <Obj>>
I am trying to find a way to use AutoValue to deserialize a JSON OBJ to a Java class (which is also Parcelable)
The JSON response usually has the form:
{
"varKey1": {
"occupations": [
{
"value": "val1",
"name": "name1"
},
{
"value": "val2",
"name": "name2"
}
]
},
"varKey2": {
"occupations": [
{
"value": "val1",
"name": "name1"
},
{
"value": "val2",
"name": "name2"
}
]
}
}
where varKey1and varKey2are strings that are not fixed / predetermined, therefore they can have any value.
It’s hard for me to understand what the type of Adapter should look like for this, although with AutoValue Gson, and any help with that would be greatly appreciated.
, AutoValue AutoValue: Gson Extension, Map<String, List<Obj>> JSON, , . , AutoValue Gson TypeAdapterFactory.
JSON Map<String, List<Obj>>, :
- ...
Map<String, Wrapper>, -List<Obj>(@AutoValue-) ,Wrapper. - ... , AutoValue: Gson.
, , , AutoValue .
final class TypeTokens {
private TypeTokens() {
}
static final TypeToken<Map<String, List<Obj>>> mapStringToObjListTypeToken = new TypeToken<Map<String, List<Obj>>>() {
};
static final TypeToken<List<Obj>> objListTypeTypeToken = new TypeToken<List<Obj>>() {
};
}
factory
Gson ( ) , , Gson Gson.
final class CustomTypeAdapterFactory
implements TypeAdapterFactory {
private static final TypeAdapterFactory customTypeAdapterFactory = new CustomTypeAdapterFactory();
static TypeAdapterFactory getCustomTypeAdapterFactory() {
return customTypeAdapterFactory;
}
@Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
if ( typeToken.getType().equals(mapStringToObjListTypeToken.getType()) ) {
@SuppressWarnings({ "unchecked", "rawtypes" })
final TypeAdapter<T> castTypeAdapter = (TypeAdapter) getMapStringToObjectListTypeAdapter(gson);
return castTypeAdapter;
}
return null;
}
}
, factory , JSON. - factory, null Gson ( ).
, Auto Value: Gson Extension, , . , , Gson, , , Auto Value: Gson Extension.
final class MapStringToObjectListTypeAdapter
extends TypeAdapter<Map<String, List<Obj>>> {
private final TypeAdapter<List<Obj>> wrapperAdapter;
private MapStringToObjectListTypeAdapter(final TypeAdapter<List<Obj>> wrapperAdapter) {
this.wrapperAdapter = wrapperAdapter;
}
static TypeAdapter<Map<String, List<Obj>>> getMapStringToObjectListTypeAdapter(final Gson gson) {
return new MapStringToObjectListTypeAdapter(gson.getAdapter(objListTypeTypeToken));
}
@Override
@SuppressWarnings("resource")
public void write(final JsonWriter out, final Map<String, List<Obj>> value)
throws IOException {
if ( value == null ) {
// nulls must be written
out.nullValue();
} else {
out.beginObject();
for ( final Entry<String, List<Obj>> e : value.entrySet() ) {
out.name(e.getKey());
out.beginObject();
out.name("occupations");
wrapperAdapter.write(out, e.getValue());
out.endObject();
}
out.endObject();
}
}
@Override
public Map<String, List<Obj>> read(final JsonReader in)
throws IOException {
// if there JSON null, then just return nothing
if ( in.peek() == NULL ) {
return null;
}
// or read the map
final Map<String, List<Obj>> result = new LinkedHashMap<>();
// expect the { token
in.beginObject();
// and read recursively until } is occurred
while ( in.peek() != END_OBJECT ) {
// this is the top-most level where varKey# occur
final String key = in.nextName();
in.beginObject();
while ( in.peek() != END_OBJECT ) {
final String wrapperName = in.nextName();
switch ( wrapperName ) {
case "occupations":
// if this is the "occupations" property, delegate the parsing to an underlying type adapter
result.put(key, wrapperAdapter.read(in));
break;
default:
// or just skip the value (or throw an exception, up to you)
in.skipValue();
break;
}
}
in.endObject();
}
in.endObject();
return result;
}
}
factory
factory, Gson abstract, Obj ( , , ).
@GsonTypeAdapterFactory
abstract class GeneratedTypeAdapterFactory
implements TypeAdapterFactory {
public static TypeAdapterFactory getGeneratedTypeAdapterFactory() {
return new AutoValueGson_GeneratedTypeAdapterFactory();
}
}
private static void dump(final Map<?, ?> map) {
for ( final Entry<?, ?> e : map.entrySet() ) {
out.print(e.getKey());
out.print(" => ");
out.println(e.getValue());
}
}
...
final Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(getGeneratedTypeAdapterFactory())
.registerTypeAdapterFactory(getCustomTypeAdapterFactory())
.create();
dump(gson.fromJson(json, mapStringToObjListTypeToken.getType()));
:
varKey1 = > [Obj {name = name1, value = val1}, Obj {name = name2, value = val2}]
varKey2 = > [Obj {name = name1, value = val1}, Obj {name = name2, value = val2}]
, :
varKey1 = > Wrapper { = [Obj {name = name1, value = val1}, Obj {name = name2, value = val2}]}
varKey2 = > Wrapper { = [Obj {name = name1, value = val1}, Obj {name = name2, value = val2}]}