Given an arbitrary JSON I would like to get value of a single field contentType. How to do it with Jackson?
{
contentType: "foo",
fooField1: ...
}
{
contentType: "bar",
barArray: [...]
}
Related
How to find specified name and its value in JSON-string from Java? (GSON)
Using gson to deserialize specific JSON field of an object (GSON)
The Jackson Way
Considering that you don't have a POJO describing your data structure, you could simply do:
final String json = "{\"contentType\": \"foo\", \"fooField1\": ... }";
final ObjectNode node = new ObjectMapper().readValue(json, ObjectNode.class);
// ^
// actually, try and *reuse* a single instance of ObjectMapper
if (node.has("contentType")) {
System.out.println("contentType: " + node.get("contentType"));
}
Addressing concerns in the comments section
If, however, you wish to not consume the entire source String, but simply access a specific property whose path you know, you'll have to write it yourself, leveraging a Tokeniser.
Actually, it's the weekend and I got time on my hands, so I could give you a head start: here's a basic one! It can run in strict mode and spew out sensible error messages, or be lenient and return Optional.empty when the request couldn't be fulfilled.
public static class JSONPath {
protected static final JsonFactory JSON_FACTORY = new JsonFactory();
private final List<JSONKey> keys;
public JSONPath(final String from) {
this.keys = Arrays.stream((from.startsWith("[") ? from : String.valueOf("." + from))
.split("(?=\\[|\\]|\\.)"))
.filter(x -> !"]".equals(x))
.map(JSONKey::new)
.collect(Collectors.toList());
}
public Optional<String> getWithin(final String json) throws IOException {
return this.getWithin(json, false);
}
public Optional<String> getWithin(final String json, final boolean strict) throws IOException {
try (final InputStream stream = new StringInputStream(json)) {
return this.getWithin(stream, strict);
}
}
public Optional<String> getWithin(final InputStream json) throws IOException {
return this.getWithin(json, false);
}
public Optional<String> getWithin(final InputStream json, final boolean strict) throws IOException {
return getValueAt(JSON_FACTORY.createParser(json), 0, strict);
}
protected Optional<String> getValueAt(final JsonParser parser, final int idx, final boolean strict) throws IOException {
try {
if (parser.isClosed()) {
return Optional.empty();
}
if (idx >= this.keys.size()) {
parser.nextToken();
if (null == parser.getValueAsString()) {
throw new JSONPathException("The selected node is not a leaf");
}
return Optional.of(parser.getValueAsString());
}
this.keys.get(idx).advanceCursor(parser);
return getValueAt(parser, idx + 1, strict);
} catch (final JSONPathException e) {
if (strict) {
throw (null == e.getCause() ? new JSONPathException(e.getMessage() + String.format(", at path: '%s'", this.toString(idx)), e) : e);
}
return Optional.empty();
}
}
#Override
public String toString() {
return ((Function<String, String>) x -> x.startsWith(".") ? x.substring(1) : x)
.apply(this.keys.stream().map(JSONKey::toString).collect(Collectors.joining()));
}
private String toString(final int idx) {
return ((Function<String, String>) x -> x.startsWith(".") ? x.substring(1) : x)
.apply(this.keys.subList(0, idx).stream().map(JSONKey::toString).collect(Collectors.joining()));
}
#SuppressWarnings("serial")
public static class JSONPathException extends RuntimeException {
public JSONPathException() {
super();
}
public JSONPathException(final String message) {
super(message);
}
public JSONPathException(final String message, final Throwable cause) {
super(message, cause);
}
public JSONPathException(final Throwable cause) {
super(cause);
}
}
private static class JSONKey {
private final String key;
private final JsonToken startToken;
public JSONKey(final String str) {
this(str.substring(1), str.startsWith("[") ? JsonToken.START_ARRAY : JsonToken.START_OBJECT);
}
private JSONKey(final String key, final JsonToken startToken) {
this.key = key;
this.startToken = startToken;
}
/**
* Advances the cursor until finding the current {#link JSONKey}, or
* having consumed the entirety of the current JSON Object or Array.
*/
public void advanceCursor(final JsonParser parser) throws IOException {
final JsonToken token = parser.nextToken();
if (!this.startToken.equals(token)) {
throw new JSONPathException(String.format("Expected token of type '%s', got: '%s'", this.startToken, token));
}
if (JsonToken.START_ARRAY.equals(this.startToken)) {
// Moving cursor within a JSON Array
for (int i = 0; i != Integer.valueOf(this.key).intValue(); i++) {
JSONKey.skipToNext(parser);
}
} else {
// Moving cursor in a JSON Object
String name;
for (parser.nextToken(), name = parser.getCurrentName(); !this.key.equals(name); parser.nextToken(), name = parser.getCurrentName()) {
JSONKey.skipToNext(parser);
}
}
}
/**
* Advances the cursor to the next entry in the current JSON Object
* or Array.
*/
private static void skipToNext(final JsonParser parser) throws IOException {
final JsonToken token = parser.nextToken();
if (JsonToken.START_ARRAY.equals(token) || JsonToken.START_OBJECT.equals(token) || JsonToken.FIELD_NAME.equals(token)) {
skipToNextImpl(parser, 1);
} else if (JsonToken.END_ARRAY.equals(token) || JsonToken.END_OBJECT.equals(token)) {
throw new JSONPathException("Could not find requested key");
}
}
/**
* Recursively consumes whatever is next until getting back to the
* same depth level.
*/
private static void skipToNextImpl(final JsonParser parser, final int depth) throws IOException {
if (depth == 0) {
return;
}
final JsonToken token = parser.nextToken();
if (JsonToken.START_ARRAY.equals(token) || JsonToken.START_OBJECT.equals(token) || JsonToken.FIELD_NAME.equals(token)) {
skipToNextImpl(parser, depth + 1);
} else {
skipToNextImpl(parser, depth - 1);
}
}
#Override
public String toString() {
return String.format(this.startToken.equals(JsonToken.START_ARRAY) ? "[%s]" : ".%s", this.key);
}
}
}
Assuming the following JSON content:
{
"people": [{
"name": "Eric",
"age": 28
}, {
"name": "Karin",
"age": 26
}],
"company": {
"name": "Elm Farm",
"address": "3756 Preston Street Wichita, KS 67213",
"phone": "857-778-1265"
}
}
... you could use my JSONPath class as follows:
final String json = "{\"people\":[],\"company\":{}}"; // refer to JSON above
System.out.println(new JSONPath("people[0].name").getWithin(json)); // Optional[Eric]
System.out.println(new JSONPath("people[1].name").getWithin(json)); // Optional[Karin]
System.out.println(new JSONPath("people[2].name").getWithin(json)); // Optional.empty
System.out.println(new JSONPath("people[0].age").getWithin(json)); // Optional[28]
System.out.println(new JSONPath("company").getWithin(json)); // Optional.empty
System.out.println(new JSONPath("company.name").getWithin(json)); // Optional[Elm Farm]
Keep in mind that it's basic. It doesn't coerce data types (every value it returns is a String) and only returns leaf nodes.
Actual test case
It handles InputStreams, so you can test it against some giant JSON document and see that it's much faster than it would take your browser to download and display its contents:
System.out.println(new JSONPath("info.contact.email")
.getWithin(new URL("http://test-api.rescuegroups.org/v5/public/swagger.php").openStream()));
// Optional[support#rescuegroups.org]
Quick test
Note I'm not re-using any already existing JSONPath or ObjectMapper so the results are inaccurate -- this is just a very rough comparison anyways:
public static Long time(final Callable<?> r) throws Exception {
final long start = System.currentTimeMillis();
r.call();
return Long.valueOf(System.currentTimeMillis() - start);
}
public static void main(final String[] args) throws Exception {
final URL url = new URL("http://test-api.rescuegroups.org/v5/public/swagger.php");
System.out.println(String.format( "%dms to get 'info.contact.email' with JSONPath",
time(() -> new JSONPath("info.contact.email").getWithin(url.openStream()))));
System.out.println(String.format( "%dms to just download the entire document otherwise",
time(() -> new Scanner(url.openStream()).useDelimiter("\\A").next())));
System.out.println(String.format( "%dms to bluntly map it entirely with Jackson and access a specific field",
time(() -> new ObjectMapper()
.readValue(url.openStream(), ObjectNode.class)
.get("info").get("contact").get("email"))));
}
378ms to get 'info.contact.email' with JSONPath
756ms to just download the entire document otherwise
896ms to bluntly map it entirely with Jackson and access a specific field
Just want to update for 2019. I found the following easiest to impl:
//json can be file or String
JsonNode parent= new ObjectMapper().readTree(json);
String content = parent.path("contentType").asText();
I would suggest to use path instead of get as get throws a NPE, where path returns with a default 0 or "", which is safer to work with if setting up the parsing correctly for 1st time.
My $0.02
If you are using JSON jars in your application then the following code snippet is useful:
String json = "{\"contentType\": \"foo\", \"fooField1\": ... }";
JSONObject jsonObject = new JSONObject(json);
System.out.println(jsonObject.getString("contentType"));
and if you are using Gson jars then the same code will look like following:
Gson gson = new GsonBuilder().create();
Map jsonMap = gson.fromJson(json, Map.class);
System.out.println(jsonMap.get("contentType"));
Another way is:
String json = "{\"contentType\": \"foo\", \"fooField1\": ... }";
JsonNode parent= new ObjectMapper().readTree(json);
String content = parent.get("contentType").asText();
I faced this issue when I decided to use Jackson as the json library for a project I worked on; mainly for its speed. I was already used to using org.json and Gson for my projects.
I quickly found out though that many tasks that were trivial in org.json and Gson were not so straightforward in Jackson
So I wrote the following classes to make things easier for me.
The classes below will allow you to use Jackson as easily as you would the simple org.json library, while still retaining the power and speed of Jackson
I wrote the whole thing in a few hours, so feel free to debug and suit the code to your own purposes.
Note that JSONObject/JSONArray below will do exactly what the OP wants.
The first is JSONObject which has similar methods to org.json.JSONObject; but at heart runs Jackson code to build JSON and parse json strings.
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* #author GBEMIRO JIBOYE <gbenroscience#gmail.com>
*/
public class JSONObject {
ObjectNode parseNode;
public JSONObject() {
this.parseNode = JsonNodeFactory.instance.objectNode(); // initializing
}
public JSONObject(String json) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
try {
this.parseNode = mapper.readValue(json, ObjectNode.class);
} catch (JsonProcessingException ex) {
Logger.getLogger(JSONObject.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void put(String key, String value) {
parseNode.put("key", value); // building
}
public void put(String key, boolean value) {
parseNode.put("key", value); // building
}
public void put(String key, int value) {
parseNode.put("key", value); // building
}
public void put(String key, short value) {
parseNode.put("key", value); // building
}
public void put(String key, float value) {
parseNode.put("key", value); // building
}
public void put(String key, long value) {
parseNode.put("key", value); // building
}
public void put(String key, double value) {
parseNode.put("key", value); // building
}
public void put(String key, byte[] value) {
parseNode.put("key", value); // building
}
public void put(String key, BigInteger value) {
parseNode.put("key", value); // building
}
public void put(String key, BigDecimal value) {
parseNode.put("key", value); // building
}
public void put(String key, Object[] value) {
ArrayNode anode = parseNode.putArray(key);
for (Object o : value) {
anode.addPOJO(o); // building
}
}
public void put(String key, JSONObject value) {
parseNode.set(key, value.parseNode);
}
public void put(String key, Object value) {
parseNode.putPOJO(key, value);
}
public static class Parser<T> {
public T decode(String json, Class clazz) {
try {
return new Converter<T>().fromJsonString(json, clazz);
} catch (IOException ex) {
Logger.getLogger(JSONObject.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
}
public int optInt(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null ? nod.asInt(0) : 0;
}
return 0;
}
public long optLong(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null ? nod.asLong(0) : 0;
}
return 0;
}
public double optDouble(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null ? nod.asDouble(0) : 0;
}
return 0;
}
public boolean optBoolean(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null ? nod.asBoolean(false) : false;
}
return false;
}
public double optFloat(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null && nod.isFloat() ? nod.floatValue() : 0;
}
return 0;
}
public short optShort(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null && nod.isShort() ? nod.shortValue() : 0;
}
return 0;
}
public byte optByte(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return nod != null && nod.isShort() ? (byte) nod.asInt(0) : 0;
}
return 0;
}
public JSONObject optJSONObject(String key) {
if (parseNode != null) {
if (parseNode.has(key)) {
ObjectNode nod = parseNode.with(key);
JSONObject obj = new JSONObject();
obj.parseNode = nod;
return obj;
}
}
return new JSONObject();
}
public JSONArray optJSONArray(String key) {
if (parseNode != null) {
if (parseNode.has(key)) {
ArrayNode nod = parseNode.withArray(key);
JSONArray obj = new JSONArray();
if (nod != null) {
obj.parseNode = nod;
return obj;
}
}
}
return new JSONArray();
}
public String optString(String key) {
if (parseNode != null) {
JsonNode nod = parseNode.get(key);
return parseNode != null && nod.isTextual() ? nod.asText("") : "";
}
return "";
}
#Override
public String toString() {
return parseNode.toString();
}
public String toCuteString() {
return parseNode.toPrettyString();
}
}
Here is the code for the JSONArray equivalent that works like org.json.JSONArray; but uses Jackson code.
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.math.BigDecimal;
import java.math.BigInteger;
/**
*
* #author GBEMIRO JIBOYE <gbenroscience#gmail.com>
*/
public class JSONArray {
protected ArrayNode parseNode;
public JSONArray() {
this.parseNode = JsonNodeFactory.instance.arrayNode(); // initializing
}
public JSONArray(String json) throws JsonProcessingException{
ObjectMapper mapper = new ObjectMapper();
this.parseNode = mapper.readValue(json, ArrayNode.class);
}
public void putByte(byte val) {
parseNode.add(val);
}
public void putShort(short val) {
parseNode.add(val);
}
public void put(int val) {
parseNode.add(val);
}
public void put(long val) {
parseNode.add(val);
}
public void pu(float val) {
parseNode.add(val);
}
public void put(double val) {
parseNode.add(val);
}
public void put(String val) {
parseNode.add(val);
}
public void put(byte[] val) {
parseNode.add(val);
}
public void put(BigDecimal val) {
parseNode.add(val);
}
public void put(BigInteger val) {
parseNode.add(val);
}
public void put(Object val) {
parseNode.addPOJO(val);
}
public void put(int index, JSONArray value) {
parseNode.set(index, value.parseNode);
}
public void put(int index, JSONObject value) {
parseNode.set(index, value.parseNode);
}
public String optString(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null ? nod.asText("") : "";
}
return "";
}
public int optInt(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null ? nod.asInt(0) : 0;
}
return 0;
}
public long optLong(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null ? nod.asLong(0) : 0;
}
return 0;
}
public double optDouble(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null ? nod.asDouble(0) : 0;
}
return 0;
}
public boolean optBoolean(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null ? nod.asBoolean(false) : false;
}
return false;
}
public double optFloat(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null && nod.isFloat() ? nod.floatValue() : 0;
}
return 0;
}
public short optShort(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null && nod.isShort() ? nod.shortValue() : 0;
}
return 0;
}
public byte optByte(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
return nod != null && nod.isShort() ? (byte) nod.asInt(0) : 0;
}
return 0;
}
public JSONObject optJSONObject(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
if(nod != null){
if(nod.isObject()){
ObjectNode obn = (ObjectNode) nod;
JSONObject obj = new JSONObject();
obj.parseNode = obn;
return obj;
}
}
}
return new JSONObject();
}
public JSONArray optJSONArray(int index) {
if (parseNode != null) {
JsonNode nod = parseNode.get(index);
if(nod != null){
if(nod.isArray()){
ArrayNode anode = (ArrayNode) nod;
JSONArray obj = new JSONArray();
obj.parseNode = anode;
return obj;
}
}
}
return new JSONArray();
}
#Override
public String toString() {
return parseNode.toString();
}
public String toCuteString() {
return parseNode.toPrettyString();
}
}
Finally for a one size-fits-all-most-likely for encoding and decoding your Java classes to JSON, I added this simple class:
/**
*
* #author GBEMIRO JIBOYE <gbenroscience#gmail.com>
*/
public class Converter<T> {
// Serialize/deserialize helpers
private Class clazz;
public Converter() {}
public T fromJsonString(String json , Class clazz) throws IOException {
this.clazz = clazz;
return getObjectReader().readValue(json);
}
public String toJsonString(T obj) throws JsonProcessingException {
this.clazz = obj.getClass();
return getObjectWriter().writeValueAsString(obj);
}
private ObjectReader requestReader;
private ObjectWriter requestWriter;
private void instantiateMapper() {
ObjectMapper mapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
requestReader = mapper.readerFor(clazz);
requestWriter = mapper.writerFor(clazz);
}
private ObjectReader getObjectReader() {
if (requestReader == null) {
instantiateMapper();
}
return requestReader;
}
private ObjectWriter getObjectWriter() {
if (requestWriter == null) {
instantiateMapper();
}
return requestWriter;
}
}
Now to taste(test) the sauce(code), use the following methods:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* #author GBEMIRO JIBOYE <gbenroscience#gmail.com>
*/
public class SimplerJacksonTest {
static class Credentials {
private String userName;
private String uid;
private String password;
private long createdAt;
public Credentials() {
}
public Credentials(String userName, String uid, String password, long createdAt) {
this.userName = userName;
this.uid = uid;
this.password = password;
this.createdAt = createdAt;
}
#JsonProperty("userName")
public String getUserName() {
return userName;
}
#JsonProperty("userName")
public void setUserName(String userName) {
this.userName = userName;
}
#JsonProperty("uid")
public String getUid() {
return uid;
}
#JsonProperty("uid")
public void setUid(String uid) {
this.uid = uid;
}
#JsonProperty("password")
public String getPassword() {
return password;
}
#JsonProperty("password")
public void setPassword(String password) {
this.password = password;
}
#JsonProperty("createdAt")
public long getCreatedAt() {
return createdAt;
}
#JsonProperty("createdAt")
public void setCreatedAt(long createdAt) {
this.createdAt = createdAt;
}
public String encode() {
try {
return new Converter<Credentials>().toJsonString(this);
} catch (JsonProcessingException ex) {
Logger.getLogger(Credentials.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
public Credentials decode(String jsonData) {
try {
return new Converter<Credentials>().fromJsonString(jsonData, Credentials.class);
} catch (Exception ex) {
Logger.getLogger(Converter.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
}
public static JSONObject testJSONObjectBuild() {
JSONObject obj = new JSONObject();
Credentials cred = new Credentials("Adesina", "01eab26bwkwjbak2vngxh9y3q6", "xxxxxx1234", System.currentTimeMillis());
String arr[] = new String[]{"Boy", "Girl", "Man", "Woman"};
int nums[] = new int[]{0, 1, 2, 3, 4, 5};
obj.put("creds", cred);
obj.put("pronouns", arr);
obj.put("creds", cred);
obj.put("nums", nums);
System.out.println("json-coding: " + obj.toCuteString());
return obj;
}
public static void testJSONObjectParse(String json) {
JSONObject obj;
try {
obj = new JSONObject(json);
JSONObject credsObj = obj.optJSONObject("creds");
String userName = credsObj.optString("userName");
String uid = credsObj.optString("uid");
String password = credsObj.optString("password");
long createdAt = credsObj.optLong("createdAt");
System.out.println("<<---Parse Results--->>");
System.out.println("userName = " + userName);
System.out.println("uid = " + uid);
System.out.println("password = " + password);
System.out.println("createdAt = " + createdAt);
} catch (JsonProcessingException ex) {
Logger.getLogger(JSONObject.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static JSONArray testJSONArrayBuild() {
JSONArray array = new JSONArray();
array.put(new Credentials("Lawani", "001uadywdbs", "ampouehehu", System.currentTimeMillis()));
array.put("12");
array.put(98);
array.put(Math.PI);
array.put("Good scores!");
System.out.println("See the built array: "+array.toCuteString());
return array;
}
public static void testJSONArrayParse(String json) {
try {
JSONArray array = new JSONArray(json);
JSONObject credsObj = array.optJSONObject(0);
//Parse credentials in index 0
String userName = credsObj.optString("userName");
String uid = credsObj.optString("uid");
String password = credsObj.optString("password");
long createdAt = credsObj.optLong("createdAt");
//Now return to the main array and parse other entries
String twelve = array.optString(1);
int ninety = array.optInt(2);
double pi = array.optDouble(3);
String scoreNews = array.optString(4);
System.out.println("Parse Results");
System.out.println("userName = " + userName);
System.out.println("uid = " + uid);
System.out.println("password = " + password);
System.out.println("createdAt = " + createdAt);
System.out.println("Parse Results");
System.out.println("index 1 = " + twelve);
System.out.println("index 2 = " + ninety);
System.out.println("index 3 = " + pi);
System.out.println("index 4 = " + scoreNews);
} catch (JsonProcessingException ex) {
Logger.getLogger(JSONObject.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static String testCredentialsEncode(){
Credentials cred = new Credentials("Olaoluwa", "01eab26bwkwjbak2vngxh9y3q6", "xxxxxx1234", System.currentTimeMillis());
String encoded = cred.encode();
System.out.println("encoded credentials = "+encoded);
return encoded;
}
public static Credentials testCredentialsDecode(String json){
Credentials cred = new Credentials().decode(json);
System.out.println("encoded credentials = "+cred.encode());
return cred;
}
public static void main(String[] args) {
JSONObject jo = testJSONObjectBuild();
testJSONObjectParse(jo.toString());
JSONArray ja = testJSONArrayBuild();
testJSONArrayParse(ja.toString());
String credsJSON = testCredentialsEncode();
testCredentialsDecode(credsJSON);
}
}
To get the source code in a place, instead of having to copy the one here, see:
the code on Github
Related
[Unable to access property of another object stored in Arraylist]
I am creating an function to get JSON input in object from RESTful Web service input and format it again in JSON format to call other web service.
I have limitation that I can not use any JSON API for object mapping hence using Java reflection core API.
I am able to create JSON format from Input for simple elements but unable to access nested elements (another user defined POJO class ). I am using arraylist.
Input
{
"GenesisIncidents": {
"service": "Transmission",
"affectedCI": "22BT_ORNC03",
"opt_additionalAffectedItems": [
{
"itemType": "NODE-ID",
"ItemName": "22BT_ORNC03"
},
{
"ItemType": "CCT",
"ItemName": "A_circuit_id"
}]
}
}
GenesisIncidents.class
import java.util.ArrayList;
import java.util.Date;
public class GenesisIncidents {
private String service;
private String affectedCI;
private ArrayList<AdditionalAffectedItems> opt_additionalAffectedItems;
public GenesisIncidents(){}
public String getService() {
return service;
}
public void setService(String service) {
this.service = service;
}
public String getAffectedCI() {
return affectedCI;
}
public void setAffectedCI(String affectedCI) {
this.affectedCI = affectedCI;
}
public ArrayList<AdditionalAffectedItems> getOpt_additionalAffectedItems() {
return opt_additionalAffectedItems;
}
public void setOpt_additionalAffectedItems(ArrayList<AdditionalAffectedItems> opt_additionalAffectedItems) {
this.opt_additionalAffectedItems = opt_additionalAffectedItems;
}
}
AdditionalAffectedItems.class
public class AdditionalAffectedItems {
private String itemType;
private String itemName;
public AdditionalAffectedItems(){
super();
}
public String getItemType() {
return itemType;
}
public void setItemType(String itemType) {
this.itemType = itemType;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
}
Implemetation
public void updateTicketExt(GenesisIncidents genesisIncidents) {
try{
Field allFields[]=genesisIncidents.getClass().getDeclaredFields();
Method allMethods[] = genesisIncidents.getClass().getDeclaredMethods();
String jsonString ="{\r\n \""+genesisIncidents.getClass().getName().toString().substring(48)+"\": {";
final String preStr="\r\n \""; //To create a JSON object format.
final String postStr="\": "; //To create a JSON object format.
int totalNoOfFields=allFields.length;
for (Field field : allFields) {
System.out.println(field.getType());
String getter="get"+StringUtils.capitalize(field.getName());
Method method= genesisIncidents.getClass().getMethod(getter, null);
try{
if(field.getType().toString().contains("Integer"))
jsonString=jsonString + preStr + field.getName() + postStr +method.invoke(genesisIncidents).toString()+",";
else
jsonString=jsonString + preStr + field.getName() + postStr +"\""+method.invoke(genesisIncidents).toString()+"\",";
if(field.getType().toString().contains("ArrayList")){
System.out.println("ArrayListElement found");
genesisIncidents.getOpt_additionalAffectedItems().forEach(obj->{System.out.println(obj.getItemName());});
//convertArrayToJSON(field, genesisIncidents);
}
}catch(NullPointerException npe)
{
System.out.println("Null value in field.");
continue;
}
}
jsonString=jsonString.substring(0,jsonString.length()-1);
jsonString=jsonString+"\r\n }\r\n }";
System.out.println("\n"+jsonString);
}catch(Exception jex){
jex.printStackTrace();
}
}
My below code line is unable to access object stored under array list.
genesisIncidents.getOpt_additionalAffectedItems().forEach(obj->{System.out.println(obj.getItemName());});
OUTPUT
karaf#root>class java.lang.String
class java.lang.String
class java.lang.String
class java.util.ArrayList
ArrayListElement found
null
null
{
"GenesisIncidents": {
"service": "Transmission",
"affectedCI": "22BT_ORNC03",
"opt_additionalAffectedItems": " [org.apache.servicemix.examples.camel.rest.model.AdditionalAffectedItems#5881a 895, org.apache.servicemix.examples.camel.rest.model.AdditionalAffectedItems#399b4e eb]"
}
}
I have fiddled around with your example I have managed to get it working. This will produce the correct JSON string by passing in an instance of a GenesisIncident object. I guess that there is much room for improvement here but this can serve as an example.
public static String genesisToJson(GenesisIncidents incidents) {
try{
StringBuilder jsonBuilder = new StringBuilder();
jsonBuilder.append("{\r\n \"")
.append(incidents.getClass().getSimpleName())
.append("\": {");
Field allFields[] = incidents.getClass().getDeclaredFields();
for (Field field : allFields) {
String getter = getGetterMethod(field);
Method method = incidents.getClass().getMethod(getter, null);
try{
if(field.getType().isAssignableFrom(Integer.class)) {
jsonBuilder.append(preStr).append(field.getName()).append(postStr)
.append(method.invoke(incidents).toString()).append(",");
} else if (field.getType().isAssignableFrom(String.class)) {
jsonBuilder.append(preStr).append(field.getName()).append(postStr).append("\"")
.append(method.invoke(incidents).toString()).append("\",");
} else if (field.getType().isAssignableFrom(List.class)) {
System.out.println("ArrayListElement found");
getInnerObjectToJson(field, incidents.getOptItems(), jsonBuilder);
}
} catch(NullPointerException npe) {
System.out.println("Null value in field.");
continue;
}
}
jsonBuilder.append("\r\n } \r\n }");
return jsonBuilder.toString();
}catch(Exception jex){
jex.printStackTrace();
}
return null;
}
private static void getInnerObjectToJson(Field field, List<AdditionalAffectedItems> items, StringBuilder builder)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
builder.append(preStr).append(field.getName()).append(postStr).append("[");
for (var item : items) {
var fields = List.of(item.getClass().getDeclaredFields());
builder.append("{");
for (var f : fields) {
String getter = getGetterMethod(f);
Method method = item.getClass().getMethod(getter, null);
builder.append(preStr).append(f.getName()).append(postStr).append("\"")
.append(method.invoke(item).toString()).append("\"");
if (!(fields.indexOf(f) == (fields.size() - 1))) {
builder.append(",");
}
}
if (items.indexOf(item) == (items.size() - 1)) {
builder.append("}\r\n");
} else {
builder.append("},\r\n");
}
}
builder.append("]");
}
private static String getGetterMethod(Field field) {
return "get" + StringUtils.capitalize(field.getName());
}
I have a program that reads in a simple JSON file and manipulates the data. I then store this data in trees (albeit badly). I have a problem where arguments can longs e.g {1,2}, longs and variables e.g {1,x2}, or variables with other variables e.g. {x1,x2}.
I have been able to retrieve the variables from the JSONArray. The problem arises when I have a variable and a value. I can't for the life of me figure out how to deal with such an occurrence. I apologise for the excessive use of try-catch operations. If anyone could help me solve this issue, it would be much appreciated.
public class program {
public static void main(String[] args) throws IOException {
File file = new File();
File outputfile = new File();
PrintWriter pw = new PrintWriter(new BufferedWriter(new
FileWriter(outputfile, true)));
JSONParser parser = new JSONParser();
try {
// creates object of parsed file
Object object = parser.parse(new FileReader(file));
// casts object to jsonObject
JSONObject jsonObject = (JSONObject) object;
// gets declaration-list JSONArray from the object created.
JSONArray jsonArray = (JSONArray) jsonObject.get("declaration-list");
// Surrounding this in a try-catch would allow me to deal with the
// different value cases unlike the frist time i wrote it
try {
/*
* iterator to cycle through the array. Made the mistake last
* time of continuously calling a method
*/
Iterator iterator = jsonArray.iterator();
while (iterator.hasNext()) {
JSONObject jo = (JSONObject) iterator.next();
String variableName = (String) jo.get("declared-variable");
MyTreeNode<String> root = new MyTreeNode<>(variableName);
try {
long value = (long) jo.get("value");
MyTreeNode<Long> child1 = new MyTreeNode(value);
System.out.println(root.getData());
root.addChild(child1);
for (MyTreeNode node : root.getChildren()) {
System.out.println(node.getData());
}
test.put(variableName, value);
// numPrint(test, variableName, pw);
} catch (Exception e) {
final JSONObject jsonValue = (JSONObject) jo.get("value");
final String operator = (String) jsonValue.get("operator");
final JSONArray arguments = (JSONArray) jsonValue.get("arguments");
ArrayList values[] = new ArrayList[arguments.size()];
if (operator.equals("set")) {
for(int i = 0; i < arguments.size(); i++){
try{
//prints nested variables
JSONObject jtest = (JSONObject) arguments.get(i);
String varval = (String) jtest.get("variable");
System.out.println(varval);
}catch(Exception g){
}
}
MyTreeNode<myObject> test1 = new MyTreeNode(new myObject(operator, arguments));
root.addChild(test1);
for (MyTreeNode node : root.getChildren()) {
System.out.print(root.getData());
System.out.print(" = ");
System.out.println(node.getData());
}
}
if (operator.equals("pair")) {
MyTreeNode<myObject> test1 = new MyTreeNode(new myObject(operator, arguments));
root.addChild(test1);
for (MyTreeNode node : root.getChildren()) {
System.out.print(root.getData() + " = ");
System.out.println(node.getData());
}
}
}
}
} catch (Exception e) {
System.out.println("oops");
}
} catch (FileNotFoundException e) {
System.out.println("Input file not found");
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParseException e) {
System.out.println("File was not parsed");
e.printStackTrace();
}
pw.flush();
pw.close();
}
}
class MyTreeNode<T> {
private T data = null;
private List<MyTreeNode> children = new ArrayList<>();
private MyTreeNode parent = null;
public MyTreeNode(T data) {
this.data = data;
}
public void addChild(MyTreeNode child) {
child.setParent(this);
this.children.add(child);
}
public void addChild(T data) {
MyTreeNode<T> newChild = new MyTreeNode<>(data);
newChild.setParent(this);
children.add(newChild);
}
public void addChildren(List<MyTreeNode> children) {
for (MyTreeNode t : children) {
t.setParent(this);
}
this.children.addAll(children);
}
public List<MyTreeNode> getChildren() {
return children;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
private void setParent(MyTreeNode parent) {
this.parent = parent;
}
public MyTreeNode getParent() {
return parent;
}
}
class myObject {
String operator;
JSONArray arguments;
public myObject(String operator, JSONArray arguments) {
this.operator = operator;
this.arguments = arguments;
}
public JSONArray get() {
return arguments;
}
public String toString() {
if (arguments.size() == 0) {
return "{}";
}
if (operator.equals("pair")) {
return "(" + arguments.get(0) + "," + arguments.get(1) + ")";
} else if (operator.equals("set")) {
String concat = "{" + arguments.get(0);
for (int i = 1; i < arguments.size(); i++) {
concat += "," + arguments.get(i);
}
return concat += "}";
}
return "wot";
}
}
In order to process the JSONArray, I suggest that you create a method which checks the type of the object first and then delegates the processing to other specialised methods based on its type.
This will allow you re-use the code in case you have arrays in arrays and also to navigate through the JSON tree.
Something along these lines:
private static void processArray(JSONArray jsonArray) {
jsonArray.forEach(o -> {
if (o instanceof Number) {
processNumber((Number) o);
} else if (o instanceof JSONObject) {
process((JSONObject) o);
} else if (o instanceof String) {
process((String) o);
} else if (o instanceof JSONArray) {
processArray((JSONArray) o); // recursive call here.
}
});
}
Other methods would look like:
private static void process(String o) {
System.out.println(o); // just an example
}
public static void processNumber(Number number) {
System.out.println(number); // just an example
}
And the most complex would be the one for processing objects:
private static void process(JSONObject o) {
o.forEach((s, o1) -> {
System.out.println(s);
if (o1 instanceof Number) {
processNumber((Number) o1);
} else if (o1 instanceof JSONObject) {
process((JSONObject) o1); // recursion
} else if (o1 instanceof String) {
process((String) o1);
} else if (o1 instanceof JSONArray) {
processArray((JSONArray) o1);
}
});
}
This method would also be recursive. With this type of approach you can navigate through all objects in the tree.
Update:
If you want to process JSON like:
{
"declared-variable": "x17",
"value": {
"operator": "set",
"arguments": [
1,
2,
{
"variable": "x8"
}
]
}
}
you can do so by creating a main method similar to this one:
public static void main(String[] args) throws IOException, ParseException {
JSONParser jsonParser = new JSONParser(JSONParser.MODE_JSON_SIMPLE);
try (InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("array_mixed.json")) {
Object obj = jsonParser.parse(in);
if (obj instanceof JSONArray) {
processArray((JSONArray) obj);
}
else if(obj instanceof Object) {
process((JSONObject) obj);
}
}
}
This main method together with the other methods described can at least print out all the elements in the JSON.
You should be able to at least print out the following in the case of the specified JSON above:
declared-variable
x17
value
arguments
1
2
variable
x8
operator
set
I´m looking for a way to export a JavaFX TreeView to JSON. To make this whole process simple, I use GSON. Its exporting the value of a treeItem well, but when I try to use the whole Tree its ending in a stack overflow. I believe this has something to do with the parent/child attribute. Is there a way to prevent GSON from exporting this attribute.
And how do I import the whole thing again? I wasn't able to import a simple object of mine, because GSON can't handle Properties.
You need to use a custom type adapter. Furthermore you can prevent stackoverflows by using loops instead of recursion:
public class TreeItemTypeAdapter<T> extends TypeAdapter<TreeItem<T>> {
private Gson gson;
public void setGson(Gson gson) {
this.gson = gson;
}
private final Class<T> valueClass;
public TreeItemTypeAdapter(Class<T> valueClass) {
if (valueClass == null) {
throw new IllegalArgumentException();
}
this.valueClass = valueClass;
}
public static TreeItemTypeAdapter<String> createStringTreeItemAdapter() {
return new TreeItemTypeAdapter<>(String.class);
}
private void writeValue(JsonWriter writer, T t) throws IOException {
if (gson == null) {
writer.value(Objects.toString(t, null));
} else {
gson.toJson(t, valueClass, writer);
}
}
private T readValue(JsonReader reader) throws IOException {
if (gson == null) {
Object value = reader.nextString();
return (T) value;
} else {
return gson.fromJson(reader, valueClass);
}
}
#Override
public void write(JsonWriter writer, TreeItem<T> t) throws IOException {
writer.beginObject().name("value");
writeValue(writer, t.getValue());
writer.name("children").beginArray();
LinkedList<Iterator<TreeItem<T>>> iterators = new LinkedList<>();
iterators.add(t.getChildren().iterator());
while (!iterators.isEmpty()) {
Iterator<TreeItem<T>> last = iterators.peekLast();
if (last.hasNext()) {
TreeItem<T> ti = last.next();
writer.beginObject().name("value");
writeValue(writer, ti.getValue());
writer.name("children").beginArray();
iterators.add(ti.getChildren().iterator());
} else {
writer.endArray().endObject();
iterators.pollLast();
}
}
}
#Override
public TreeItem<T> read(JsonReader reader) throws IOException {
if (gson == null && !valueClass.getName().equals("java.lang.String")) {
throw new IllegalStateException("cannot parse classes other than String without gson provided");
}
reader.beginObject();
if (!"value".equals(reader.nextName())) {
throw new IOException("value expected");
}
TreeItem<T> root = new TreeItem<>(readValue(reader));
TreeItem<T> item = root;
if (!"children".equals(reader.nextName())) {
throw new IOException("children expected");
}
reader.beginArray();
int depth = 1;
while (depth > 0) {
if (reader.hasNext()) {
reader.beginObject();
if (!"value".equals(reader.nextName())) {
throw new IOException("value expected");
}
TreeItem<T> newItem = new TreeItem<>(readValue(reader));
item.getChildren().add(newItem);
item = newItem;
if (!"children".equals(reader.nextName())) {
throw new IOException("children expected");
}
reader.beginArray();
depth++;
} else {
depth--;
reader.endArray();
reader.endObject();
item = item.getParent();
}
}
return root;
}
}
public static void main(String[] args) {
TreeItem<String> ti = new TreeItem<>("Hello world");
TreeItem<String> ti2 = new TreeItem<>("42");
TreeItem<String> ti3 = new TreeItem<>("Foo");
TreeItem<String> ti4 = new TreeItem<>("Bar");
ti.getChildren().addAll(ti2, ti3);
ti2.getChildren().add(ti4);
TreeItemTypeAdapter<String> adapter = new TreeItemTypeAdapter<>(String.class);
Gson gson = new GsonBuilder().registerTypeAdapter(TreeItem.class, adapter).create();
adapter.setGson(gson);
System.out.println(gson.toJson(ti));
System.out.println(toString(gson.fromJson("{\"value\":\"Hello world\",\"children\":[{\"value\":\"42\",\"children\":[{\"value\":\"Bar\",\"children\":[]}]},{\"value\":\"Foo\",\"children\":[]}]}",
TreeItem.class)));
}
private static String toString(TreeItem ti) {
StringBuilder sb = new StringBuilder("TreeItem [ value: \"").append(ti.getValue()).append("\" children [");
boolean notFirst = false;
for (TreeItem i : (List<TreeItem>) ti.getChildren()) {
if (notFirst) {
sb.append(",");
} else {
notFirst = true;
}
sb.append(toString(i));
}
return sb.append("]]").toString();
}
I would like to combine two separate parsed jsonObjects into a single arraylist, then display the results as Strings?
I would like to store summaryJsonObject & segment in storylineData. When I step through the code using the debugger summaryJsonObject & segment both hold the raw json. The raw json data also shows in the logcat but storylineData remains null & unavailable throughout.
Here is the parsing code.
public class StorylineData {
private static String date;
private ArrayList<SummaryData> summary;
private ArrayList<SegmentData> segments;
private String caloriesIdle;
private String lastUpdate;
public String getDate() {
return date;
}
public ArrayList<SummaryData> getSummary() {
return summary;
}
public ArrayList<SegmentData> getSegments() {
return segments;
}
public String getCaloriesIdle() {
return caloriesIdle;
}
public String getLastUpdate() {
return lastUpdate;
}
public void setDate(String date) {
this.date = date;
}
public void setSummary(ArrayList<SummaryData> summary) {
this.summary = summary;
}
public void setSegments(ArrayList<SegmentData> segments) {
this.segments = segments;
}
public void setCaloriesIdle(String caloriesIdle) {
this.caloriesIdle = caloriesIdle;
}
public void setLastUpdate(String lastUpdate) {
this.lastUpdate = lastUpdate;
}
public static StorylineData parse(JSONObject jsonObject) {
if (jsonObject != null) {
StorylineData storylineData = new StorylineData();
storylineData.date = jsonObject.optString("date");
storylineData.caloriesIdle = jsonObject.optString("caloriesIdle");
storylineData.lastUpdate = jsonObject.optString("lastUpdate");
storylineData.summary = new ArrayList<SummaryData>();
storylineData.segments = new ArrayList<SegmentData>();
JSONArray summariesJsonArray= jsonObject.optJSONArray("summary");
if (summariesJsonArray != null) {
for (int i = 0; i < summariesJsonArray.length(); i++) {
JSONObject summaryJsonObject = summariesJsonArray.optJSONObject(i);
if (summaryJsonObject != null) {
storylineData.summary.add(SummaryData.parse(summaryJsonObject));
Log.d("storylineHandler", summaryJsonObject.toString());
}
}
}
JSONArray segmentsJsonArray = jsonObject.optJSONArray("segments");
if (segmentsJsonArray != null) {
for (int i = 0; i < segmentsJsonArray.length(); i++) {
JSONObject segment = segmentsJsonArray.optJSONObject(i);
if (segment != null) {
storylineData.segments.add(SegmentData.parse(segment));
Log.d("storylineHandler", segment.toString());
}
}
}
return storylineData;
}
return null;
}
}
The MainActivity looks like this:
MainActivity
public class MainActivity extends FragmentActivity implements OnClickListener{
..other variables here..
List<StorylineData> storylineData;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...other ui elements here...
mEditTextResponse = (TextView) findViewById(R.id.editResponse);
storylineData = new StorylineData();
MovesAPI.init(this, CLIENT_ID, CLIENT_SECRET, CLIENT_SCOPES.....
#Override
public void onClick(View v) {
toggleProgress(true);
switch (mSpinnerAPI.getSelectedItemPosition()) {
... other cases here...
break;
...other cases here...
case 4: // Get Summary Day
MovesAPI.getSummary_SingleDay(summaryHandler, "20150418", null);//Date changed to "20150117"
break;
Other cases here..
case 10: // Get Storyline Day
MovesAPI.getStoryline_SingleDay(storylineHandler, "20150418", null, false);//Date changed to "20150418"
break;
...Other cases here..
}
}
... Other MovesHandlers here...
private JSONObject summaryJsonObject;
private List<StorylineData> storylineList;
private JSONObject summariesJsonArray;
private MovesHandler<ArrayList<StorylineData>> storylineHandler = new MovesHandler<ArrayList<StorylineData>>() {
#Override
public void onSuccess(ArrayList<StorylineData> result) {
toggleProgress(false);
storylineList = (List<StorylineData>) StorylineData.parse(summaryJsonObject);
updateResponse( + storylineData.toString() + "\n" //displays true to layout view
result.add(StorylineData.parse(summariesJsonArray))+ "\n"
+Log.d("call result", result.toString()) + "\n" //displays 60 in layout view & com.protogeo.moves.demos.apps.storyline.StorylineData#52824f88, null]
+ Log.d("Log.d storylineHandler", storylineHandler.toString()) + "\n" ); //returns 78 in layout view & com.protogeo.moves.demos.apps.Mainactivity#234234 to log cat
onFailure code here..
}
};
public void toggleProgress(final boolean isProgrressing) {
togglePregress code here..
}
public void updateResponse(final String message) {
runOnUiThread(new Runnable() {
public List<StorylineData> storylineList;
#Override
public void run() {
mEditTextResponse.setText(message);
if (storylineData!= null) {
for (StorylineData storylineData : storylineList) {
mEditTextResponse.append(("storylineData" + storylineData.toString()));
}
}
}
});
}
}
HttpClass
public static void getDailyStorylineList(final MovesHandler<JSONArray> handler,
final String specificSummary,
final String from,
final String to,
final String pastDays,
final String updatedSince,
final boolean needTrackPoints) {
new Thread(new Runnable() {
#Override
public void run() {
try {
/* Refresh access token if only AuthData.MOVES_REFRESHBEFORE days are there to expire current token */
AuthData.refreshAccessTokenIfNeeded();
/* Exchange the authorization code we obtained after login to get access token */
HashMap<String, String> nameValuePairs = new HashMap<String, String>();
nameValuePairs.put("access_token", AuthData.getAuthData().getAccessToken());
// if (specificSummary != null && specificSummary.length() > 0) nameValuePairs.put("specificSummary", specificSummary);//att
if (from != null && from.length() > 0) nameValuePairs.put("from", from);
if (to != null && to.length() > 0) nameValuePairs.put("to", to);
if (pastDays != null && pastDays.length() > 0) nameValuePairs.put("pastDays", pastDays);
if (updatedSince != null && updatedSince.length() > 0) nameValuePairs.put("updatedSince", updatedSince);
if (needTrackPoints) nameValuePairs.put("trackPoints", "true");
URL url = new URL(MovesAPI.API_BASE + MovesAPI.API_PATH_STORYLINE + (specificSummary != null ? specificSummary : "") + "?" + Utilities.encodeUrl(nameValuePairs));
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoInput(true);
urlConnection.connect();
if (urlConnection.getResponseCode() != 200) {
/* All other HTTP errors from Moves will fall here */
handler.onFailure(getErrorStatus(Utilities.readStream(urlConnection.getErrorStream()), urlConnection.getResponseCode()), "Server not responded with success ("+ urlConnection.getResponseCode() +")");
return;
}
String response = Utilities.readStream(urlConnection.getInputStream());
Object object = new JSONTokener(response).nextValue();
if (object instanceof JSONArray) {
JSONArray jsonArray = (JSONArray) object;
ArrayList<StorylineData> storylineData = new ArrayList<StorylineData>();
if (jsonArray != null) {
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject storylineJsonObject = jsonArray.optJSONObject(i);
if (storylineJsonObject != null) {
storylineData.add(StorylineData.parse(storylineJsonObject));
}
}
}
handler.onSuccess(storylineData);
} else {
handler.onFailure(MovesStatus.INVALID_RESPONSE, "Expected a JSONArray from server, but failed");
}
} catch (Exception ex) {
ex.printStackTrace();
handler.onFailure(MovesStatus.UNEXPECTED_ERROR, "An unexpected error occured, please check logcat");
}
}
}).start();
}
MovesHandler
public interface MovesHandler<T> {//T stands for generic type
/**
* Implement this method to get success notifications along with the result
* #param result : Result of the operation completed with this handler
*/
public void onSuccess(ProfileData result);
/**
* Implement this method to get failure notifications along with the {#link MovesStatus} code and a brief message
* #param status : Status code of the failure
* #param message : A brief message about the reason behind failure
*/
public void onFailure(MovesStatus status, String message);
}
If you wanted to have one ArrayList to store both SummaryData and SegmentData, you could just created an ArrayList of Objects, ArrayList<Object>. This would be the more general solution.
The alternative would be having SummaryData and SegmentData inherit the same class or implement the same interface.
Using an extended class, you could have:
class Data {
}
class SegmentData extends Data {
}
class SummaryData extends Data {
}
You could then have an ArrayList that would be able to add both SegmentData and SummaryData objects.
If you wanted to show each item as a String you would need to loop through the list and call the toString() function of each item
ArrayList<Data> dataList;
for (Data d : dataList) {
Log.d("data", d.toString())
}
Just make sure to overwrite the toString() function in SegmentData and SummaryData
EDIT: Showing how to print JsonArray
If you wanted to just print for JsonArrays, you could:
public class StorylineData {
private static String date;
private JSONArray summary;
private JSONArray segments;
private String caloriesIdle;
private String lastUpdate;
public String getDate() {
return date;
}
public JSONArray getSummary() {
return summary;
}
public JSONArray getSegments() {
return segments;
}
public String getCaloriesIdle() {
return caloriesIdle;
}
public String getLastUpdate() {
return lastUpdate;
}
public void setDate(String date) {
this.date = date;
}
public void setSummary(JSONArray summary) {
this.summary = summary;
}
public void setSegments(JSONArray segments) {
this.segments = segments;
}
public void setCaloriesIdle(String caloriesIdle) {
this.caloriesIdle = caloriesIdle;
}
public void setLastUpdate(String lastUpdate) {
this.lastUpdate = lastUpdate;
}
public static StorylineData parse(JSONObject jsonObject) {
if (jsonObject != null) {
StorylineData storylineData = new StorylineData();
storylineData.date = jsonObject.optString("date");
storylineData.caloriesIdle = jsonObject.optString("caloriesIdle");
storylineData.lastUpdate = jsonObject.optString("lastUpdate");
storylineData.summary = jsonObject.optJSONArray("summary");
storylineData.segments = jsonObject.optJSONArray("segments");
return storylineData;
}
return null;
}
#Override
public String toString() {
JSONArray combined = new JSONArray(summary);
combined.put(segment);
return combined.toString();
}
}
In your MainActivity
private StorylineData storylineData;
private MovesHandler<JSONArray> storylineHandler = new MovesHandler<JSONArray>() {
#Override
public void onSuccess(JSONArray result) {
toggleProgress(false);
storylineData = StorylineData.parse(summaryJsonObject);
updateResponse(storylineData.toString()) //displays true to layout view
result.add(storylineData.getSummary());
Log.d("call result", result.toString());
Log.d("Log.d storylineHandler", storylineHandler.toString());
}
};
I'm trying to access JSON file on the internet and it has some null fields like this one:
{
"c":[
{
"v": "Week 10"
},
null,
null,
null,
null,
{
"v": null
}]
}
when I try to access them to put them on a string an exception is thrown
I've used JSONObject.isNull(""), JSONObject.toString().equals("null") and non of them work help please!!
you can read this Json use getJsonArray to get a List, and then loop this list.
String jstr = "{'c':[{'v': 'Week 10'}, null,null,null,null,{'v': null}]}";
JSONObject json = JSONObject.fromObject(jstr);
JSONArray jsonArray = json.getJSONArray("c");
for(int i=0;i < jsonArray.size();i++){
System.out.println(jsonArray.get(i).toString());
}
or you can read this json into a bean, below is the sample code,hope this can help you.
c.java
public class c {
private String v;
public String getV() {
return v;
}
public void setV(String v) {
this.v = v;
}
}
json2Bean.java
public class json2Bean {
private List<c> c;
public List<c> getC() {
return c;
}
public void setC(List<c> c) {
this.c = c;
}
}
json2String.java
public class json2String {
public static void main(String[] args) {
String jstr = "{'c':[{'v': 'Week 10'}, null,null,null,null,{'v': null}]}";
Map<String, Class<?>> m = new HashMap<String, Class<?>>();
m.put("c", c.class);
json2Bean myBean = (json2Bean) JSONObject.toBean(JSONObject.fromObject(jstr), json2Bean.class, m);
for (c e : myBean.getC()) {
if (e != null) {
System.out.println(e.getV());
}
}
}
}