Ответ 1
Вам явно нужен пользовательский TypeAdapter
. Но сложными являются:
- ваш родительский класс является общим
-
mSerialChild
не относится к типуT
, а относится к типуMyChildInterface
- мы хотим избежать разбора вручную json для каждого дочернего класса и иметь возможность добавлять свойства к родительскому, не изменяя весь код.
Помня об этом, я получил следующее решение.
public class MyParentAdapter implements JsonDeserializer<MyDeserialParent>{
private static Gson gson = new GsonBuilder().create();
// here is the trick: keep a map between "type" and the typetoken of the actual child class
private static final Map<String, Type> CHILDREN_TO_TYPETOKEN;
static{
// initialize the mapping once
CHILDREN_TO_TYPETOKEN = new TreeMap<>();
CHILDREN_TO_TYPETOKEN.put( "value", new TypeToken<MyChild1>(){}.getType() );
}
@Override
public MyDeserialParent deserialize( JsonElement json, Type t, JsonDeserializationContext
jsonDeserializationContext ) throws JsonParseException{
try{
// first, get the parent
MyDeserialParent parent = gson.fromJson( json, MyDeserialParent.class );
// get the child using the type parameter
String type = ((JsonObject)json).get( "type" ).getAsString();
parent.mSerialChild = gson.fromJson( json, CHILDREN_TO_TYPETOKEN.get( type ) );
return parent;
}catch( Exception e ){
e.printStackTrace();
}
return null;
}
}
замечания:
- пользовательский адаптер должен быть зарегистрирован на gsonBuilder
- Если вам нужны пользовательские свойства gson для ваших детей, вы можете передать объект
Gson
в конструктореMyParentAdapter
, так как сейчас он использует значение по умолчанию; - дети и родительский должны иметь атрибуты с разными именами;
- каждый новый тип должен быть добавлен к карте с соответствующим классом.
Полный пример
Главная:
public class DeserializeExample{
MyDeserialParent[] myDeserialParents;
static String json = "{\n" +
" \"myDeserialParents\" : [\n" +
" {\n" +
" \"otherProp\": \"lala\"," +
" \"type\": \"value\", //used in a TypeAdapter to choose child implementation\n" +
" \"childProp1\": \"1\",\n" +
" \"childProp2\": \"2\"\n" +
" }\n" +
" ]\n" +
"}";
public static void main( String[] args ){
Gson gson = new GsonBuilder().registerTypeAdapter( MyDeserialParent.class, new MyParentAdapter() ).create();
DeserializeExample result = gson.fromJson( json, DeserializeExample.class );
System.out.println( gson.toJson( result ));
// output:
// {"myDeserialParents":[{"mSerialChild":{"childProp1":"1","childProp2":"2"},"otherProp":"lala"}]}
}//end main
}//end class
Родитель:
class MyDeserialParent<T extends MyChildInterface>{
MyChildInterface mSerialChild;
//some other fields (not 'type')
String otherProp;
}
ребенок:
public class MyChild1 implements MyChildInterface {
String childProp1;
String childProp2;
}//end class