Olá, Victor!
Este problema se parece um pouco com este aqui.
Está dando NullPointerException porque a sua data class está diferente do json que está sendo retornado.
Na aula, a estrutura esperada é esta aqui:
"info": {
"title": "BioShock",
"steamAppID": null,
"thumb": "https://sttc.gamersgate.com/images/product/bioshock/cover-180-b0e244.jpg"
},
Ou seja, ele espera um info, e dentro dele, precisa ter um title, um steamAppID e uma thumb.
Então você deve criar duas data class, uma classe para sinalizar o info e outra para sinalizar title, steamAppID e thumb, logo elas deveriam ser escritas assim:
InfoJogo
data class InfoJogo(val info: InfoApiShark) {
override fun toString(): String {
return info.toString()
}
}
InfoApiShark
data class InfoApiShark(val title:String, val thumb:String, val steamAppID: String)
Na aula a professora não colocou o steamAppID, porque é uma informação que não era interessante para ela no momento, tanto que no exemplo do Bioshock ele vem nulo.
Essa explicação toda faz sentido quando a sua API é esta:
https://www.cheapshark.com/api/1.0/games?id=128
Esta API de cima, onde tem o endpoint /games?id={id}
foi a que foi usada na aula, usando somente o id para a busca, já a sua que você menciona no tópico, é diferente, que é esta:
https://www.cheapshark.com/api/1.0/games?ids=128%2C129%2C130`
Note que uma usa id e outra usa ids, então o resultado será diferente, logo vai ter uma estrutura diferente.
PS.: Para quem está lendo e ficou confuso com a URL, o "%2C" que se encontra no parâmetro, é uma codificação para vírgula.
Sendo assim, sabemos que um endpoint retorna um valor único de um jogo e outro endpoint retorna o valor de três jogos (128, 129, 130), então precisa ter uma estrutura de lista ou similar.
{
"128": {
"info": {
"title": "BioShock",
"steamAppID": null,
"thumb": "https://sttc.gamersgate.com/images/product/bioshock/cover-180-b0e244.jpg"
}
},
"129": {
"info": {
"title": "Red Orchestra 2: Heroes of Stalingrad",
"steamAppID": null,
"thumb": "https://sttc.gamersgate.com/images/product/red-orchestra-2-heroes-of-stalingrad/cover-180-f8237a.jpg"
}
},
"130": {
"info": {
"title": "Renegade Ops",
"steamAppID": "99300",
"thumb": "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/99300/capsule_sm_120.jpg?t=1614779423"
}
}
}
Então para solucionar o erro, há duas possibilidades:
1º Possibilidade: Trocar o endpoint de ids para id:
val client: HttpClient = HttpClient.newHttpClient()
val request = HttpRequest.newBuilder()
.uri(URI.create("https://www.cheapshark.com/api/1.0/games?id=128"))
.build()
/*Mesmo código*/
Esta eu acho melhor, porque você tem um maior controle dos dados que está vindo.
2º Possibilidade: Fazer uma nova classe de dados:
Como foi citado anteriormente neste post, a classe tem que ter os mesmos atributos do json, como este novo retorno tem 128, 129 e 130, a classe também tem que ter EXATAMENTE estes mesmos nomes:
data class JogoResponse(
val `128`: InfoJogo,
val `129`: InfoJogo,
val `130`: InfoJogo
)
Isso considerando que o InfoJogo que já foi criado e dentro dele tem as outras propriedades como info e dentro de info aquelas outras três: title, thumb, steamAppID. Em outras palavras, na InfoJogo não se toca.
Agora que temos esta "entidade principal", podemos chamar ela na main:
/*
Mesmo código
*/
val meuJogo = gson.fromJson(json, JogoResponse::class.java)
println(meuJogo)
A InfoJogo continua existindo, pois a JogoResponse utiliza ela, mas note que na geração da variável meuJogo
, eu troquei o tipo para JogoResponse, que é exatamente o retorno do json.
Agora qual é o grande problema desta segunda possibilidade: como foi visto, eu tive que colocar explicitamente os valores "128", "129" e "130".
Aí tem a terceira possibilidade (é eu sei... eu sou um grande brincalhão). Com o teu mesmo endpoint, é só adicionar &format=array
no final.
Terceira Possibilidade:
Trocar o endpoint para:
https://www.cheapshark.com/api/1.0/games?ids=128%2C129%2C130&format=array
Desta forma, ele vai vir como array, ao invés de chave e valor. Neste caso, só vai ter mais uma mudança, que é na tipagem declarada no gson:
/*
Mesmo código
*/
val gson = Gson()
val meuJogo = gson.fromJson(json, Array<InfoJogo>::class.java)
println(meuJogo)
Bom, acredito que seja isso. Espero ter explicado direitinho.
Bom código!