Estou consumindo uma API do meu aplicativo Android e todas as respostas JSON são assim:
{
'status': 'OK',
'reason': 'Everything was fine',
'content': {
< some data here >
}
O problema é que todos os meus POJOs têm um status
, reason
campos e dentro do content
campo está o POJO real que desejo.
Existe alguma maneira de criar um conversor personalizado de Gson para extrair sempre o content
campo, para que o retrofit retorne o POJO apropriado?
Respostas:
Você escreveria um desserializador personalizado que retornasse o objeto incorporado.
Digamos que seu JSON seja:
Você então teria um
Content
POJO:Então você escreve um desserializador:
Agora, se você construir um
Gson
comGsonBuilder
e registrar o desserializador:Você pode desserializar seu JSON direto para
Content
:Edite para adicionar a partir de comentários:
Se você tiver diferentes tipos de mensagens, mas todas elas tiverem o campo "conteúdo", poderá tornar o desserializador genérico fazendo:
Você só precisa registrar uma instância para cada um dos seus tipos:
Quando você chama,
.fromJson()
o tipo é transportado para o desserializador, então deve funcionar para todos os seus tipos.E, finalmente, ao criar uma instância de Retrofit:
fonte
setConverter(new GsonConverter(gson))
naRestAdapter.Builder
aula de RetrofitPerson.class
eList<Person>.class
/Person[].class
com desserializador separado?A solução de @BrianRoach é a solução correta. É importante notar que, no caso especial em que você aninhou objetos personalizados que precisam de um personalizado
TypeAdapter
, você deve registrar oTypeAdapter
com a nova instância de GSON , caso contrário, o segundoTypeAdapter
nunca será chamado. Isso ocorre porque estamos criando uma novaGson
instância dentro de nosso desserializador personalizado.Por exemplo, se você tivesse o seguinte json:
E você queria que este JSON fosse mapeado para os seguintes objetos:
Você precisaria registrar o
SubContent
'sTypeAdapter
. Para ser mais robusto, você pode fazer o seguinte:e crie-o assim:
Isso poderia ser facilmente usado para o caso de "conteúdo" aninhado, simplesmente passando uma nova instância de
MyDeserializer
com valores nulos.fonte
java.lang.reflect.Type
Um pouco tarde, mas espero que isso ajude alguém.
Basta criar o seguinte TypeAdapterFactory.
e adicione-o ao seu construtor GSON:
ou
fonte
jsonElement
? como eu fizcontent
,content1
etc.Tive o mesmo problema alguns dias atrás. Resolvi isso usando a classe de wrapper de resposta e o transformador RxJava, que acho uma solução bastante flexível:
Embrulho:
Exceção personalizada para lançar, quando o status não está OK:
Transformador Rx:
Exemplo de uso:
Meu tópico: Retrofit 2 RxJava - Gson - desserialização "Global", alterar tipo de resposta
fonte
Continuando a ideia de Brian, porque quase sempre temos muitos recursos REST, cada um com sua própria raiz, pode ser útil generalizar a desserialização:
Então, para analisar a carga útil de amostra acima, podemos registrar o desserializador GSON:
fonte
Uma solução melhor poderia ser esta ..
Então, defina seu serviço assim ..
fonte
De acordo com a resposta de @Brian Roach e @rafakob eu fiz isso da seguinte maneira
Resposta Json do servidor
Classe de manipulador de dados comum
Serializador personalizado
Objeto Gson
Api call
fonte
Esta é a mesma solução que @AYarulin, mas assume que o nome da classe é o nome da chave JSON. Desta forma, você só precisa passar o nome da classe.
Então, para analisar a carga útil de amostra acima, podemos registrar o desserializador GSON. Isso é problemático, pois a chave faz distinção entre maiúsculas e minúsculas, portanto, a caixa do nome da classe deve corresponder à caixa da chave JSON.
fonte
Aqui está uma versão do Kotlin baseada nas respostas de Brian Roach e AYarulin.
fonte
No meu caso, a chave "conteúdo" mudaria para cada resposta. Exemplo:
Nesses casos, usei uma solução semelhante à listada acima, mas tive que ajustá-la. Você pode ver a essência aqui . É um pouco grande para postar aqui no SOF.
A anotação
@InnerKey("content")
é usada e o resto do código é para facilitar seu uso com Gson.fonte
Não se esqueça
@SerializedName
e@Expose
anotações para todos os membros da classe e membros da classe interna que a maioria desserializados de JSON por Gson.Veja https://stackoverflow.com/a/40239512/1676736
fonte
Outra solução simples:
fonte