gson de-serialising object array without identifier - java

Im getting an error trying to take a json array to a list of objects, the exception is as below.
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 170
here is the code i am trying to use
public static void main(String[] args) throws FileNotFoundException {
Gson gson = new Gson();
Test test = new Test();
JsonElement json = gson.fromJson(test.getFile("fieldTypes.json"), JsonElement.class);
String result = gson.toJson(json);
System.out.println(result);
Type listType = new TypeToken<ArrayList<JiraField>>(){}.getType();
JiraField[] jiraFields = gson.fromJson(result, listType);
for (JiraField jiraField : jiraFields) {
System.out.println(jiraField);
}
}
This is the file contents
[
{
"id": "issuetype",
"key": "issuetype",
"name": "Issue Type",
"custom": false,
"orderable": true,
"navigable": true,
"searchable": true,
"clauseNames": [
"issuetype",
"type"
],
"schema": {
"type": "issuetype",
"system": "issuetype"
}
},
{
"id": "timespent",
"key": "timespent",
"name": "Time Spent",
"custom": false,
"orderable": false,
"navigable": true,
"searchable": false,
"clauseNames": [
"timespent"
],
"schema": {
"type": "number",
"system": "timespent"
}
}
]
The file is being read from the resources folder but that is working fine and the sysout is correctly showing the json contents. i assume there is something im doing wrong ?

ok, so. turns out to be caused by un mapped fields, this is how i got it working
in the object you add the #Expose annotation for the fields you want
public class JiraField {
#Expose
private String id ;
#Expose private String key ;
#Expose private String name ;
#Expose private boolean custom ;
#Expose private boolean orderable ;
#Expose private boolean navigable ;
#Expose private String[] clauseNames ;
Then when you initialise gson, you do it like this
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
then it works :)
JiraFields{id='issuetype', key='issuetype', name='Issue Type', custom=false, orderable=true, navigable=true, clauseNames=[issuetype, type]}
JiraFields{id='timespent', key='timespent', name='Time Spent', custom=false, orderable=false, navigable=true, clauseNames=[timespent]}

Try this:
Type listType = new TypeToken<ArrayList<JiraField[]>>(){}.getType();
I think we need to specify the JiraField[] in-order to get Array.

I'm assuming you have a minified JSON according to the exception message ...at line 1 column 170.... It would be nice if you provide both exact your exact JSON document and your mapping as well, since the posted formatted JSON now has the layout destroyed. I'm also assuming your mapping is custom and basically something like:
final class JiraField {
#SerializedName("id")
final String id = null;
#SerializedName("key")
final String key = null;
#SerializedName("name")
final String name = null;
#SerializedName("custom")
final boolean isCustom = Boolean.valueOf(false);
#SerializedName("orderable")
final boolean isOrderable = Boolean.valueOf(false);
#SerializedName("navigable")
final boolean isNavigable = Boolean.valueOf(false);
#SerializedName("searchable")
final boolean isSearchable = Boolean.valueOf(false);
#SerializedName("clauseNames")
final List<String> clauseNames = null;
#SerializedName("schema")
final List<String> schema = null;
}
Note the JiraField.schema field type: it's a list. Trying to deserialize a list of JiraFields with the default Gson configuration would result into:
java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 170 path $[0].schema
The symptom and the column are exactly the same (however, again, I'm just assyming your JSON file is minified), but note the path $[0].schema you probably missed to post: it says that an array begin token [ is expected (since the field is a List<String>), but was an object begin token {. Changing the field type to a more appropriate arbitrary Map<String, String> or any other custom appropriate POJO would fix it. Partially.
#SerializedName("schema")
final Map<String, String> schema = null;
Why partially? Your type token is bound to an ArrayList, but you're casting the deserialization result to an array JiraField[], therefore you'd get something like this:
Exception in thread "main" java.lang.ClassCastException: java.util.ArrayList cannot be cast to [LJiraField;
To fix it, you have to declare your jiraFields variable matching the deserialized value type: it's an array list, but not an array -- these are not the same in Java.
List<JiraField> jiraFields = ...
Another note regarding deserialization is that you don't need an intermediate json object to deserialize from. test.getFile most likely returns a java.io.Reader, so you can pass it directly to deserialize. Summarizing all up, the following should work for you:
// Immutable and thread-safe, can be instantiated once and shared
private static final Gson gson = new Gson();
// Immutable and thread-safe value type, the same story, + List instead of ArrayList - interfaces are usually much better
private static final Type listType = new TypeToken<List<JiraField>>() {
}.getType();
public static void main(final String... args)
throws IOException {
try ( final Reader reader = test.getFile("fieldTypes.json") ) {
final List<JiraField> jiraFields = gson.fromJson(reader, listType);
for ( final JiraField jiraField : jiraFields ) {
System.out.println(jiraField.key + " => " + jiraField.name);
}
}
}
Output:
issuetype => Issue Type
timespent => Time Spent

Type listType = new TypeToken<ArrayList<JiraField>>(){}.getType();
ArrayList<JiraField> jiraFields = gson.fromJson(result, listType);
for (JiraField jiraField : jiraFields) {
System.out.println(jiraField);
}
Try This code

Comment this line
Type listType = new TypeToken<ArrayList<JiraField>>(){}.getType();
Try with this
JiraField[] jiraFields = gson.fromJson(result, JiraField[].class);

Related

How to convert an json response like that?

I have a json reponse like given below.Basically,I want to convert an object and use it.
[
{
"Id": 1290,
"N": "Türkiye",
"Fid": 196,
"EC": 10,
"CL": null,
"SID": 0
},
{
"Id": 1239,
"N": "Dünya",
"Fid": 152,
"EC": 63,
"CL": null,
"SID": 0
}
]
... Goes on
Here is what I have tried,I am using org.json library.
String jsonString = response.body().string(); // Getting json response and converting to string.
JSONObject jsonResponse = new JSONObject( jsonString ); // Not working
JSONArray jsonArray = new JSONArray( jsonString ); // Not working
JSONArray matches = new JSONArray( jsonString ).getJSONArray(0); // Not working
But I am gettin those errors
A JSONObject text must begin with '{' at 0 [character 1 line 1]
A JSONArray text must begin with '{' at 0 [character 1 line 1]
I have checked topics like Parse JSON Array without Key. But the json described not like mine.
Any idea what should ı do?
in Java you would first need to define a class which has all the attributes
public class MyClass {
private int Id;
private int N;
private int Fid;
private int EC;
private int CL;
private int Sid;
// getters, setters, no arg constructor
}
then you can use for example gson library to parse it like this:
MyClass[] myClassArray = gson.fromJson(jsonString , MyClass[].class)
I really recommend you to use the Gson library it's way better to perform data operations:
public class User {
int id;
String n;
int fid;
int ec;
String cl;
int sid;
public static User[] parse(String s){
return new GsonBuilder().create().fromJson(s, User[].class);
}
}
Have you looked into Google's Gson? It is really easy to use and you can both serialize and deserialize objects.
Here is an example:
public Company[] deserializeCompany() {
Gson gson = new Gson();
Company[] companies = gson.fromJson(companiesJSON, Company[].class);
return companies;
}
First you need to make a template class that has a member field for each key in the json. E.g. private String id for the 'Id' key in the json you provided. In my example it is the Company class.
Next you make a new Gson object using Gson gson = new Gson(); and use the .fromJson function supplying it both the Json array and the Object array type (which is of the form MyClass[].class).
First, your question is not to convert a JSON array without key. Second, there are many popular JSON libraries can achieve what you want such as org.json, Jackson, Gson and so on.
Here comes several examples:
With org.json, you can retrieve field values in a JSON array as follows:
JSONArray jsonResponse = new JSONArray(jsonStr);
System.out.println(jsonResponse.get(0).toString());
System.out.println("Id: " + jsonResponse.getJSONObject(0).get("Id"));
System.out.println("N : " + jsonResponse.getJSONObject(0).get("N"));
And the expected output should be:
{"Fid":196,"CL":null,"Id":1290,"N":"Türkiye","EC":10,"SID":0}
Id: 1290
N : Türkiye
With Jackson, you can retrieve field values in a JSON array as follows:
ObjectMapper objectMapper = new ObjectMapper();
List<Map<String, Object>> jsonResponse = objectMapper.readValue(jsonStr, new TypeReference<List<Map<String, Object>>>() {});
System.out.println(jsonResponse.toString());
System.out.println("Id: " + jsonResponse.get(0).get("Id"));
System.out.println("N : " + jsonResponse.get(0).get("N"));
And the expected output should be:
{Id=1290, N=Türkiye, Fid=196, EC=10, CL=null, SID=0}
Id: 1290
N : Türkiye
3. Furthermore, if you define a POJO as follows:
class MyObject {
private #JsonProperty("Id") int id;
private #JsonProperty("N") String n;
private #JsonProperty("Fid") int fid;
private #JsonProperty("EC") int ec;
private #JsonProperty("CL") int cl;
private #JsonProperty("SID") int sid;
//general getters, setters and toString
}
Then you can deserialize the JSON response to your POJO by:
ObjectMapper objectMapper = new ObjectMapper();
List<MyObject> jsonResponse = objectMapper.readValue(jsonStr, new TypeReference<List<MyObject>>() {});
System.out.println(jsonResponse.get(0).toString());
System.out.println("Id: " + jsonResponse.get(0).getId());
System.out.println("N : " + jsonResponse.get(0).getN());
And the expected output should be:
MyObject{id=1290, n='Türkiye', fid=196, ec=10, cl=0, sid=0}
Id: 1290
N : Türkiye

How to I check int field is null for gson? [Android]

I want to serialize nulls for a specific field or class.
I've also researched stackoverflow but couldn't see a result.
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.serializeNulls().create();
I used it but it did not work.
My Json result is two type. Pojo crashes when it's like the first case.
"character": {
"id": "",
"name": ""
},
"character": {
"id": 10,
"name": "İrem"
}
My crash's log:
com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: empty String
at com.google.gson.internal.bind.TypeAdapters$7.read(TypeAdapters.java:228)
at com.google.gson.internal.bind.TypeAdapters$7.read(TypeAdapters.java:218)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222)
My Pojo
#SerializedName("name")
private String name;
#SerializedName(value = "id")
private Integer id; // or private int id; Both are failing.
1) First option, not receive a String. If the number is not available, you should be receiving null instead. So it would look like this:
"character": {"id": null,"name": null}
This would solve the issue.
2) Second option - change your data model to not look for Integer, instead just an Object. But this means more validation work for you.
#SerializedName("name")
private String name;
#SerializedName(value = "id")
private Object id;
So once you parse it like this:
MyPojo pojo = gson.fromJson(jsonString, MyPojo.class);
You will have to do this to use the id field:
if(pojo.getId() instanceof Integer) {
// you know you have a number
} else if (pojo.getId() instanceof String) {
// you know it's not a valid number
}
That's it!
3) third option: have two data model.
First one for Integer:
#SerializedName("name")
private String name;
#SerializedName(value = "id")
private Integer id;
Second one for String:
#SerializedName("name")
private String name;
#SerializedName(value = "id")
private String id;
So when you parse it, you parse it to a JsonObject:
JsonObject jsonObject = gson.fromJson(jsonString, JsonObject.class);
Then check which one you need to map to:
try {
Integer id = jsonObject.get("id").getAsInt();
// it's a number!!
MyIntegerPojo integerPojo = new Gson().fromJson(jsonObject, MyIntegerPojo.class);
} catch (ClassCastException e) {
// it's not a number
MyStringPojo stringPojo = new Gson().fromJson(jsonObject, MyStringPojo.class);
}
I really recommended the first option - it is cleaner and it would be the right way to do it.
Your problem is the id is String not an Integer in
"character": {
"id": "",
"name": ""
}
You should fix it from the backend.
Possible solutions are 2:
BE has to be consistent on this field and always provide a String or a Number (accepted by Json - there's not such a Double or Integer in Json).
Follow this small tutorial which tells you how to create a custom parser for your classes.
What you want to do is check for the instance of id when parsing it, and always use an Integer (or a null value) if an empty/invalid String is provided.
If you want to prevent Null Pointer Exceptions during reading json values, you can also do the following method:
1.) convert to com.google.gson.JsonObject
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
...
JsonObject convertedJsonObject = JsonParser.parseString( jsonString);
2.) Check if element exist and is not JsonNull
if( convertedJsonObject.has("key") && !convertedJsonObject.get("key").isJsonNull()){
... do your variable assignment
}

Jackson - Json string to Java List of class

I am trying to map a JSON string to a Java class using Jackson.
public class ChartData {
List<String> xAxis=new ArrayList<String>();
List<String> yAxis=new ArrayList<String>();
List<String> zAxis=new ArrayList<String>();
String type;
public ChartData() {
}
public ChartData(String type, List<String> yAxis, List<String> zAxis) {
this.type = type;
this.yAxis = yAxis;
this.zAxis = zAxis;
}
The code I tried :
List<ChartData> emp = new ArrayList<>();
String o2 ="[{\"type\": \"2\", \"yAxis\": [\"11\"], \"zAxis\": [\"8\"]}, {\"type\": \"3\",
\"yAxis\": [\"17\", \"13\", \"12\"], \"zAxis\": [\"14\", \"13\", \"12\"]}]";
ObjectMapper mapper = new ObjectMapper();
data= (List<ChartData>) mapper.readValue(o2, ChartData.class);
return data;
But, I am getting the following error:
Can not deserialize instance of com.ChartData out of START_ARRAY token
at [Source: [{"type": "2", "yAxis": ["11"], "zAxis": ["8"]}, {"type":
"3", "yAxis": ["17", "13", "12"], "zAxis": ["14", "13", "12"]}]; line:
1, column: 1]
Where is my mistake?
There is a specific way to deserialize into list in jackson:
List<ChartData> data = mapper.readValue(o2 , new TypeReference<List<ChartData>>(){});
In your code you have also type mismatch in the conversion. You are using mapper.readValue(o2, ChartData.class) but you are casting it to List<ChartData>.
To maintain the basic type conversion (without TypeReference) you can deserialize the json into array in the following way:
ChartData[] data = mapper.readValue(o2 , ChartData[].class);
and afterwards convert it to a list if you need to.

Java - How can i read json file and put values into array

I have this JSON file called city.list.json, containing objects like these:
{
"id": 707860,
"name": "Hurzuf",
"country": "UA",
"coord": {
"lon": 34.283333,
"lat": 44.549999
}}
How can I put name's value into array?
This is the code I've tried:
String name = null;
JSONArray jsonArr = new JSONArray("[JSON String]");
ArrayList<Data> dataList = new ArrayList<>();
for (int i = 0; i < jsonArr.length(); i++) {
JSONObject jsonObj = jsonArr.getJSONObject(i);
Data data = new Data();
data.name = jsonObj.getString("name");
dataList.add(data);
}
But it gives me errors on data saying "Constructor Data in class Data cannot applied to given types"
You can use GSON library to achieve this task:
String input = yourSampleJson;
Gson gson = new Gson();
Map<String,Object> inputPojo = new HashMap<>();
inputPojo = gson.fromJson(input, inputPojo.class); // This map now contains the representation of your JSON.
I generally prefer having a POJO class which represents your JSON structure something as :
Class DanielePojo {
Integer id;
String name;
String country;
Coord coord; // This is another class similar to this POJO which is represented as Object in your JSON
// Then your getters and setters
}
Then you can convert JSON into Pojo object directly without having a MAP as an intermediate object.
DanielePojo pojo = new GSON.fromJSON(input,DanielePojo.class);

converting string to gson object

I have a string output from server and I am trying to extract some values form the string.
Here is the output from server:
jsonString =
{
"MEANING":"reduce",
"DISPLAY":"",
"TYPE_CD":1,
"SELECTED_IND":1,
"CNT":1,
"SOURCES":[
{ "a":1 }
]
}
Code:
JsonReader reader = new JsonReader(new StringReader(jsonString));
DataObject obj1 = new Gson().fromJson(reader, DataObject.class);
DataObject Class:
DataObject
{
private int MEANING;
private int CNT;
private String TYPE_CD;
private String DISPLAY;
private String MEANING;
private List<Long> SOURCES;
public String getSourceTypeMeaning()
{
return this.MEANING;
}
public String getSourceTypeDisplay()
{
return this.DISPLAY;
}
public String getSourceTypeCd()
{
return this.TYPE_CD;
}
public int getSourceCount()
{
return this.CNT;
}
public List<Long> getSourceList()
{
return this.SOURCES;
}
}
but getting this error
Expected a string but was BEGIN_OBJECT at line 1 column 132
I am not able to find the issue with my code.
Other answers are pointing out that the problem is in the SOURCES field, and that's true, but the solutions they're giving are not correct...
You can't use just a Map to parse the SOURCES field, because this field is indeed an array! You have:
"SOURCES": [ ... ]
Since you have square brackets [ ], you have an array! And it's true there's a Map, but it is contained in the array...
So, what you need to parse that field correctly is:
private List<Map<String, int>> SOURCES;
Note that we use a Map to allow the content of SOURCES to have multiple and unknown values, so that this code could parse not only your JSON, but also something like:
"SOURCES":[
{ "a":1, "b":2 },
{ "c":3 },
{ "x":99, "y":98, "z":97 }
]
SOURCES variable should be Map<String,Long>,because in JSON string SOURCES is key-value collection ("a":1) where "a" is string and 1 is number.
Hope this helps.
Check this
"SOURCES":[
{ "a":1 }
]
This will represent a List of map not List of long.
So change your List<long> to List<Map<String, Long>> or List<Map<Object, Long>>.

Categories

Resources