I am fetching a JSON using retrofit 2, which carries object if the key has value else an empty array. ex:
If the key i.e address has values it returns object
{
"student": {
"name": "Some name",
"address": {
"house": "5",
"road": "3"
}
}
}
If the key i.e address does not have any value it returns empty array
{
"student": {
"name": "Some name",
"address": []
}
}
In my POJO class I have made my Address class type to object so that retrofit can parse the JSON.
public class Student {
#SerializedName("name")
#Expose
private String name;
#SerializedName("address")
#Expose
private Object address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Object getAddress() {
return address;
}
public void setAddress(Object address) {
this.address = address;
}
}
Now how can I check that the address type is object or an array?
I have tried with isArray(), but did not find result.
if(obj.getclass().isArray())
Thanks in advance.
You can check through instanceof is object is JosnObject or JsonArray?
if (address instanceof JSONObject) {
JSONObject jsonObject = (JSONObject) address;
}
else if (address instanceof JSONArray) {
JSONArray jsonArray = (JSONArray) address;
}
You can go for json schema validation where you have to definie everything regrading type and format of json and later on validate your json using
Jackson 2.x libraries and fge/json-schema-validator.
Reference link for more details.
http://wilddiary.com/validate-json-against-schema-in-java/
I wonder why your json is not consistent? I mean if there is no value in address it not supposed to be a JSONArray
Instead it supposed to be like -
"address": {
"house": "",
"road": ""
}
It will easy to parse if you are doing like above -
Now you Pojo will be -
public class Address {
#SerializedName("house")
#Expose
private String house;
#SerializedName("road")
#Expose
private String road;
public String getHouse() {
return house;
}
public void setHouse(String house) {
this.house = house;
}
public String getRoad() {
return road;
}
public void setRoad(String road) {
this.road = road;
}
}
And finally you can get the Address using -
#SerializedName("address")
#Expose
private Address address;
in your Student class
PS,
Server side problems must be fixed by Server side.
Thanks to all. I have found my answer with the help of instanceof.
Instead of checking directly the address obj, I have to convert the value into Object type, i.e
Gson gson = new GsonBuilder().serializeNulls().setLenient().create();
String jsonStr = gson.toJson(obj.getAddress());
Object json = new JSONTokener(jsonStr).nextValue();
And then I can check with JSONObject
if (json instanceof JSONObject) {
// Object
}else{
// Array
}
Related
i don't arrive to get the name of the containerStatuses.
I tried this (regarding a precedent post), the error is reported on the get("name") with "The method get(String) is undefined for the type JsonElement".
Thanks for help
JsonObject data = new Gson().fromJson(myjsoncontent, JsonObject.class);
JsonArray items = data .get("items").getAsJsonArray();
for(JsonElement element : items){
JsonObject object = element.getAsJsonObject();
String containerstatusesname = object.get("status").getAsJsonObject().get("containerStatuses").getAsJsonArray().get(0).get("name").getAsString();
}
// My Json Content
{
"kind": "Space",
"apiVersion": "v1",
"metadata": {
"selfLink": "something",
"resourceVersion": "something"
},
"items": [
{
"status": {
"containerStatuses": [
{
"name": "thisismyname"
}
]
}
}
]
}
Why are you using gson emulating JSON.parse? Is using a sledgehammer to crack a nut.
If you want to use gson it's better to create a class that matches your json data as:
public class ApiResponse {
private String kind;
private String apiVersion;
private Metadata metadata;
private List<Item> items;
public List<String> getAllNames() {
List<String> allNames = new ArrayList();
for (Item item: items) {
allNames.add(item.getStatus().get(0).getName());
}
return allNames;
}
public String getFirstName() {
if (items.length == 0 || items.get(0).getStatus().length == 0) {
return "";
}
return items.get(0).getStatus().get(0).getName();
}
class Metadata {
private String selfLink;
private String resourceVersion;
}
class Item {
private List<StatusContainer> status;
List<StatusContainer> getStatus() {
return status;
}
}
class StatusContainer {
private String name;
String getName() {
return name;
}
}
}
And then execute:
ApiResponse response = gson.fromJson(myjsoncontent, ApiResponse.class);
String firstName = response.getFirstName();
And this way the response object will contain all the data of the parsed json. Notice you'll need to add the getters to access this properties if are kept private.
No need to emulate the result of JSON.parse and have JsonObject, JsonArray...
You have to change
.get(0).get("name")
to
.get(0).getAsJsonObject().get("name")
JsonArray returns JsonElements when you iterate over it
Get the Array Element as Object cause its structured as Object
.getAsJsonArray().get(0).getAsJsonObject().get("name").getAsString();
I have a POJO class which I use to serialise and deserialise between JSON messages and the POJO object for use within my Java code. In the POJO class, there is a field called requestMessage which contains a string of JSON. When the payload is sent between the services, this field is literally just a string.
For example, this is how the payload would look:
{
"name": "John Smith",
"status": true,
"requestMessage": "{\"id\": \"some-id\", \"timestamp\": \"2019-11-30\"}"
}
To cater for this field, I created an attribute requestMessage in my POJO class and made the type as JSONObject, which is a type from the org.json package. I was thinking this kind of make sense because in case I need to use it in my code, I could easily access the information as a JSONObject. I've something like this in my POJO class:
public class Message {
private String name;
private boolean status;
private JSONObject requestMessage;
#JsonCreator
public Message(
#JsonProperty("name") String name,
#JsonProperty("status") boolean status,
#JsonProperty("requestMessage") JSONObject requestMessage
) {
this.name = name;
this.status = status;
this.requestMessage = requestMessage;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
public JSONObject getRequestMessage() {
return requestMessage;
}
public void setRequestMessage(JSONObject requestMessage) {
this.requestMessage = requestMessage;
}
#Override
public String toString() {
return "Message{" +
"name='" + name + '\'' +
", status=" + status +
", requestMessage=" + requestMessage +
'}';
}
}
However, it seems Jackson wasn't able to convert it as a string properly when sending out the message. The requestMessage field is always converted into a string as an empty {} object in the payload.
How can I get Jackson to convert and map the requestMessage attribute in the Message POJO class correctly as a string when it's sending out the payload?
You need to tell Jackson to serialize the JSONObject field using its toString method, like this:
public static class Message {
private String name;
private boolean status;
#JsonSerialize(using=ToStringSerializer.class)
private JSONObject requestMessage;
// ...
}
Deserialization was working because Jackson defaults to use a constructor that takes a String parameter for deserialization. JSONObject has one, so it got deserialized. I would have expected, for consistency, that toString was used on serialization, but it doesn't. I imagine there must be a good design reason behind it.
That being said, I don't understand why you try to use JSONObject from json.org if you are already using Jackson. I would stick to JSONObject's equivalent in Jackson, which I guess is JsonNode, as suggested by Coderino Javarino.
I have a response that returns a json object in following format:
{
"playerId": "001",
"name": "michel",
"age": 21,
"nation": "USA",
"ratings": [
{
"type": "speed",
"score": "0121"
},
{
"type": "accuracy",
"score": "85"
}
],
"teaminfo": {
"teamName": "HON",
"isValid": "true"
}
}
and I have a Java Class as :
public class MyRider {
public String playerId;
public String name;
public int age;
public String speed;
public String accuracy;
public String teamName;
public String isValid;
//getter, setter...
}
I want to map the JSON object into Java object using GSON.
I tried using JsonDeserializationContext deserialize, and it returned null for the nested values in JSON.
Without custom deserializer
If you cannot change the JSON to return exactly what you want, I suggest you create classes to match it:
MyRider:
public class MyRider {
private String playerId;
private String name;
private int age;
private String nation;
private List<Rating> ratings;
private TeamInfo teaminfo;
// getters, setters, toString override
}
Rating:
public class Rating {
private String type;
private String score;
// getters, setters, toString override
}
TeamInfo:
private static class TeamInfo {
private String teamName;
private String isValid;
// getters, setters, toString override
}
Then simply deserialize as normal:
MyRider rider = gson.fromJson(json, MyRider.class);
If you need exactly the fields you've specified in MyRider in your question, consider a transformer class to map the full class above to your needs.
With custom deserializer
It's also possible to do this with a custom deserializer, but slightly pointless as GSON provides the normal mapping for you which you can then adapt.
Here is an example with a deserializer:
public class MyRiderDeserializer implements JsonDeserializer<MyRider> {
#Override
public MyRider deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context)
throws JsonParseException {
MyRider rider = new MyRider();
if(json.isJsonObject()) {
JsonObject riderObj = json.getAsJsonObject();
rider.setPlayerId(riderObj.get("playerId").getAsString());
rider.setName(riderObj.get("name").getAsString());
rider.setAge(riderObj.get("age").getAsInt());
JsonArray ratingsArray = riderObj.get("ratings").getAsJsonArray();
for(JsonElement ratingElem : ratingsArray) {
JsonObject ratingObj = ratingElem.getAsJsonObject();
String type = ratingObj.get("type").getAsString();
switch(type) {
case "speed":
rider.setSpeed(ratingObj.get("score").getAsString());
break;
case "accuracy":
rider.setAccuracy(ratingObj.get("score").getAsString());
break;
default:
break;
}
}
JsonObject teamInfo = riderObj.get("teaminfo").getAsJsonObject();
rider.setTeamName(teamInfo.get("teamName").getAsString());
rider.setIsValid(teamInfo.get("isValid").getAsString());
}
return rider;
}
}
Note this does not include any checks to validate whether the properties are actually there and is the simplest possible custom deserializer I could think of. To use it, you must register the type adapter at Gson creation time:
Gson gson = new GsonBuilder()
.registerTypeAdapter(MyRider.class, new MyRiderDeserializer())
.create();
MyRider myRider = gson.fromJson(reader, MyRider.class);
I have the following json from the Server. It is a json array with different objects. I want to identify the user objects based on the key "type" and add them to a user hashmap and fetch user to show information in my view containing the "payments" object. I am using gson and retrofit. TIA
"included":[
{
"id":"1",
"type":"payments",
"attributes":{
"amount_cents":100,
"amount_currency":"INR",
"description":"Test description!!",
"created_at":"2016-03-01T11:30:53Z",
"status":"paid",
"paid_at":null,
"charged_at":null,
"formatted_amount":"Rs1.00"
},
"relationships":{
"sender":{
"data":{
"id":"2",
"type":"users"
}
},
"receiver":{
"data":{
"id":"1",
"type":"users"
}
}
}
},
{
"id":"2",
"type":"users",
"attributes":{
"first_name":"Rob",
"last_name":"Thomas"
}
},
{
"id":"1",
"type":"users",
"attributes":{
"first_name":"Matt",
"last_name":"Thomas"
}
}]
My classes are
public class ActivityFeedItem implements IFeedItem {
#SerializedName("id")
String id;
#SerializedName("type")
String type;
#SerializedName("attributes")
Attributes attributes;
protected class Attributes {
double amount_cents;
String amount_currency;
String description;
String created_at;
String status;
String paid_at;
String charged_at;
String formatted_amount;
Relationships relationships;
public double getAmount_cents() {
return amount_cents;
}
public String getAmount_currency() {
return amount_currency;
}
public String getDescription() {
return description;
}
public String getCreated_at() {
return created_at;
}
public String getStatus() {
return status;
}
public String getPaid_at() {
return paid_at;
}
public String getCharged_at() {
return charged_at;
}
public String getFormatted_amount() {
return formatted_amount;
}
public Relationships getRelationships() {
return relationships;
}
}
}
and
public class UserFeedItem implements IFeedItem {
#SerializedName("id")
String id;
#SerializedName("type")
String type;
#SerializedName("attributes")
Attributes attributes;
public class Attributes {
#SerializedName("first_name")
String first_name;
#SerializedName("last_name")
String last_name;
}
}
This is pretty easy if you just put your JSON response String into a JSONArray. Then you can just access the type field and test if it's users. Like this:
JSONArray jsonArray = new JSONArray(yourServerResponseString);
for(int i=0; i<jsonArray.length(); i++) {
JSONObject object = (JSONObject) jsonArray.get(i);
String type = object.getString("type");
if(type.equals("users")) {
//add to your users HashMap
}
}
First of all create an array of objects from you JSON using GSON as below
Gson gson= new Gson();
String jsonString= yourJsonObject.getString("included");
ActivityFeedItem[] activityFeedArray=gson.fromJson(jsonString,ActivityFeedItem[].class);
Now your activityFeedArray contains all the feedItems you get in JSON. Then you can iterate through it as you would in any array and add to hashmap when type is user as below-
for(ActivityFeedItem item:activityFeedArray) {
if(item.type.equals("users")) {
//add to your users HashMap
}
}
I have a json object
data = {
'ad': {
"date":"2013-06-05",
"catagory":"6",
"subcatagory":"5",
"text":"John john",
"ssn":"1306743999",
"email":"jonbrynjar#365.is",
"phone":"8612001"
},
'cc-info': {
"amount": "70",
"cardNumber": "4222222222222",
"expiryDate": "1215",
"currency": "ISK"
},
'dates': [
{ 'date': '2013-06-18', 'media': 1 },
{ 'date': '2013-06-19', 'media': 3 }
]
}
Then I have a subflow that takes the "cc-info" part of that json object and uses that data to call a third party service.
To extract the "cc-info" part of the json object I use #JsonAutoDetect class
#JsonAutoDetect
public class Handpoint {
private String amount;
private String cardNumber;
private String expiryDate;
private String currency;
public String getAmount() { return this.amount; }
public void setAmount(String amount) { this.amount = amount; }
public String getCardNumber() { return this.cardNumber; }
public void setCardNumber(String cardNumber) { this.cardNumber = cardNumber; }
public String getExpiryDate() { return this.expiryDate; }
public void setExpiryDate(String expireDate) { this.expiryDate = expireDate; }
public String getCurrency() { return this.currency; }
public void setCurrency(String currency) { this.currency = currency; }
}
When I send in the whole json object I get an error.
The question is: Do I have to put every variable in the json object into my #JsonAutoDetect class ?
Or what would be best practice for this.
I have verified that my code works when I just send in the "cc-info" part of the json objcet.
You don't need that #JsonAutoDetect, it doesn't do anything different from defaults without arguments.
But if your question is whether you can just ignore unknown properties, answer is yes. Here are couple of ways.
For example:
mapper.disable(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES);
would do the trick.
There is an easier way to convert your JSON element to a series of objects. Have you tried the Google GSon library? There is a sample:
import com.google.gson.Gson;
Gson gson = new Gson();
Handpoint testing = gson.fromJson(data, Handpoint.class);
System.out.println("Amount: " + testing.getAmount());
On the other hand, if you want to deserialize the dates, that contain arrays, you'd better take a look here:
Gson Array deserialization