С ретрофитом вы наверняка используете какую-нибудь ConverterFactory для преобразования ответа в объект. Например, GsonConverterFactory (GSON). Рассмотрим ситуацию на его примере:
Все объекты описываете как обычно, кроме msg. Его описываете как интерфейс Message. Регистрируете:
class MessageDeserializer implements JsonDeserializer<Message>{ ... }
...
Gson gson = new GsonBuilder()
.registerTypeAdapter(Message.class, new MessageDeserializer())
.create();
GsonConverterFactory.create(gson);
В методе
public Message deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { ... }
Десериализуете msg на основе тех данных, которые есть (надо научиться различать разные типы msg). Кладёте данные в разные реализации Message, например для {'txt':''} делаете такую реализацию:
class MessageTxt implements Message {
private final String txt;
public MessageTxt(String txt){
this.txt = txt;
}
String getTxt() { return txt; }
}
Сам интерфейс Message может вообще не содержать методов (маркерный интерфейс) или содержать общие для всех типов msg методы, или дополнительно содержать метод для возвращения типа. Как-то так я бы поступил, видимо. Разные реализации Message потом можно просто проверять instaceof и кастовать.