I am trying to parse my JSONObject to get my JSON Array's data.
But the problem is JSONParser is a class in org.json.simple.JSONParser and the JSONObject is in org.json.JSONObject.
I cannot find any parser in org.json to avoid class cast exception!
Do we have any other way to get this stuff sorted...?
Or am i going in a completely wrong direction?
Please suggest
My JSON looks like :
{
"dataIntents": [
{
"intent": "muster.policy.daily",
"expr": "Am I supposed to register my attendance daily?"
},
{
"intent": "leave.probation",
"expr": "An employee is eligible for how many leaves in 1st year ??"
},
{
"intent": " leave.resigned ",
"expr": "Are resigned employees eligible for pro rata leave credit"
},
{
"intent": " muster.deadline.submission ",
"expr": "By when should I get my pending leave/Emuster applications
approved?"
}
]
}
My main class:
public class DLMain {
public static void main(String[] args) {
try {
JSONParser parser = new JSONParser();
Object obj =
parser.parse(newFileReader("/home/cmss/Downloads/data.json"));
org.json.JSONObject dataObject = (org.json.JSONObject)obj;
System.out.println(dataObject);
org.json.JSONArray getArray =
dataObject.getJSONArray("dataIntents");
for (int i = 0; i < getArray.length(); i++) {
org.json.JSONObject objects = getArray.getJSONObject(i);
String a = objects.getString("expr");
}
System.out.println();
} catch (Exception e) {
System.out.println(e);
}
}
}
I want all values of my "expr" key in a JSONObject or String.
Help appreciated in advance :)
Why don't you use a POJO for that?
So far your Json is a list of intents, you can have something like:
public class Intents {
private List<Intent> dataIntents;
}
and another
public class Intent {
private String intent;
private String expr;
}
(please generate the constructor and getter setter)
And then you can use directly the ObjectMapper and you avoid all the ugly JSON parsing.
Hope it helps!
Related
I have a json
{
"yes":
{
"en": "Yes",
"de": "Ja"
},
"no":
{
"en": "No",
"de": "Nein"
}
}
I want a java function using jackson that can find the highest key possible for a particular json value.
For Instance, if I passed value as Nein -> then no Key which is at the top level should be the output. How can I accomplish this in java??
Well, you could try something like following:
public static void getRootNodeOfJSONObject() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
String jsonString = "{\"yes\":{\"en\": \"Yes\",\"de\": \"Ja\"},\"no\": {\"en\": \"No\",\"de\": \"Nein\"}}";
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JsonNode jsonNodeRoot = objectMapper.readTree(jsonString);
for (Iterator key = jsonNodeRoot.fields(); key.hasNext();) {
String text = key.next().toString();
if(text.contains("Nein"))
{
String rootElement = text.substring(0, text.indexOf("="));
System.out.println("Root element: " + rootElement);
}
}
}
public static void main(String[] args) throws IOException {
getRootNodeOfJSONObject();
}
You can try JsonPath (https://github.com/json-path/JsonPath).
Focus on "Predicates" section.
If you need any help let me know.
I have the following code:
try {
JSONObject json = new JSONObject(data);
...
} catch(JSONException ex) {
if(LOGS_ON) Log.e(TAG, "Could not save data.", ex);
}
It throws an exception, although the json string passed in is pretty valid. The exception is the following:
org.json.JSONException: Value {"ShopId3Digit":"ww0","ServerTime":1426695017191,"SMSTelephone":"2104851130","SendPODAgain":true,"SendLocationAgain":true,"IsHUB":false,"AllowReceiptsAndDeliveries":true} of type java.lang.String cannot be converted to JSONObject
Do you see something wrong with the json data I'm passing in?
BTW this is the string as seen in Eclipse watch:
"{\"ShopId3Digit\":\"ww0\",\"ServerTime\":1426695017191,\"SMSTelephone\":\"2104851130\",\"SendPODAgain\":true,\"SendLocationAgain\":true,\"IsHUB\":false,\"AllowReceiptsAndDeliveries\":true}"
Here's a working version
import org.json.JSONException;
import org.json.JSONObject;
public class Test {
public static void main(String[] args) {
String data = "{\"ShopId3Digit\":\"ww0\",\"ServerTime\":1426695017191,\"SMSTelephone\":\"2104851130\",\"SendPODAgain\":true,\"SendLocationAgain\":true,\"IsHUB\":false,\"AllowReceiptsAndDeliveries\":true}";
try {
JSONObject json = new JSONObject(data);
System.out.println("Success: json = ");
System.out.println(json.toString(2));
} catch(JSONException ex) {
System.out.println("Error: " + ex);
}
}
}
(using the most recent version available at https://github.com/douglascrockford/JSON-java). I have tested this code, it compiles and successfully outputs
Success: json =
{
"IsHUB": false,
"SMSTelephone": "2104851130",
"AllowReceiptsAndDeliveries": true,
"SendPODAgain": true,
"SendLocationAgain": true,
"ShopId3Digit": "ww0",
"ServerTime": 1426695017191
}
Therefore, the error seems to be not with the json data.
It was my mistake after all. I obtain the data from a .NET program through Newtonsoft serializer. By mistake I was serializing the already serialized object resulting in just a string. The starting and ending quotes in the watch in Eclipse are actually part of the value.
Thank you godfatherofpolka for the effort you went through.
Inshort : I am trying to find some api that could just change the value by taking first parameter as jsonString , second parameter as JSONPath and third will be new value of that parameter. But, all I found is this..
https://code.google.com/p/json-path/
This api allows me to find any value in JSON String. But, I am not finding easy way to update the value of any key. For example, Here is a book.json.
{
"store":{
"book":[
{
"category":"reference",
"author":"Nigel Rees",
"title":"Sayings of the Century",
"price":8.95
},
{
"category":"fiction",
"author":"Evelyn Waugh",
"title":"Sword of Honour",
"price":12.99,
"isbn":"0-553-21311-3"
}
],
"bicycle":{
"color":"red",
"price":19.95
}
}
}
I can access color of bicycle by doing this.
String bicycleColor = JsonPath.read(json, "$.store.bicycle.color");
But I am looking for a method in JsonPath or other api some thing like this
JsonPath.changeNodeValue(json, "$.store.bicycle.color", "green");
String bicycleColor = JsonPath.read(json, "$.store.bicycle.color");
System.out.println(bicycleColor); // This should print "green" now.
I am excluding these options,
Create a new JSON String.
Create a JSON Object to deal with changing value and convert it back to jsonstring
Reason: I have about 500 different requests for different types of service which return different json structure. So, I do not want to manually create new JSON string always. Because, IDs are dynamic in json structure.
Any idea or direction is much appreciated.
Updating this question with following answer.
Copy MutableJson.java.
copy this little snippet and modify as per you need.
private static void updateJsonValue() {
JSONParser parser = new JSONParser();
JSONObject jsonObject = new JSONObject();
FileReader reader = null;
try {
File jsonFile = new File("path to book.json");
reader = new FileReader(jsonFile);
jsonObject = (JSONObject) parser.parse(reader);
} catch (Exception ex) {
System.out.println(ex.getLocalizedMessage());
}
Map<String, Object> userData = null;
try {
userData = new ObjectMapper().readValue(jsonObject.toJSONString(), Map.class);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
MutableJson json = new MutableJson(userData);
System.out.println("Before:\t" + json.map());
json.update("$.store.book[0].author", "jigish");
json.update("$.store.book[1].category", "action");
System.out.println("After:\t" + json.map().toString());
}
Use these libraries.
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.codehaus.jackson.map.ObjectMapper;
The thing is that the functionality you want is already an undocumented feature of JsonPath. Example using your json structure:
String json = "{ \"store\":{ \"book\":[ { \"category\":\"reference\", \"author\":\"Nigel Rees\", \"title\":\"Sayings of the Century\", \"price\":8.95 }, { \"category\":\"fiction\", \"author\":\"Evelyn Waugh\", \"title\":\"Sword of Honour\", \"price\":12.99, \"isbn\":\"0-553-21311-3\" } ], \"bicycle\":{ \"color\":\"red\", \"price\":19.95 } } }";
DocumentContext doc = JsonPath.parse(json).
set("$.store.bicycle.color", "green").
set("$.store.book[0].price", 9.5);
String newJson = new Gson().toJson(doc.read("$"));
Assuming that parsed JSON can be represented in memory as a Map, you can build an API similar to JsonPath that looks like:
void update(Map<String, Object> json, String path, Object newValue);
I've quickly done a gist of a dirty implementation for simple specific paths (no support for conditions and wildcards) that can traverse json tree, E.g. $.store.name, $.store.books[0].isbn. Here it is: MutableJson.java. It definitely needs improvement, but can give a good start.
Usage example:
import java.util.*;
public class MutableJson {
public static void main(String[] args) {
MutableJson json = new MutableJson(
new HashMap<String, Object>() {{
put("store", new HashMap<String, Object>() {{
put("name", "Some Store");
put("books", Arrays.asList(
new HashMap<String, Object>() {{
put("isbn", "111");
}},
new HashMap<String, Object>() {{
put("isbn", "222");
}}
));
}});
}}
);
System.out.println("Before:\t" + json.map());
json.update("$.store.name", "Book Store");
json.update("$.store.books[0].isbn", "444");
json.update("$.store.books[1].isbn", "555");
System.out.println("After:\t" + json.map());
}
private final Map<String, Object> json;
public MutableJson(Map<String, Object> json) {
this.json = json;
}
public Map<String, Object> map() {
return json;
}
public void update(String path, Object newValue) {
updateJson(this.json, Path.parse(path), newValue);
}
private void updateJson(Map<String, Object> data, Iterator<Token> path, Object newValue) {
Token token = path.next();
for (Map.Entry<String, Object> entry : data.entrySet()) {
if (!token.accept(entry.getKey(), entry.getValue())) {
continue;
}
if (path.hasNext()) {
Object value = token.value(entry.getValue());
if (value instanceof Map) {
updateJson((Map<String, Object>) value, path, newValue);
}
} else {
token.update(entry, newValue);
}
}
}
}
class Path {
public static Iterator<Token> parse(String path) {
if (path.isEmpty()) {
return Collections.<Token>emptyList().iterator();
}
if (path.startsWith("$.")) {
path = path.substring(2);
}
List<Token> tokens = new ArrayList<>();
for (String part : path.split("\\.")) {
if (part.matches("\\w+\\[\\d+\\]")) {
String fieldName = part.substring(0, part.indexOf('['));
int index = Integer.parseInt(part.substring(part.indexOf('[')+1, part.indexOf(']')));
tokens.add(new ArrayToken(fieldName, index));
} else {
tokens.add(new FieldToken(part));
}
};
return tokens.iterator();
}
}
abstract class Token {
protected final String fieldName;
Token(String fieldName) {
this.fieldName = fieldName;
}
public abstract Object value(Object value);
public abstract boolean accept(String key, Object value);
public abstract void update(Map.Entry<String, Object> entry, Object newValue);
}
class FieldToken extends Token {
FieldToken(String fieldName) {
super(fieldName);
}
#Override
public Object value(Object value) {
return value;
}
#Override
public boolean accept(String key, Object value) {
return fieldName.equals(key);
}
#Override
public void update(Map.Entry<String, Object> entry, Object newValue) {
entry.setValue(newValue);
}
}
class ArrayToken extends Token {
private final int index;
ArrayToken(String fieldName, int index) {
super(fieldName);
this.index = index;
}
#Override
public Object value(Object value) {
return ((List) value).get(index);
}
#Override
public boolean accept(String key, Object value) {
return fieldName.equals(key) && value instanceof List && ((List) value).size() > index;
}
#Override
public void update(Map.Entry<String, Object> entry, Object newValue) {
List list = (List) entry.getValue();
list.set(index, newValue);
}
}
A JSON string can be easily parsed into a Map using Jackson:
Map<String,Object> userData = new ObjectMapper().readValue("{ \"store\": ... }", Map.class);
Just answering for folks landing on this page in future for reference.
You could consider using a Java implementation of jsonpatch. RFC can be found here
JSON Patch is a format for describing changes to a JSON document. It can be used to avoid sending a whole document when only a part has changed. When used in combination with the HTTP PATCH method it allows partial updates for HTTP APIs in a standards compliant way.
You can specify the operation that needs to be performed (replace, add....), json path at which it has to be performed, and the value which should be used.
Again, taking example from the RFC :
[
{ "op": "test", "path": "/a/b/c", "value": "foo" },
{ "op": "remove", "path": "/a/b/c" },
{ "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] },
{ "op": "replace", "path": "/a/b/c", "value": 42 },
{ "op": "move", "from": "/a/b/c", "path": "/a/b/d" },
{ "op": "copy", "from": "/a/b/d", "path": "/a/b/e" }
]
For Java implementation, I have not used it myself, but you can give a try to https://github.com/fge/json-patch
So in order to change a value within a JSon string, there are two steps:
Parse the JSon
Modify the appropriate field
You are trying to optimize step 2, but understand that you are not going to be able to avoid step 1. Looking at the Json-path source code (which, really, is just a wrapper around Jackson), note that it does do a full parse of the Json string before being able to spit out the read value. It does this parse every time you call read(), e.g. it is not cached.
I think this task is specific enough that you're going to have to write it yourself. Here is what I would do:
Create an object that represents the data in the parsed Json string.
Make sure this object has, as part of it's fields, the Json String pieces that you do not expect to change often.
Create a custom Deserializer in the Json framework of your choice that will populate the fields correctly.
Create a custom Serializer that uses the cached String pieces, plus the data that you expect to change
I think the exact scope of your problem is unusual enough that it is unlikely a library already exists for this. When a program receives a Json String, most of the time what it wants is the fully deserialized object - it is unusual that it needs to FORWARD this object on to somewhere else.
I'm using Google GSON to transform my Java object to JSON.
Currently I'm having the following structure:
"Step": {
"start_name": "Start",
"end_name": "End",
"data": {
"duration": {
"value": 292,
"text": "4 min."
},
"distance": {
"value": 1009.0,
"text": "1 km"
},
"location": {
"lat": 59.0000,
"lng": 9.0000,
"alt": 0.0
}
}
}
Currently a Duration object is inside a Data object. I would like to skip the Data object and move the Duration object to the Step object, like this:
"Step": {
"start_name": "Start",
"end_name": "End",
"duration": {
"value": 292,
"text": "4 min."
},
"distance": {
"value": 1009.0,
"text": "1 km"
},
"location": {
"lat": 59.0000,
"lng": 9.0000,
"alt": 0.0
}
}
How can I do this using GSON?
EDIT: I've tried to use a TypeAdapter to modify the Step.class, but in the write-method I'm not able to add my duration object to the JsonWriter.
You can probably do this by writing, and then registering a custom serializer for Step, and making sure inside it you work with Duration etc, instead of Data.
// registering your custom serializer:
GsonBuilder builder = new GsonBuilder ();
builder.registerTypeAdapter (Step.class, new StepSerializer ());
Gson gson = builder.create ();
// now use 'gson' to do all the work
The code for the custom serializer below, I'm writing off the top of my head. It misses exception handling, and might not compile, and does slow things like create instances of Gson repeatedly. But it represents the kind of thing you'll want to do:
class StepSerializer implements JsonSerializer<Step>
{
public JsonElement serialize (Step src,
Type typeOfSrc,
JsonSerializationContext context)
{
Gson gson = new Gson ();
/* Whenever Step is serialized,
serialize the contained Data correctly. */
JsonObject step = new JsonObject ();
step.add ("start_name", gson.toJsonTree (src.start_name);
step.add ("end_name", gson.toJsonTree (src.end_name);
/* Notice how I'm digging 2 levels deep into 'data.' but adding
JSON elements 1 level deep into 'step' itself. */
step.add ("duration", gson.toJsonTree (src.data.duration);
step.add ("distance", gson.toJsonTree (src.data.distance);
step.add ("location", gson.toJsonTree (src.data.location);
return step;
}
}
In such case I register TypeAdapter for nested data field. Within the the adapter data's fields are added to parent object. No need to create adapter for enclosing class.
public class Step {
private String startName;
private endName;
#JsonAdapter(JsonFlatMapAdapter.class)
private Map<String, Object> data;
...
}
public class JsonFlatMapAdapter extends TypeAdapter<Map<String, Object>> {
#Override
public void write(JsonWriter out, Map<String, Object> value) throws IOException {
out.nullValue();
Gson gson = new Gson();
value.forEach((k,v) -> {
try {
out.name(k).jsonValue(gson.toJson(v));
} catch (IOException e) {
}
});
}
#Override
public Map<String, Object> read(JsonReader in) throws IOException {
return null;
}
}
I don't think there is beautifull way to do it in gson. Maybe get java object (Map) from initial json, remove data, put duration and serialize to json:
Map initial = gson.fromJson(initialJson);
// Replace data with duration in this map
Map converted = ...
String convertedJson = gson.toJson(converted);
Ran into the same problem. The answer from #ArjunShunkar pointed me in the right direction. I fixed it writing a custom Serializer, but slightly different:
public class StepSerializer implements JsonSerializer<Step> {
#Override
public JsonElement serialize(Step src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject step = new JsonObject();
step.add ("start_name", context.serialize(src.start_name);
step.add ("end_name", context.serialize(src.end_name);
JsonObject data = context.serialize(src.data).getAsJsonObject();
data.entrySet().forEach(entry -> {
step.add(entry.getKey(), entry.getValue());
});
return step;
}
}
This could be improved further, the "start_name" and "end_name" props are still hardcoded. Could be removed by going over the entrySet for the root object and excluding 'data' there, leaving only the element that needs to be unwrapped hardcoded.
very simple java/json question.
I have the following test chunk of code. I can get the 1st element using the ".get()" by either index, or by the key. but I can't get any other elements by key...
The test dies, with nothing on the cmdline.. I'm assuming this is due to something not being correctly set within my env to display err results..
UPDATE::
OK.. it appears that the real issue is I don't know how to get an item, and to 1st determine what "type" it should be cast to. for the "nickname","name".. if I cast them as String.. I get the correct result..
So, how can one iterate through the key/value list of the json to determime how to correctly get each item??
The test code is:
import org.json.simple.JSONObject;
import org.json.simple.*;
//import org.json.simple.JSONValue;
public class asuH {
public static void main(String[] args){
final String[] arguments = args;
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
try{
String json_=arguments[0];
//--get the page for the 1st and 2nd urls...
//test the json input..
System.out.println("asdfsfd \n");
System.out.println(json_);
//JSONObject obj=new JSONObject();
//Object obj=JSONValue.parse(json_);
String k9="{\"nickname\":null,\"num\":100,\"contact\":{\"phone\":\"123456\",\"zip\":\"7890\"},\"balance\":1000.21,\"is_vip\":true,\"name\":\"foo\"}";
//JSONObject obj = (JSONObject)JSONValue.parse(json_);
JSONObject obj = (JSONObject)JSONValue.parse(k9);
System.out.print("11 \n");
String fa = (String)obj.get("nickname");
System.out.print(fa);
System.out.print("22 \n");
fa = (String)obj.get("contact"); //<< not working!!!
System.out.println("22 cc\n");
System.out.println(fa);
String ttt=obj.toString();
System.out.print(ttt);
System.out.println("\n s4354455 \n");
System.exit(0);
}
catch (Exception ex) {}
System.exit(0);
}
});
}
}
any thoughts/pointers are appreciated.
thanks
The value corresponding to property named contact is not a String. Use the appropriate getter method, and don't cast.
// snip...
String fa = obj.getString("nickname");
// snip...
JsonObject contact = obj.getObject("contact");
// and so on
You can get field from your object and ask for it's type:
Object field = obj.get("field");
if (field instanceof JSONArray) {
...
} else if (field instanceof JSONObject) {
...
} else if (field instanceof Number) {
...
} else {
...
}
You get the picture...