Quero transferir um objeto de lista pelo Google Gson, mas não sei desserializar tipos genéricos.
O que eu tentei depois de olhar para isso (resposta de BalusC):
MyClass mc = new Gson().fromJson(result, new List<MyClass>(){}.getClass());
mas, em seguida, recebo um erro no eclipse dizendo "O tipo new List () {} deve implementar o método abstrato herdado ..." e, se eu usar uma correção rápida, recebo um monstro com mais de 20 stubs de métodos.
Tenho certeza de que existe uma solução mais fácil, mas não consigo encontrá-la!
Editar:
Agora eu tenho
Type listType = new TypeToken<List<MyClass>>()
{
}.getType();
MyClass mc = new Gson().fromJson(result, listType);
No entanto, recebo a seguinte exceção na linha "fromJson":
java.lang.NullPointerException
at org.apache.harmony.luni.lang.reflect.ListOfTypes.length(ListOfTypes.java:47)
at org.apache.harmony.luni.lang.reflect.ImplForType.toString(ImplForType.java:83)
at java.lang.StringBuilder.append(StringBuilder.java:203)
at com.google.gson.JsonDeserializerExceptionWrapper.deserialize(JsonDeserializerExceptionWrapper.java:56)
at com.google.gson.JsonDeserializationVisitor.invokeCustomDeserializer(JsonDeserializationVisitor.java:88)
at com.google.gson.JsonDeserializationVisitor.visitUsingCustomHandler(JsonDeserializationVisitor.java:76)
at com.google.gson.ObjectNavigator.accept(ObjectNavigator.java:106)
at com.google.gson.JsonDeserializationContextDefault.fromJsonArray(JsonDeserializationContextDefault.java:64)
at com.google.gson.JsonDeserializationContextDefault.deserialize(JsonDeserializationContextDefault.java:49)
at com.google.gson.Gson.fromJson(Gson.java:568)
at com.google.gson.Gson.fromJson(Gson.java:515)
at com.google.gson.Gson.fromJson(Gson.java:484)
at com.google.gson.Gson.fromJson(Gson.java:434)
I fazer JsonParseExceptions de captura e "resultado" não é nulo.
Eu verifiquei listType com o depurador e obtive o seguinte:
- Tipo de lista
- args = ListOfTypes
- list = null
- resolvedTypes = Tipo [1]
- loader = PathClassLoader
- ownerType0 = null
- ownerTypeRes = null
- rawType = Class (java.util.ArrayList)
- rawTypeName = "java.util.ArrayList"
- args = ListOfTypes
parece que a chamada "getClass" não funcionou corretamente. Alguma sugestão...?
Edit2: verifiquei no Guia do Usuário do Gson . Ele menciona uma exceção de tempo de execução que deve ocorrer durante a análise de um tipo genérico para o Json. Fiz isso "errado" (não mostrado acima), como no exemplo, mas não recebi a exceção. Então mudei a serialização como no guia do usuário sugerido. Não ajudou, no entanto.
Edit3: Resolvido, veja minha resposta abaixo.
TokenType
. Você já tentou dessa maneira?Respostas:
Método para desserializar a coleção genérica:
Como várias pessoas nos comentários mencionaram, aqui está uma explicação de como a
TypeToken
classe está sendo usada. A construçãonew TypeToken<...>() {}.getType()
captura um tipo de tempo de compilação (entre<
e>
) em umjava.lang.reflect.Type
objeto de tempo de execução . Ao contrário de umClass
objeto, que pode representar apenas um tipo bruto (apagado), oType
objeto pode representar qualquer tipo na linguagem Java, incluindo uma instanciação parametrizada de um tipo genérico.A
TypeToken
classe em si não tem um construtor público, porque você não deve construí-lo diretamente. Em vez disso, você sempre constrói uma subclasse anônima (daí a{}
, que é uma parte necessária dessa expressão).Devido ao apagamento do tipo, a
TypeToken
classe só pode capturar tipos que são totalmente conhecidos no momento da compilação. (Ou seja, você não pode fazernew TypeToken<List<T>>() {}.getType()
por um parâmetro de tipoT
.)Para mais informações, consulte a documentação da
TypeToken
turma .fonte
{ "myObjectArray":[ {....} , {....} , {....} ] }
, criei o arquivo de modelo{....}
, como faço para obter esse código genérico de coleção para não assumir que meu elemento raiz é uma matriz sem criar um novo arquivo de objeto aninhadoOutra maneira é usar uma matriz como um tipo, por exemplo:
Dessa forma, você evita todos os problemas com o objeto Type e, se realmente precisa de uma lista, pode sempre converter a matriz em uma lista:
IMHO isso é muito mais legível.
E para torná-la uma lista real (que pode ser modificada, consulte as limitações de
Arrays.asList()
), faça o seguinte:fonte
MyClass
valor e ele será definido dinamicamente!T[] yourClassList = gson.fromJson(message, T[].class);
// não pode selecionar a partir de tipo de variávelmcList
nesta resposta, foi apenas o resultado da chamada paraArrays.asList
. Esse método retorna uma lista na qual a maioria, se não todos, os métodos opcionais são deixados sem implementação e lançam exceções. Por exemplo, você não pode adicionar nenhum elemento a essa lista. Como sugere a edição posterior,Arrays.asList
possui limitações, e agrupá-lo em um número realArrayList
permite obter uma lista que é mais útil em muitos casos.Array.newInstance(clazz, 0).getClass()
como descrito na resposta de David Wood .Consulte este post. Tipo Java genérico como argumento para GSON
Eu tenho uma solução melhor para isso. Aqui está a classe de wrapper para lista, para que o wrapper possa armazenar exatamente o tipo de lista.
E então, o código pode ser simples:
fonte
mEntity.rulePattern
?Desde então
Gson 2.8
, podemos criar a função util comoExemplo usando
fonte
TypeToken#getParameterized
parece uma maneira melhor, então o corte com uma subclasse anônimaWep, outra maneira de alcançar o mesmo resultado. Nós o usamos para sua legibilidade.
Em vez de fazer esta frase difícil de ler:
Crie uma classe vazia que estenda uma lista do seu objeto:
E use-o ao analisar o JSON:
fonte
Para Kotlin simplesmente:
ou, aqui está uma função útil:
Então, para usar:
fonte
inline fun <reified T> buildType() = object : TypeToken<T>() {}.type!!
e chamá-lo com o tipo List:buildType<List<YourMagicObject>>()
buildType
e também chama a função com o tipo genérico? Isso é um erro de digitação? - Isso criaria ArrayList <ArrayList <YourMagicObject>>Exemplo:
fonte
DevNG
a resposta acima, escrita 2 anos antes: stackoverflow.com/a/17300003/1339923 (e leia a resposta para ressalvas a essa abordagem) #Como ele responde à minha pergunta original, aceitei a resposta do doc_180, mas se alguém encontrar esse problema novamente, também responderei à segunda metade da minha pergunta:
O NullPointerError que descrevi não teve nada a ver com a própria lista, mas com seu conteúdo!
A classe "MyClass" não tinha um construtor "no args" e nem a superclasse. Depois de adicionar um construtor "MyClass ()" simples ao MyClass e sua superclasse, tudo funcionou bem, incluindo a serialização e desserialização da lista, conforme sugerido por doc_180.
fonte
Aqui está uma solução que funciona com um tipo definido dinamicamente. O truque é criar o tipo adequado de matriz usando Array.newInstance ().
fonte
class.cast()
evitasse o aviso não verificado causado pela transmissão para(T)
. Ou, melhor ainda, não se preocupe com a conversão e use algo comoArrays.asList()
converter de uma matriz para aList<T>
. Além disso, não há necessidade de passar um comprimento paraArray.newInstance()
- uma matriz de tamanho zero será suficiente para chamargetClass()
.Quero acrescentar mais uma possibilidade. Se você não deseja usar o TypeToken e deseja converter a matriz de objetos json em um ArrayList, pode proceder da seguinte maneira:
Se sua estrutura json é como:
}
e sua estrutura de classe é como:
então você pode analisá-lo como:
Agora você pode acessar cada elemento do objeto className.
fonte
Consulte o exemplo 2 para entender a classe 'Tipo' do Gson.
Exemplo 1: Neste deserilizeResturant, usamos a matriz Employee [] e obtemos os detalhes
Exemplo 2:
fonte
Gostei da resposta do kays1, mas não consegui implementá-la. Então eu construí minha própria versão usando o conceito dele.
Uso:
fonte
No meu caso, a resposta de @ uncaught_exceptions não funcionou, eu tive que usar em
List.class
vez dejava.lang.reflect.Type
:fonte