IllegalStateException: This is not a JSON Array (Gson Java) - java

I've been trying to create using Gson a way to import track data. This is my first attempt at using Gson and I am struggling to understand where I am going wrong. I am trying to use spotify's json. This is the address I am using.
https://api.spotify.com/v1/search?q=%22Perform%20this%20way%22&type=track
And I've created a class to import it. I have been following this guide.
http://www.javabeat.net/invoking-restful-web-service-using-api-in-java-net-and-gson/
I get the following error after typing in my query and giving it the okay to go ahead..
Exception in thread "main" java.lang.IllegalStateException: This is not a JSON Array.
at com.google.gson.JsonElement.getAsJsonArray(JsonElement.java:106)
at TestingNonApplication.GsonTesting.main2(GsonTesting.java:72)
- Refers to this line. JsonArray jArray = rootElement.getAsJsonArray();
Is there anything I've left out. I wasn't sure if I needed a toString or serialization.
package TestingNonApplication;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.stream.JsonReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* #author Scorchgid
*/
public class GsonTesting {
/**
* #param args the command line arguments
*/
String baseURLStart = "http://api.spotify.com/v1/search?q=\"";
String baseURLEnd = "\"&type=track";
String jsonSource;
public static void main(String[] args) {
try {
GsonTesting gTest = new GsonTesting();
gTest.main2();
} catch (FileNotFoundException ex) {
Logger.getLogger(GsonTesting.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(GsonTesting.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void main2() throws FileNotFoundException, MalformedURLException, IOException {
Scanner commandlineReader = new Scanner(System.in);
String searchString = "";
boolean contin = false;
while (contin == false) {
System.out.println("Enter query");
String query = commandlineReader.nextLine();
searchString = baseURLStart + query + baseURLEnd;
searchString = searchString.replace(" ", "%20");
System.out.println(searchString
+ "\r\n Type Yes to continue or anything else to re enter");
query = commandlineReader.nextLine();
if (query.equalsIgnoreCase("yes")) {
contin = true;
}
}
//----------------------------------------------------------------------
/* Connection and Response */
URLConnection urlConnection = new URL(searchString).openConnection();
urlConnection.connect();
JsonReader reader = new JsonReader(new InputStreamReader(urlConnection.getInputStream()));
JsonParser jsonParser = new JsonParser();
JsonElement rootElement = jsonParser.parse(reader);
JsonArray jArray = rootElement.getAsJsonArray();
List results = new ArrayList();
Gson gson = new Gson();
for (JsonElement spotifyElement : jArray) {
Tracks spot = gson.fromJson(rootElement, Tracks.class);
results.add(spot);
System.out.println(spot.toString());
}
}
}
class Tracks {
String href;
List<Items> items;
public class Items {
Album albums;
public class Album {
String album_type;
String[] available_markets;
External_Urls external_urls;
public class External_Urls {
String spotify;
}
String href;
String id;
List<Image> images;
public class Image {
Integer height;
String url;
Integer width;
}
String name;
String type;
String uri;
List<Artists> artists;
}
List<Artists> artist;
public class Artists {
External_Urls external_urls;
public class External_Urls {
String spotify;
}
String herf;
String id;
String name;
String type;
String uri;
}
String avaliable_markets;
Integer disc_number;
Integer duration;
Boolean explicity;
External_Urls external_ids;
public class External_Ids {
String isrc;
}
External_Urls external_urls;
public class External_Urls {
String spotify;
}
String herf;
String id;
String name;
Integer popularity;
String preview_url;
Integer tracknumber;
String type;
String uri;
}
Integer limit;
String next;
Integer offset;
String previous;
Integer total;
}

Json string is perfect.
There are 4 mistakes in your class to map json to obj. (class Tracks)
external_urls should be an object, not list (at all three places)
artists list should be outside album class.
external_ids should be object, not list (at one place)
spotify member is missing in one external_urls class.
A general advise is to reduce the use of inner classes when using gson (convert your inner classes to normal public classes and create the object instead of the inner class).
Also more readable and reusable code in this case. For example, if you design your external_urls as a separate class you just need one class and can have 3 member obj instead of the 3 inner classes you have now. Gson will work perfectly if you do so.

Related

So I am trying to create this json file using gson

Here is the code I want to create with my Java code. I'm not doing anything elaborate. Just trying to refresh myself with parsing json from java.
[{"county":"Jefferson",
"houses":\[
{"squareFeet":1100,
"bedrooms":2,
"bathrooms":2,
"internet":"y",
"location":"Country"
},
{"squareFeet":750,
"bedrooms":1,
"bathrooms":1,
"internet":"n",
"location":"Town"
}
\]
}]
At the moment my Java code looks like this.
With this code below I am close to having it, with the exception of the first Object, and also the title to the array of houses.
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Formatter;
import java.util.List;
public class HousesToJSON {
/**
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
JSONArray houses = new JSONArray();
House houseOne = createHouseObjectOne();
House houseTwo = createHouseObjectTwo();
houses.add(houseOne);
houses.add(houseTwo);
try (FileWriter writer = new FileWriter("houses.json")) {
gson.toJson(houses, writer);
} catch (IOException e) {
e.printStackTrace();
}
}
private static House createHouseObjectOne() {
House house = new House();
house.setSquareFeet(1100);
house.setBedrooms(2);
house.setBathrooms(2);
house.setInternet('y');
house.setLocation("Country");
return house;
}
private static House createHouseObjectTwo() {
House house = new House();
house.setSquareFeet(750);
house.setBedrooms(2);
house.setBathrooms(1);
house.setInternet('y');
house.setLocation("Town");
return house;
}
}
This create the file below.
[
{
"squareFeet": 1100,
"bedrooms": 2,
"bathrooms": 2,
"internet": "y",
"location": "Country"
},
{
"squareFeet": 750,
"bedrooms": 2,
"bathrooms": 1,
"internet": "y",
"location": "Town"
}
]
I am still pretty new at this, and any help would be much appreciated.
Something along the lines of this should provide you with the neccesary objects for your JSON example:
package com.example;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class CountyContainer {
#SerializedName("county")
#Expose
private String county;
#SerializedName("houses")
#Expose
private List<House> houses = null;
public String getCounty() {
return county;
}
public void setCounty(String county) {
this.county = county;
}
public List<House> getHouses() {
return houses;
}
public void setHouses(List<House> houses) {
this.houses = houses;
}
}
package com.example;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class House {
#SerializedName("squareFeet")
#Expose
private Integer squareFeet;
#SerializedName("bedrooms")
#Expose
private Integer bedrooms;
#SerializedName("bathrooms")
#Expose
private Integer bathrooms;
#SerializedName("internet")
#Expose
private String internet;
#SerializedName("location")
#Expose
private String location;
public Integer getSquareFeet() {
return squareFeet;
}
public void setSquareFeet(Integer squareFeet) {
this.squareFeet = squareFeet;
}
public Integer getBedrooms() {
return bedrooms;
}
public void setBedrooms(Integer bedrooms) {
this.bedrooms = bedrooms;
}
public Integer getBathrooms() {
return bathrooms;
}
public void setBathrooms(Integer bathrooms) {
this.bathrooms = bathrooms;
}
public String getInternet() {
return internet;
}
public void setInternet(String internet) {
this.internet = internet;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
You can generate these yourself using this online service and selecting the GSON annotation style:
http://www.jsonschema2pojo.org/
When you've created your objects, you can write those objects to a JSON file using:
final Gson gson = new Gson();
try (final FileWriter writer = new FileWriter("houses.json")) {
gson.toJson(houses, writer); // houses refers to your object containing the List of House objects and the country
} catch (final IOException e) {
// Handle exceptions here
}
Alternatively, you can also use place the JSON data into a String:
String json = gson.toJson(houses);
For more information regarding GSON functionality, please take a look at the official documentation:
https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/module-summary.html
There is no House class provided, but I guess we can skip it. You are moving in the right direction. Just add another class:
public class County {
private String county;
private List<House> houses;
// getters, setters, whatever :)
}
And create instance of this class. Set name (county field) and houses and serialize to JSON :)
I would probably rename json array to JSONArray counties = new JSONArray(); and what you need to add to this array is some county with name "Jefferson" and list of houses that you have now.
County county = new County();
county.setCounty("Jefferson");
List<House> houses = new ArrayList<>();
houses.add(houseOne);
houses.add(houseTwo);
county.setHouses(houses);
counties.add(county);
This might not be 100% working code, but hope the idea is clear :)

Two differents types of responses in POJO

I'm using Retrofit with POJO, which usually works, but the answer has two different objects depending on whether the result is valid. Which one is a String and the another is an Object:
{
"data":"No results."
}
or:
{
"data": {
"exame": [
{
"id": 776,
"codigo": "DHT",
"instrucao": "- Text."
},
{
"id": 776,
"codigo": "DHT",
"instrucao": "- Text"
}
]
}
}
And my class:
public class Exame {
#SerializedName("data")
#Expose
#Nullable
private ExameItem exameItem;
private String mensagem;
public ExameItem getExameItem() {
return exameItem;
}
public void setExameItem(ExameItem exameItem) {
this.exameItem = exameItem;
}
public String getMensagem() {
return mensagem;
}
public void setMensagem(String mensagem) {
this.mensagem = mensagem;
}
}
When I do Exame().getExameItem its fine, but when I try test if have a message in Exame().getMessagem its bring me a this error:
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 10 path $.data
So, I think how can I test if #data is a String of an Object, but I don't kwon how, anyone may help?
You need to implement custom deserialiser by implementing JsonDeserializer interface. See below example:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.annotations.JsonAdapter;
import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Type;
import java.util.List;
public class GsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
Gson gson = new GsonBuilder().create();
System.out.println(gson.fromJson(new FileReader(jsonFile), Exame.class));
}
}
class ExamsJsonDeserializer implements JsonDeserializer<Exame> {
#Override
public Exame deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject root = json.getAsJsonObject();
JsonElement data = root.get("data");
Exame exam = new Exame();
if (data.isJsonPrimitive()) {
exam.setMensagem(data.getAsString());
} else {
ExameItem examItem = context.deserialize(data, ExameItem.class);
exam.setExameItem(examItem);
}
return exam;
}
}
#JsonAdapter(ExamsJsonDeserializer.class)
class Exame {
private ExameItem exameItem;
private String mensagem;
// getters, setters, toString
}
class ExameItem {
private List<Item> exame;
//getters, setters, toString
}
class Item {
private int id;
// ...
//getters, setters, toString
}

Having issue collecting Json object and array with java

First of all, i am new to this so please pardon me. Have been working on a music app and I am trying to parse JSON code from a streaming link and display "artist" name and "title" of song to my app users. But i am having issues collecting the data.
Here is my JSON code from the streaming link:
{"type":"result","data":[{"title":"My Stream ","song":"Unknown - The Authorised One","track":{"artist":"Unknown Artist","title":"The Authorised One","album":"Unknown","royaltytrackid":181938.0000,"started":1498151105,"id":181938,"length":0,"playlist":{"id":3520,"title":"Rev Arome E. Adah"},"buyurl":"https:\/\/itunes.apple.com\/us\/album\/the-unknown-god\/id772022436?uo=4","imageurl":"http:\/\/is5.mzstatic.com\/image\/thumb\/Music5\/v4\/d7\/6d\/52\/d76d52df-db43-7130-0e37-62241ff50a21\/source\/100x100bb.jpg"},"bitrate":"128 Kbps","server":"Online","autodj":"Online","source":"Yes","offline":false,"summary":"<a href=\"http:\/\/cp9.serverse.com:2199\/tunein\/-stream\/svhxmwhp.pls\">Eloti Designs Stream - Unknown - The Authorised One<\/a>","listeners":0,"maxlisteners":1000,"reseller":0,"serverstate":true,"sourcestate":true,"sourceconn":1,"date":"Jun 22, 2017","time":"07:06 PM","rawmeta":"Unknown - The Authorised One ","mountpoint":"\/stream","tuneinurl":"http:\/\/209.133.216.3:7550\/stream","directtuneinurl":"","proxytuneinurl":"http:\/\/209.133.216.3\/proxy\/svhxmwhp?mp=\/stream","tuneinformat":"mp3","webplayer":"muses","servertype":"ShoutCast2","listenertotal":0,"url":"http:\/\/cp9.serverse.com:2199\/rpc"}]
I used this code to post "artist" name of "Unkwown Artist" to my text field but it didn't work for me.
JSONObject parentObject = new JSONObject(finalJson);
JSONArray parentArray = parentObject.getJSONArray("data");
JSONObject finalObject = parentArray.getJSONObject(0);
String songName = finalObject.getString("artist");
return songName;
track is a jsonobject containing artist and track is inside first jsonobject of
data array so fetch track then fetch artist from it
String songName = finalObject.getJSONObject("track").getString("artist");
{
"type":"result",
"data":[ // fetch JSONArray
{ // fetch first JSONObject
"title":"My Stream ","song":"Unknown - The Authorised One",
"track":{ // fetch track JSONObject
"artist":"Unknown .." // fetch string
Have you tried the jackson parser? It's super easy to use and can easily parse the string above. All you need to do is create 3/4 POJO classes that map your structure and then apply the readValue function of the Mapper to the outer class. Following is a small example with a List and one inner class:
import java.io.IOException;
import java.util.List;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
class OutterPojo {
public String aString;
public List<InnerPojo> aList;
public String getaString() {
return aString;
}
public void setaString(String aString) {
this.aString = aString;
}
public List<InnerPojo> getaList() {
return aList;
}
public void setaList(List<InnerPojo> aList) {
this.aList = aList;
}
#Override
public String toString() {
return new StringBuilder().append("{ #OutterPojo# ").append("aString:").append(aString).append(", ").append("aList:")
.append(aList).append(" }").toString();
}
}
class InnerPojo {
public String anotherString;
public String getanotherString() {
return anotherString;
}
public void setanotherString(String anotherString) {
this.anotherString = anotherString;
}
#Override
public String toString() {
return new StringBuilder().append("{ #InnerPojo# ").append("anotherString:").append(anotherString).append(" }")
.toString();
}
}
public class Test {
public static void main(String args[]) throws JsonParseException, JsonMappingException, IOException {
String jsonData = "{\"aString\":\"s\",\"aList\":[{\"anotherString\":\"ss\"},{\"anotherString\":\"sss\"}]}";
ObjectMapper objectMapper = new ObjectMapper();
OutterPojo testObject = objectMapper.readValue(jsonData, OutterPojo.class);
System.out.println(testObject);
}
}
As to dependencies all you need for this to work is jackson-core, jackson-databind and jackson-annotations - here's the link to maven:
https://mvnrepository.com/artifact/com.fasterxml.jackson.core
Hope it helps! :)

JSON text to Java conversion issue with random number generation

For example my JSON text is coming like this.
"pages":{"42010":{"pageid":42010,"ns":0,"title":"Queen (band)"}}
Because everytime my json text is coming with different number which is inside pages tag.
How do i convert this to Java equivalent class?
Currently my generated java class is something like this.
#Generated("org.jsonschema2pojo")
public class Pages {
#SerializedName("42010")
#Expose
private _42010 _42010;
}
That _42010 class contains the inner fields like "pageid":42010,"ns":0,"title":"Queen (band)", since i am getting everytime new number inside pages, its not working. its working only for the specific json text.
You can use a custom deserialiser that ignored the changing number. For example:
package jacksonTest;
import java.io.IOException;
import java.lang.reflect.Type;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
public class CustomDeserialiser {
public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
String json = "{\"42010\":{\"pageid\":42010,\"ns\":0,\"title\":\"Queen (band)\"}}";
String json2 = "{\"12345\":{\"pageid\":12345,\"ns\":0,\"title\":\"Queen (band)\"}}";
Gson g = new GsonBuilder().registerTypeAdapter(Pages.class, new PagesDeserialiser()).create();
Pages fromJson = g.fromJson(json, Pages.class);
System.out.println(fromJson);
fromJson = g.fromJson(json2, Pages.class);
System.out.println(fromJson);
}
public static class PagesDeserialiser implements JsonDeserializer<Pages> {
#Override
public Pages deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws com.google.gson.JsonParseException {
JsonObject object = json.getAsJsonObject();
Pages p = new Pages();
object.entrySet().forEach( e -> {
JsonObject tmp = e.getValue().getAsJsonObject();
if(tmp.get("pageid") != null) {
// right object
p._42010 = new _42010();
p._42010.ns = tmp.get("ns").getAsInt();
p._42010.pageid = tmp.get("pageid").getAsInt();
p._42010.title = tmp.get("title").getAsString();
}
});
return p;
}
}
public static class Pages {
_42010 _42010;
#Override
public String toString() {
return _42010.toString();
}
}
public static class _42010 {
int pageid;
int ns;
String title;
#Override
public String toString() {
return title + " " + pageid + " " + ns;
}
}
}
The deserialiser for type pages simply checks the entries to find the one that contains a pageId and then populates the class.
Running my test gives you:
Queen (band) 42010 0
Queen (band) 12345 0
I am assuming that you are using Gson as your json library.
Regards,
Artur
Why do not use an JSON library like jackson or org.json?
Make your json correct like
{
"pages":{
"42010":{
"pageid":42010,
"ns":0,
"title":"Queen (band)"
}
}
}
And you will be able to use it like :
JSONObject jsonObjet = new JSONObject(yourJson);
jsonObjet.get("pages");
Ideally it should be using Map.
This helps in forming the values as Map<Integer, Pojo>.
Lets say
public class Pojo{
private int pageid;
private String title;
private int ns;
// getter and setter
}
This suffices the requirement of holding the random digits, generated at runtime,

Array Json to List<MyObject> with Gson or Xtream

Hello I had this follow json code.
[{"check":{"domain":"qwe.coedu.br"}},{"check":{"domain":"qwe.com.br"}},{"check":{"domain":"qwe.com"}}]"
How do to convert this json in my object
class Check {String domain , String status ...}
It return a List<Check>, but the Check attributes are null. See my code. with Gson.
Gson gson = new Gson();
Type fooType = new TypeToken<Collection<Check>>(){}.getType();
System.out.println(((List<Check>)gson.fromJson("[{\"check\":{\"status\":\"2\",\"domain\":\"william.com.br\"}}]", fooType)).get(0).getDomain());
When I debug my returned list, this contains all objects in list, but all with your attributes null.
What is wrong ?
You need a customized converter, because you have a list of objects that holds a property named check. And this property is of a class that has the properties domain and status.
Two possibilities here:
if you don't want to change the Json format, or you simply can't probably write your own JsonDeserializer, in which you will instanciate your Check object and then set the properties by your own is the best choice;
or you could modify your check class in order to hold a check property of a type that holds a property named domain and another one status.
For the second case is pretty clear what needs to be done, but for the first case you could do something like:
import java.lang.reflect.Type;
import java.util.Collection;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
public class GsonTestClass {
static class MyDeserializer implements JsonDeserializer<Check> {
public Check deserialize(JsonElement arg0, Type arg1,
JsonDeserializationContext arg2) throws JsonParseException {
JsonObject jsonObject = arg0.getAsJsonObject().get("check").getAsJsonObject();
// this code could be improved with null checks and so on...
return new Check( //
jsonObject.get("domain").getAsString(), //
jsonObject.get("status").getAsString() //
);
}
}
public static void main(String args[]) {
Gson gson = new GsonBuilder().registerTypeAdapter(Check.class, new MyDeserializer()).create();
String json = "[{\"check\":{\"status\":\"2\",\"domain\":\"william.com.br\"}}]";
Type fooType = new TypeToken<Collection<Check>>() {}.getType();
System.out.println((gson.fromJson(json, fooType)));
}
static class Check {
private String domain;
private String status;
public Check() {
}
public Check(String domain, String status) {
super();
this.domain = domain;
this.status = status;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
#Override
public String toString() {
return "Check: " + domain + " - " + status;
}
}
}
Your Java class Check with its fields domain and status corresponds to
{"status":"2","domain":"william.com.br"}
in JSON, so a JSON "equivalent" of List<Check> would be
[{"status":"1","domain":"qwe.coedu.br"},{"status":"1","domain":"qwe.com.br"}]
Your JSON has another level of object nesting, where each list entry is an object with one property named check. Either restructure you JSON to remove the seemingly unnecessary nesting, or deserialize into e.g.
List<Map<String,Check>>

Categories

Resources