I get a JsonObject from another server like this:
{"data": {
"key": "Cooking.Oven.Program.HeatingMode.HotAir",
"options": [
{
"key": "Cooking.Oven.Option.SetpointTemperature",
"value": 230,
"unit": "°C"
},
{
"key": "BSH.Common.Option.Duration",
"value": 1200,
"unit": "seconds"
}
]
}
}
My problem is now. How can I separate this JsonObject in smaller parts.
If this would be a normal object with one key value pair, I would transfere it to a map. But here the line
Map<String, String> map = toMap(this.json);
private Map<String, String> toMap(JsonObject json) {
return new Gson().fromJson(json, new TypeToken<HashMap<String, String>>() {
}.getType());
}
throws an error
Exception occurred while informing handler: java.lang.IllegalStateException: Expected STRING but was BEGIN_ARRAYcom.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected STRING but was BEGIN_ARRAY
What is the easiest solution to get all the entries to a map?
Do you have any hints or cues for me?
Try this:
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
//... get JSON string
String jsonResponse = yourJsonResponseString;
// parse JSON
JSONObject jsonObject = new JSONObject (jsonResponse);
JSONObject data = jsonObject.getJSONObject("data");
String key = data.getString("key");
JSONArray options = data.getJSONArray("options");
for(i=0; i<options.length(); i++){
JSONObject optionsObject = options.getJSONObject(i);
String key = optionsObject.getString("key");
int value = optionsObject.getInt("value");
String unit = optionsObject.getString("unit");
// ... put these values into some object or store it somehow..
}
So, first you have to get values from JSON into String, int etc. Then you can add those values into your custom data structure.
I hope I could help you.
Related
My Rest API is returning the following response, in which only the inner list is required, all data shall be discarded:
{
"meta": [],
"links": [],
"body": [
{
"meta": [],
"links": [],
"body": {
"field1": "value1",
"fieldn": "valuen"
} // <-----
},
{
"meta": [],
"links": [],
"body": {
"field1": "value1",
"fieldn": "valuen"
} // <-----
}
]
}
Is there any way in Gson or another other java library to fetch an array of the body or a straightforward way of doing that? Or maybe even using standard of java 8?
Or, should I use a standard iterator as follows:
//Old way to do this
JSONArray BodyArr = (JSONArray) jsonObject.get("Body");
Iterator<JSONObject> itBody = BodyArr.iterator();
int teller = 0;
while (itBody.hasNext()) {
JSONObject bodyObj = itBody.next();
JSONObject body = (JSONObject) bodyObj.get("Body");
}
Also in mysql we have way to do that using notation ($.body.body[] etc.). Is there any notational way to fetch the object
I think we have a nicely written article on this.
Json object iteration
If you have a class that represents an object in the array, then you can deserialize the JSONArray to an array of that class using public <T> T fromJson(JsonElement json, java.lang.Class<T> classOfT) throws JsonSyntaxException on the Gson class:
class BodyItem {
public String[] meta;
public String[] links;
public String field1;
public String fieldn;
}
public BodyItem[] getBodyItems(final Gson gson, final JsonObject jsonObject) {
final JsonElement body = jsonObject.get("body");
return gson.fromJson(body, BodyItem[].class);
}
public static void main(final String[] args) {
final String response = "<your REST API JSON response>";
final Gson gson = new Gson();
final JsonObject jsonObject = gson.fromJson(response, JsonObject.class);
final BodyItem[] bodyItems = getBodyItems(gson, jsonObject);
}
If you want a more notational way of accessing fields in Gson objects, you can use JsonObject's convenience accessors:
JsonArray getAsJsonArray(java.lang.String memberName)
JsonObject getAsJsonObject(java.lang.String memberName)
JsonPrimitive getAsJsonPrimitive(java.lang.String memberName)
And then with a JsonArray, you can iterate with for (final JsonElement element : jsonArray) or .forEach, and you can get JsonElements with the JsonElement get(int i) accessor.
So, say you had your original JsonObject response and wanted to get the value of body.field1 in the second element of the body list, you might do:
String value = jsonObject
.getAsJsonArray("body")
.get(1)
.getAsJsonObject()
.getAsJsonObject("body")
.getAsJsonObject("field1");
I've got a JSON structure like the following:
{
"identifier": 1045608,
"scientificName": "Apis mellifera Linnaeus 1758",
"exemplar": false,
"richness_score": 400.0,
"dataObjects": [
{
"identifier": "d72801627bf4adf1a38d9c5f10cc767f",
"dataObjectVersionID": 30073527,
"dataType": "http://purl.org/dc/dcmitype/StillImage",
"dataSubtype": "",
"vettedStatus": "Trusted",
"dataRatings": {
"1": 0,
"2": 0,
"3": 4,
"4": 0,
"5": 6
},
"dataRating": 4.2,
"mimeType": "image/jpeg",
"created": "2009-07-12T15:13:19Z",
"title": "Honey Bee on Mountain Mint",
"language": "en",
"license": "http://creativecommons.org/licenses/by/2.0/",
"rightsHolder": "John Baker",
"source": "https://www.flickr.com/photos/38875278#N08/3730360050/",
"mediaURL": "https://farm3.staticflickr.com/2619/3730360050_c771a4c2cf_o.jpg",
"agents": [
{
"full_name": "John Baker",
"homepage": "http://www.flickr.com/photos/38875278#N08",
"role": "photographer"
},
{
"full_name": "Flickr: EOL Images",
"homepage": "http://www.flickr.com/groups/encyclopedia_of_life",
"role": "provider"
}
],
}
]
}
I have defined a top-level class to deserialize into as:
class EOLDataObjectsResponse {
private int identifier;
private String scientificName;
private Boolean exemplar;
#SerializedName("richness_score") private float richnessScore;
private List<EOLDataObjectsTaxonConcept> taxonConcepts;
private List<LinkedTreeMap<String, String>> dataObjects;
}
Everything was parsing properly with Gson until I added the dataObjects property. What I am getting on testing is:
Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 2242 path $.dataObjects[0].
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:224)
at com.google.gson.Gson.fromJson(Gson.java:887)
at com.google.gson.Gson.fromJson(Gson.java:825)
at emt.eol.EOLDataObjects.query(EOLDataObjects.java:102)
at emt.eol.EOLDataObjects.query(EOLDataObjects.java:51)
at emt.eol.EOLDataObjects.main(EOLDataObjects.java:136)
What I would like to do is parse just that property into a list of nested maps of string-string pairs since I have no guarantees re what is coming back in that list yet want to make it available in a nested map format if someone needs to access it. I was hoping that the Gson LinkedTreeMap class would do the trick, but apparently not the way I'm using it.
Can anyone suggest what might be causing problems or possibly a better approach? Thanks!
dataObjects is not a key as other strings. It is a json object. You have to parse it as JSON Object separately.
public static Map parse(final String json,final Map map){
try {
//Instance of JsonFactory for Object Mapper istance
final JsonFactory factory = new JsonFactory();
final ObjectMapper mapper = new ObjectMapper(factory);
//create JsonNode from json String
final JsonNode rootNode = mapper.readTree(json);
// iterate till it fetch all parameter and value from json string
final Iterator<Map.Entry<String, JsonNode>> fieldsIterator = rootNode.fields();
while (fieldsIterator.hasNext()) {
final Map.Entry<String, JsonNode> field = fieldsIterator.next();
//if normal json, put value to map
map.put(field.getKey(), String.valueOf(field.getValue()));
//if json oject again recurse parse method.
if ((String.valueOf(field.getValue()).startsWith("{") && String.valueOf(field.getValue()).endsWith("}"))) {
parse(String.valueOf(field.getValue()),map);
}
//if json array it invoke parseJsonArray
if (String.valueOf(field.getValue()).startsWith("[{") && String.valueOf(field.getValue()).endsWith("}]")) {
parseJsonArray(String.valueOf(field.getValue()),map);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
public static void parseJsonArray(String jsonArray,Map<String, String> map) {
try {
JSONArray jsonArray1 = new JSONArray(jsonArray);
for (int i = 0; i < jsonArray1.length(); i++) {
JSONObject json = jsonArray1.getJSONObject(i);
Iterator<String> keys = json.keys();
while (keys.hasNext()) {
String key = keys.next();
map.put(key, String.valueOf(json.get(key)));
System.out.println("Key :" + key + " Value :" + String.valueOf(json.get(key)));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
I need to pull out value of RecordOne from following JSON.
{
"errors": [],
"data": {
"paging": {
"RecordOne": 8,
"RecordTwo": 9,
"recordThree": 2,
"totalNumberOfRecords": 86052
},
"products": [
{
"testabstract": "test data",
"authors": "Frank Jr.",
"invertedauthors": "Frank VJr.",
"formatCode": "KND"
}
]
}
}
I'm using Java as language and JSON object to achieve the same, following is what I'm using:
protected String getTokenValueUnderHeirarchy(String responseString){
JSONObject json = new JSONObject(responseString);
String val= json.getJSONObject("data").getJSONObject("paging").getString("RecordOne");
System.out.println("val::"+val);
return val;
}
I'm getting value of val = 1, it should be 8
If I try to seek value for key totalNumberOfRecords with same code it returns correct value which is 86052
I know it's something silly but I can't catch it.
When I ran your code with the JSON example, I ended up with a "JSONException: JsonObject["RecordOne"] is not a string"..... which it isn't. Wrapping the 8 with double quotes: "8" returned the value that you expected. You can access this value with other get methods: getInt if you would like.
This test case parses both a String and an int. I pulled this from your example. Does it run for you?
package org.nadnavillus.test;
import org.json.JSONObject;
import org.junit.Test;
public class TestCase {
protected String getTokenValueUnderHeirarchy(String responseString) throws Exception {
JSONObject json = new JSONObject(responseString);
String val= json.getJSONObject("data").getJSONObject("paging").getString("RecordOne");
System.out.println("val::"+val);
return val;
}
protected String getTokenValueUnderHeirarchyInt(String responseString) throws Exception {
JSONObject json = new JSONObject(responseString);
int val= json.getJSONObject("data").getJSONObject("paging").getInt("RecordTwo");
System.out.println("val::"+val);
return String.valueOf(val);
}
#Test
public void testJson() throws Exception {
String input = "{\"errors\": [], \"data\": {\"paging\": {\"RecordOne\": \"8\", \"RecordTwo\": 9, \"recordThree\": 2, \"totalNumberOfRecords\": 86052}}}";
String test = this.getTokenValueUnderHeirarchy(input);
System.out.println(test);
test = this.getTokenValueUnderHeirarchyInt(input);
System.out.println(test);
}
}
I am new to stackoverflow.
I am creating an Java application which it will get data from a web server. The data is in json format. Example"
[
{
"item_name": "Adame",
"item_type": "Special",
"item": "Chestplate",
"item_min_lvl": "50",
"enchantment": {
"health": "0.3",
"dam": "24%",
"life": "0.1",
"xp": "24%",
"loot": "22%"
},
"def": "73"
},
{
"item_name": "Sticks'",
"item_type": "Unique",
"item": "Stick",
"item_min_lvl": "4",
"enchantment": {
"health": "0.6",
"mana": "1",
"dam": "12%",
"life": "0.3",
"xp": "17%",
"loot": "17%"
},
"min_dam": "39",
"max_dam": "34"
}
]
I know how to deserialize json using Gson. As you can see, it's started with [. I never deserialize this case before. Also, the json data is not the same(e.g. enchantment). I also searched in Google but I can't find any similar case. Can anyone help me with the code?
Try with this code. You will get the answer of your question. It's an List with 2 items.
StringBuilder builder = new StringBuilder();
BufferedReader reader = new BufferedReader(new FileReader(new File("resources/json1.txt")));
String line = null;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
reader.close();
Gson gson = new Gson();
Type listType = new TypeToken<ArrayList<MyJSON>>() {
}.getType();
List<MyJSON> list = gson.fromJson(builder.toString(), listType);
// you can try this form as well
// MyJSON[] list = gson.fromJson(builder.toString(), MyJSON[].class);
for (MyJSON json : list) {
System.out.println(json.toString());
}
...
class MyJSON {
String item_name;
String item_type;
String item;
String item_min_lvl;
Enchantment enchantment;
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("\nitem_name:").append(item_name);
builder.append("\nitem_type:").append(item_type);
builder.append("\nitem:").append(item);
builder.append("\nitem_min_lvl:").append(item_min_lvl);
builder.append("\n\nEnchantment Details:");
builder.append("\nhealth:").append(enchantment.health);
builder.append("\ndam:").append(enchantment.dam);
builder.append("\nlife:").append(enchantment.life);
builder.append("\nxp:").append(enchantment.xp);
builder.append("\nloot:").append(enchantment.loot);
return builder.toString();
}
}
class Enchantment {
String health;
String dam;
String life;
String xp;
String loot;
}
output:
item_name:Adame
item_type:Special
item:Chestplate
item_min_lvl:50
Enchantment Details:
health:0.3
dam:24%
life:0.1
xp:24%
loot:22%
item_name:Sticks'
item_type:Unique
item:Stick
item_min_lvl:4
Enchantment Details:
health:0.6
dam:12%
life:0.3
xp:17%
loot:17%
EDIT
The structure of each entry is not same hence you can't use POJO for this type of JSON.
Simply use ArrayList<Map<String, Object>> and access the value based on key from the map.
Gson gson = new Gson();
Type listType = new TypeToken<ArrayList<Map<String, Object>>>() {
}.getType();
ArrayList<Map<String, Object>> list = gson.fromJson(builder.toString(), listType);
for (Map<String, Object> json : list) {
for (String key : json.keySet()) {
System.out.println(key + ":" + json.get(key));
}
System.out.println("===========");
}
output:
item_name:Adame
item_type:Special
item:Chestplate
item_min_lvl:50
enchantment:{health=0.3, dam=24%, life=0.1, xp=24%, loot=22%}
def:73
===========
item_name:Sticks'
item_type:Unique
item:Stick
item_min_lvl:4
enchantment:{health=0.6, mana=1, dam=12%, life=0.3, xp=17%, loot=17%}
min_dam:39
max_dam:34
===========
This is actually valid in Java and with GSON:
YourObject[] locs = gson.fromJson (someJsonString, YourObject[].class);
It'll parse and return an array of YourObject. Just create Java Classes that represent your JSON objects, and replace the placeholders as necessary.
EDIT:
As Braj said before, you can create a fully formed POJO, including the other, (non-symmetrical) attributes (I'm borrowing the code from from Braj's answer here):
//... snip ...
class MyJSON
{
String item_name;
String item_type;
String item;
String item_min_lvl;
Enchantment enchantment;
// Heres the other attributes
String min_dam;
String max_dam;
}
//... snip ...
GSON will parse it and set the values to null if they aren't provided in the original JSON.
However, from the other question, it seems that the JSON (Java - JSON Parser Error) for enchantment is provided inconsistently, so this will cause issues. I would recommend sending JSON for enchantment as an array for consistency, then you could structure your POJO as:
//... snip ...
class MyJSON
{
String item_name;
String item_type;
String item;
String item_min_lvl;
Enchantment[] enchantment;
// Heres the other attributes
String min_dam;
String max_dam;
}
//... snip ...
I'm trying to parse the JSON located at http://api.pathofexile.com/ladders/Default?offset=0&limit=1.
{
"total": 15000,
"entries": [
{
"online": false,
"rank": 1,
"character": {
"name": "Byrr",
"level": 85,
"class": "Shadow",
"experience": 1397076236
},
"account": {
"name": "Canoobians"
}
}
]
}
I've been following the androidhive tutorial while attempting to modify it to retrive the "online" and "rank" elements. (Eventually I want all of the elements with large numbers of entries, but I'm starting with just those two to try to understand things.
public class AndroidJSONParsingActivity extends ListActivity {
// url to make request
private static String url = "http://api.pathofexile.com/ladders/Default?offset=0&limit=2";
// JSON node names
private static final String TAG_ENTRIES = "entries";
private static final String TAG_ONLINE = "online";
private static final String TAG_RANK = "rank";
// entries JSONArray
JSONArray entries = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Hashmap for ListView
ArrayList<HashMap<String, String>> entriesList = new ArrayList<HashMap<String, String>>();
// create JSON Parser instance
JSONParser jParser = new JSONParser();
// getting JSON string from url
JSONObject json = jParser.getJSONFromUrl(url);
try {
// Getting Array of entries
entries = json.getJSONArray(TAG_ENTRIES);
// looping through entries
for (int i = 0; i < entries.length(); i++) {
JSONObject ent = entries.getJSONObject(i);
// storing each JSON item in a variable
String online = ent.getString(TAG_ONLINE);
String rank = ent.getString(TAG_RANK);
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
// adding each child node to HashMap key => value
map.put(TAG_ONLINE, online);
map.put(TAG_RANK, rank);
// adding HashList to ArrayList
entriesList.add(map);
}
} catch (JSONException e) {
e.printStackTrace();
}
// Updating parsed JSON data into ListView
ListAdapter adapter = new SimpleAdapter(this, entriesList, R.layout.list_item, new String[] { TAG_ONLINE, TAG_RANK }, new int[] { R.id.online, R.id.rank });
setListAdapter(adapter);
My JSONParser() class is the same as in the tutorial. Now when I run the program I get the error:
Error parsing data org.json.JSONException: Value <!DOCTYPE of type java.lang.String cannot be converted to JSONObject.
I don't know why this error is happening since the JSON is valid according to JSONLint, so it shouldn't be sending any HTML, correct? Is there something I'm missing, or even a completely different/better way to extract the JSON? Any kicks in the right direction would be greatly appreciated.
EDIT : I can't self answer yet since I'm a new user, but It turns out that I was getting a NullPointerException in JSONParser() that I didn't see before, and using HttpGet() rather than HttpPost() solved my problem.
Thanks.
Look at this line in JSONParser
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "iso-8859-1"), 8);
Site returns this header
Content-Type: text/html; charset=UTF-8
You have to change iso-8859-1 to UTF-8 in BufferedReader.
It turns out that I was getting a NullPointerException in JSONParser() that I didn't see before and using HttpGet() rather than HttpPost() solved my problem.