I have the json:
{
"albums": [
{
"default": {
"privacy": "public"
......
}
}
},
{
"second_album": {
"privacy": "public"
......
}
},
{
"third_album": {
"privacy": "public"
......
}
}
}
]
}
I want to make Java Objects for this json.
public class AlbumsResponse {
private List<Album> albums = new ArrayList<>();
public List<Album> getAlbums() {
return albums;
}
public void setAlbums(List<Album> albums) {
this.albums = albums;
}
}
and
public class Album {
private Title title;
public Title getTitle() {
return title;
}
public void setTitle(Title title) {
this.title = title;
}
}
But as you can see Album has no any "Title" field in json but has something like this
"second_album": {
"privacy": "public"
......
}
How to work with this? How to convert name of json-object as unit in json-array to field "title" in java-object?
Based on your question, I am not entirely sure how you want to convert the object shown into a Title, but I believe that you can achieve what you are looking for with a custom deserializer.
For example, the following deserializer takes the first key of the JSON object, wraps this in a Title, and then returns an Album with that Title:
public static class AlbumDeserializer implements JsonDeserializer<Album> {
#Override
public Album deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
// Get the key of the first entry of the JSON object
JsonObject jsonObject = json.getAsJsonObject();
Map.Entry<String, JsonElement> firstEntry = jsonObject.entrySet().iterator().next();
String firstEntryKey = firstEntry.getKey();
// Create a Title instance using this key as the title
Title title = new Title();
title.setTitle(firstEntryKey);
// Create an Album instance using this Title
Album album = new Album();
album.setTitle(title);
return album;
}
}
You can then register this custom deserializer with your Gson instance, and convert your JSON with it:
Gson gson = new GsonBuilder()
.registerTypeAdapter(Album.class, new AlbumDeserializer())
.create();
AlbumsResponse response = gson.fromJson(json, AlbumsResponse.class);
System.out.println(response);
Assuming that your classes implement toString in a basic way, running this with your example prints the following:
AlbumsResponse{albums=[Album{title=Title{title='default'}}, Album{title=Title{title='second_album'}}, Album{title=Title{title='third_album'}}]}
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();
First, I know there are many questions on this topic but I couldn't find one that solves my problem.
I need to deserialize with Gson a json that is in this form:
{
"name": "abc",
"entries":
[
[
"first_entry_name",
{"is_ok": true, "type": "first_entry_type"}
],
[
"second_entry_name",
{"is_ok": false, "type": "second_entry_type"}
]
]
}
I've implemented the classes:
class Entries
{
String name;
ArrayList<Entry> entries;
}
class Entry
{
String name;
Details details;
}
class Details
{
Boolean is_ok;
String type;
}
I'm deserializing with:
Entries ent = new Gson().fromJson(json, Entries.class);
And I'm getting this error:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY
I understand why I'm getting this error but I can't think of a way to deserialize this json.
How should this json be deserialized?
Code is fine but your JSON file should be like below
{
"name": "abc",
"entries":
[
{
"first_entry_name":{"is_ok": true, "type": "first_entry_type"}
},
{
"second_entry_name":{"is_ok": false, "type": "second_entry_type"}
}
]
}
In the json posted in original question, there was list inside a list (entries) but ideally it should be json element inside a list.
Here is the screenshot of code with output
Hope this helps
i am not really sure if that help , i come from c# world . but i think that will be a generic problem , so try to cast your instance (ent) from object to array or list of that Type ..
i mean like this
this c# syntax but i think there are mostly the same with java
<List>Entries ent = (<List>Entries)new Gson().fromJson(json, Entries.class);
it can be also here Array but List is more dynamic .. hopefully works
You may do something like below.
try adding another wrapper class as I have added sample here as EntryTwo.
class Entries
{
String name;
ArrayList<Entry> entries;
}
class Entry
{
ArrayList<EntryTwo> entryTwo;
}
class EntryTwo
{
String name;
Details details;
}
class Details
{
Boolean is_ok;
String type;
}
Hope this works...
You need to implement custom deserialiser for List<Entry> type:
class EntriesJsonDeserializer implements JsonDeserializer<List<Entry>> {
#Override
public List<Entry> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonArray array = json.getAsJsonArray();
List<Entry> entries = new ArrayList<>(array.size());
for (JsonElement item : array) {
JsonArray itemArray = item.getAsJsonArray();
entries.add(parseEntry(context, itemArray));
}
return entries;
}
private Entry parseEntry(JsonDeserializationContext context, JsonArray array) {
Entry entry = new Entry();
entry.setName(array.get(0).getAsString());
entry.setDetails(context.deserialize(array.get(1), Details.class));
return entry;
}
}
You can register it using JsonAdapter annotation:
class Entries {
String name;
#JsonAdapter(EntriesJsonDeserializer.class)
List<Entry> entries;
}
You can try following code:
public class Entries {
private String name;
private List<List<String>> entries;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setEntries(List<List<String>> entries) {
this.entries = entries;
}
public List<List<String>> getEntries() {
return entries;
}
}
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 need to parse a JSON file that contains long list of customers. In the JSON file each customer may have one id as a string:
{
"cust_id": "87655",
...
},
or a few ids as an array:
{
"cust_id": [
"12345",
"45678"
],
...
},
The Customer class is as below:
public class Customer {
#SerializedName("cust_id")
#Expose
private String custId;
public String getCustId() {
return custId;
}
public void setCustId(String custId) {
this.custId = custId;
}
}
I parse the JSON using Gson:
Gson gson = new Gson()
Customers customers1 = gson.fromJson(json, Customers.class)
and it fails with com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_ARRAY when it attempts to parse the array.
The reason of failure is clear.
My question: what is the best way to handle both cases (when id is a string and when it is an array of strings), given I can not change the json file structure?
If you want to handle both scenarios you can use a custom deserializer. Of course, you have to change the "cust_id" variable to be a list or an array.
Main:
String json1 = "{\"cust_id\": \"87655\"}";
String json2 = "{\"cust_id\": [\"12345\", \"45678\"]}";
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Customer.class, new CustomerDeserializer());
Gson gson = gsonBuilder.create();
Customer customer1 = gson.fromJson(json1, Customer.class);
System.out.println(customer1);
Customer customer2 = gson.fromJson(json2, Customer.class);
System.out.println(customer2);
Customer
public class Customer {
#SerializedName("cust_id")
private List<String> custId;
public List<String> getCustId() {
return custId;
}
public void setCustId(List<String> custId) {
this.custId = custId;
}
}
CustomerDeserializer
public class CustomerDeserializer implements JsonDeserializer<Customer> {
#Override
public Customer deserialize(JsonElement jsonElement, Type typeOf, JsonDeserializationContext context) throws JsonParseException {
Customer result = null;
Gson gson = new Gson();
try {
// try to deserialize by assuming JSON has a list
result = gson.fromJson(jsonElement, Customer.class);
} catch (JsonSyntaxException jse) {
// error here means JSON has a single string instead of a list
try {
// get the single ID
String custId = jsonElement.getAsJsonObject().get("cust_id").getAsString();
result = new Customer();
result.setCustId(Arrays.asList(new String[] {custId}));
} catch (Exception e) {
// more error handling here
e.printStackTrace();
}
}
return result;
}
}
Output
Customer [custId=[87655]]
Customer [custId=[12345, 45678]]
Try method overriding:
public class Customer {
#SerializedName("cust_id")
#Expose
private String custId;
public void setCustId(String custId) {
this.custId = {custId};
}
public String[] getCustId() {
return custId;
}
#override
public void setCustId(String[] custId) {
this.custId = custId;
}
}
Now In the code all values of CUSTID will be arrays instead of strings
You can just simply specify all values as array, even if is just one value.
{
"cust_id": ["87655"],
...
},
UPDATE: If you cannot change the json, you can bind every field in Customer class except custId and set it manually.
public class Customer {
private String[] custId;
public String getCustId() {
return custId;
}
public void setCustId(String custId) {
custId = new String[] {custId};
}
public void setCustId(String[] custId) {
this.custId = custId;
}
}
And then parse manually:
Gson gson = new Gson();
Customers customers = gson.fromJson(json, Customers.class);
Object custId = new JSONObject(json).get("cust_id");
if (custId instanceof String) {
customers.setCustId((String) custId);
else if (custId instanceof JSONArray) {
customers.setCustId(convertToStringArray(new JSONArray(custId)));
}
Refer this.
Now the problem is that you will have to write your own code on the returned map to get the desired result.
I am calling a webservice which gives me a json like this
{
"discussions": [{
"id": 54,
"name": "Test Discusssion",
"discussion": 41,
"created": 1472816138,
"modified": 1472816138,
"subject": "Test Discusssion",
"message": "<p>Welcome all to test discussion<\/p>",
}],
"warnings": []
}
But in android I am parsing it as
ArrayList<MoodleDiscussion> mDiscussions = gson.fromJson(reader,
new TypeToken<List<MoodleDiscussion>>() {
}.getType());
And the error I am getting is
java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT
I want to convert the received json into an array how should I ?
Here is the MoodleDiscussion class
public class MoodleDiscussion extends SugarRecord < MoodleDiscussion > {#
SerializedName("id") int discussionid;#
SerializedName("name") String name;#
SerializedName("subject") String subject;
public int getDiscussionid() {
return discussionid;
}
public String getName() {
return name;
}
public int getUserid() {
return userid;
}
public String getSubject() {
return subject;
}
}
The list you're trying to parse is contained within a nested json data structure that also needs to be represented in java classes if Gson is to parse it correctly.
You'll need a container class that looks something like this:
public class MoodleDiscussionResponse {
private List<MoodleDiscussion> discussions;
private List<Object> warnings;
public List<MoodleDiscussion> getDiscussions() {
return discussions;
}
public List<Object> getWarnings() {
return warnings;
}
}
Then you should be able to read it like so:
MoodleDiscussionResponse response = gson.fromJson(reader, MoodleDiscussionResponse.class);
List<MoodleDiscussion> mDiscussions = response.getDiscussions();
Define class the same:
class Discussion implements Serializable
{
#SerializedName("id")
int id;
#SerializedName("name")
String name;
#SerializedName("discussion")
String discussion;
bla bla
}
and:
class ResultResponse implements Serializable
{
#SerializedName("discussions")
List<Discussion> mDiscussion = new ArrayList<>();
}
I think that is enough to parser using gson.
You can not using below code in this case :)
ArrayList<MoodleDiscussion> mDiscussions = gson.fromJson(reader,
new TypeToken<List<MoodleDiscussion>>() {
}.getType());
you can parse in two ways first get array list of json object and loop it
JSONArray discussionsList = obj1.getJSONArray("discussions");
for (int i = 0; i < discussionsList.length(); i++) {
JSONObject jsonObject = orderList.getJSONObject(i);
Type type = new TypeToken<MoodleDiscussion>() {
}.getType();
CompletedOrderData completedOrderData = new Gson().fromJson(jsonObject.toString(), type);
disscussionDataArrayList.add(completedOrderData);
and second way is parse jsonArray object as below
Type type = new TypeToken<ArrayList<MoodleDiscussion>>() {
}.getType();
disscussionDataArrayList=new Gson().fromJson(orderList,type);