Parsing Dynamically wrapped JSON array - java

I have an Abstract class with many concrete implementations:
public abstract Ticket {
private Long id;
private Currency fine;
...
}
public class SpeedingTicket extends Ticket {
public Currency getFine(){
// Expensive!
...
}
}
public class ParkingTicket extends Ticket {
public Currency getFine(){
// Eh, not so bad
...
}
}
When the concrete classes are serialized into JSON, it is wrapped with the classes simple name (speedingTickets or parkingTickets):
"_embedded": {
"speedingTickets" :
[{
"id":1,
"fine": "$190",
...,
},
{
"id":2,
"fine": "$100",
...,
}]
}
or
"_embedded": {
"parkingTickets" :[{
"id":100,
"fine": "$15",
...,
}]
}
Since I do not know, at runtime, which Ticket implementation I am receiving back, how can I parse the JSON out using the JSON Response API given the array is wrapped with the concrete implementations simple name?
I have a hack where I take the String value of the JSON and do String operations (substring, indexOf, etc) on it to return only what's in between the braces ("[...]"). I know there's a better way to do this...
After some research, I think I'll try the following tomorrow to see if it works:
JsonNode rootNode = mapper.readTree(jsonResponse);
String classImpl = Iterables.get(rootNode.get("_embedded").fields(), 0).textValue()
I can then say List<Ticket> tickets = response.readAsList(jsonResponse, "_embedded",classImpl) which should allow me to parse the JSON into a List

If you're using Jackson (as your tag suggests), you want to use Polymorphic Deserialization - which is exactly the problem of knowing how to deserialize to the correct subtype.
For example:
#JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="#class")
class { }
What this essentially does is include the class name in your JSON, so the deserializer has enough information to properly choose the subclass to instantiate. Something like this:
"_embedded": {
"parkingTickets" :[{
"_type": "ParkingTicket.class",
"id":100,
"fine": "$15",
...,
}]
}

You can just check the type by checking the variable the response contains.
JSONObject jsonObj = new JSONObject(response);
if(jsonObj.has("speedingTickets")){
// parse speedingTickets
}else if(jsonObj.has("parkingTickets")){
// parse parkingtickets
}

A JSON object is an unordered set of key/value pairs. A JSON array is an ordered collection of values. The values themselves could be objects or arrays.
In java it is easy to parse json with org.json library https://github.com/stleary/JSON-java
Short example how to parse json array:
String str = "{ \"number\": [3, 4, 5, 6] }";
JSONObject obj = new JSONObject(str);
JSONArray arr = obj.getJSONArray("number");
for (int i = 0; i < arr.length(); i++)
System.out.println(arr.getInt(i));

Related

java jackson parse json array

I need help with parsing, I've tried to create a different kind of model classes, but no use, please help me out here. the json looks like this:
[
[
1518909300000,
"0.08815700",
"0.08828700",
"0.08780000",
"0.08792900",
"1727.93100000",
1518910199999,
"152.11480375",
5118,
"897.71600000",
"79.04635703",
"0"
],
[
1518910200000,
"0.08788400",
"0.08824200",
"0.08766200",
"0.08810000",
"1789.81300000",
1518911099999,
"157.20177729",
6201,
"898.89500000",
"78.95697080",
"0"
]
]
and I'm trying to parse it using data class:
#JsonIgnoreProperties(ignoreUnknown = true)
public class KlineResponse {
public List<Kline> getKlineList() {
return klineList;
}
public List<Kline> klineList;
public class Kline {
#JsonProperty("4")
Double close;
#JsonProperty("8")
Integer tradesNumber;
public Double getClose() {
return close;
}
public void setClose(Double close) {
this.close = close;
}
public Integer getTradesNumber() {
return tradesNumber;
}
public void setTradesNumber(Integer tradesNumber) {
this.tradesNumber = tradesNumber;
}
}
}
and this line
mapper.readValue(response.getBody(), new TypeReference<List<KlineResponse>>(){})
or
mapper.readValue(response.getBody(), KlineResponse.class)
but each time the error:
Can not deserialize instance of pt.settings.model.KlineResponse out of START_ARRAY token,
please help
The core issue is that you receive an array of arrays where you expect and array of objects. Changing mapper.readValue(response.getBody(), KlineResponse.class) to mapper.readValue(response.getBody(), Object[].class) confirms it.
You have a couple of options on how to proceed:
Change from Jackson to standard JSON parsing, as suggested by #cricket_007 on his answer
Instead of mapping it to an object try to access the JSON differently. See #jschnasse's answer for an example.
Change the format of text you parse, if you can
If you can't change the format of the input then you can either
Create a constructor and annotate it with #JsonCreator, like instructed here
Parse the input as Object array and feed the parsed array into a constructor of your own
You don't need any java classes. There are no JSON objects to deserialize, only arrays.
In the second case, Jackson is expecting { "klineList": [] }
In the first, [{ "klineList": [] }, { "klineList": [] }]
And a Kline object is only parsable as {"4": 0.0, "8": 0 } (replace zeros with any value of same type)... So really unclear why you expected that to work given that data... The annotations are not the index of the lists.
Plus, your lists have both strings and integers, so you can only deserialize as TypeReference<List<List<Object>>>, then iterate that to parse ints, floats, or strings
I might recommend you use a standard json parser, not an objectmapper
Use JsonNode together with JPointer. Avoid to create a POJO and work directly on the data via JsonNode.
ObjectMapper mapper = new ObjectMapper();
JsonNode matrix = mapper.readValue(in, JsonNode.class);
matrix.forEach(array -> {
System.out.println("Next Values:");
System.out.println(array.at("/4").asDouble());
System.out.println(array.at("/8").asInt());
});
Prints
Next Values:
0.087929
5118.0
Next Values:
0.0881
6201.0

Changing JSON array to to a pojo object array

I am getting API response on the following format. I am working on Android project
{
Course: [
{
"Year": 2017,
"CourseTitle": "..",
"Quarter": "autumn",
},
{
"Year": 2017,
"CourseTitle": "..",
"Quarter": "autumn",
}
],
Instructor: {
"name": ,
"address":
}
}
My goal is to get Course array of courses, and assign it to the POJO (plain old java object) that I created using online tool. I am also using the GSON library. I did find different implementation online, and I finally used this, and I was able to filter the nested object "Courses", which holds an array object of courses.
JsonParser parser = new JsonParser();
JsonObject element = (JsonObject)parser.parse(response);
JsonElement responseWrapper = element.getAsJsonArray("Courses");
When I look responseWrapper using debugger tool, it holds a JSON array of course (objects). I wanted to assign these data to the "Course" POJO class I created
public class Course implements Parcelable {
private String href;
private int year;
private String courseTitle;
private String quarter;
private String courseTitleLong;
private String curriculumAbbreviation;
private String courseNumber;
}
I added the following line.
Course[] courseList = gson.fromJson(responseWrapper,Course[].class);
CourseList is an array of Course object, but when I look what I got using debugger tool all the field variables are "null". How could I solve this problem? Is there a better way I should have approached? The whole purpose is getting array of course objects so I could manipulate it for display.
Try to rename your fields to exactly match the json response, even case-wise.

Map generic JSON object to Map interface with GSON

Given the following JSON object
{
"id": 5,
"data: { ... }
}
Is it possible to map this to the following POJO?
class MyEntity {
int id;
Map<String, Object> data;
}
Because I would like to leave the data object open ended. Is this even possible or what is a better approach to go about this? I am doing this on Android.
I don't have any idea about Android application but you can achieve it using Gson library easily.
The JSON that is used in your post is not valid. It might be a typo. Please validate it here on JSONLint - The JSON Validator
Simply use Gson#fromJson(String, Class) method to convert a JSON string into the object of passed class type.
Remember the name of instance member must be exactly same (case-sensitive) as defined in JSON string as well. Read more about JSON Field Naming
Use GsonBuilder#setPrettyPrinting() that configures Gson to output Json that fits in a page for pretty printing.
Sample code:
String json = "{\"id\": 5,\"data\": {}}";
MyEntity myEntity = new Gson().fromJson(json, MyEntity.class);
String prettyJsonString = new GsonBuilder().setPrettyPrinting().create().toJson(myEntity);
System.out.println(prettyJsonString);
output:
{
"id": 5,
"data": {}
}

GSON How to deserialize to a class with this array json string

I am struggling to find a way to serialize / deserialize this JSON output to a Java class? Can anyone provide code sample?
[
{
"topic": "this is my topic"
},
[
{
"name": "John"
},
{
"age": 100
}
]
]
My current attempt uses this Javabean:
public class Test {
private String topic;
private List<Person> listOfPersons;
}
Which I try to deserialize data into using Gson:
gson.fromJson(this.json, Test[].class);
But the deserialization fails, because Gson is looking for a list of persons in the JSON, but it doesn't exist.
It doesn't seem like having an object next to an array, inside an array, is sensical. It would make sense to put things this way:
{
"topic": "this is my topic",
"listOfPersons" : [
{
"name": "John",
"age": 100
},
{
... another person
}
]
}
Then you could just have a Person class:
public class Person {
private String name;
private int age;
}
...and you could deserialize with the code you already have.
The problem here is that your JSON data is syntactically correct, but semantically ambiguous. And by that I mean, it appears to represent a polymorphic array, where each item in the array is of a different type.
In addition, the portion representing a 'person' seems to have been de-normalized horribly, where each attribute of a person is represented as a separate object in an array. Quite weird indeed. Unfortunately its really impossible to tell what types are represented just by looking at the data alone, and there are no hints provided to allow Gson to deserialize the data for you. The best you can do in this case is manually parse the information.
Test test = new Test();
JsonArray rootArray = new JsonParser().parse(jsonString);
test.setTopic(rootArray.get(0).get("topic");
Person person = new Person();
JsonArray personArray = rootArray.get(1);
person.setName(personArray.get(0).get("name"));
person.setAge(personArray.get(1).get("age"));
test.setListOfPersons(Arrays.asList(person));

How to get JSON data from an url in Java?

I have checked out many pages but most of the tutorials and script return an error code with this type of JSON output. So how would I be able to extract the data from this JSON in Java?:
[
{
"user":{"id":"1","username":"user1"},
"item_name":"item1",
"custom_field":"custom1"
},
{
"user":{"id":"2","username":"user2"},
"item_name":"item2",
"custom_field":"custom2"
},
{
"user":{"id":"3","username":"user3"},
"item_name":"item3",
"custom_field":"custom3"
}
]
If you want to use Gson, then first you declare classes for holding each element and sub elements:
public class MyUser {
public String id;
public String username;
}
public class MyElement {
public MyUser user;
public String item_name;
public String custom_field;
}
Then you declare an array of the outermost element (because in your case the JSON object is a JSON array), and assign it:
MyElement[] data = gson.fromJson (myJSONString, MyElement[].class);
Then you simply access the elements of data.
The important thing to remember is that the names and types of the attributes you declare should match the ones in the JSON string. e.g. "id", "item_name" etc.
If your trying to serialize/deserialize json in Java I would recommend using Jackson. http://jackson.codehaus.org/
Once you have Jackson downloaded you can deserialize the json strings to an object which matches the objects in JSON.
Jackson provides annotations that can be attached to your class which make deserialization pretty simple.
You could try JSON Simple
http://code.google.com/p/json-simple/
Example:
JSONParser jsonParser = new JSONParser();
JSONArray jsonArray = (JSONArray) jsonParser.parse(jsonDataString);
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject obj = (JSONObject) jsonArray.get(i);
//Access data with obj.get("item_name")
}
Just be careful to check for nulls/be careful with casting and such.

Categories

Resources