evaluate JSON expression in child object - java

I am trying to evaluate json expression using Josson, but it gives invalid function error
String json ="{\"data\":{\"B\":\"calc(348+(96*$.SelectedPump.stg*$.ModelMaster.count))\"},\"SelectedPump\":{\"stg\":10,\"ab\":200},\"ModelMaster\":{\"count\":20}}";
Josson josson = Josson.fromJsonString(json.toString());
System.out.println(josson.getNode("data.eval(B)"));
Stacktrace:
Exception in thread "main" java.lang.IllegalArgumentException: Invalid function call eval() : Invalid function call calc() : Calc syntax error.
at com.octomix.josson.FuncDispatcher.apply(FuncDispatcher.java:84)
at com.octomix.josson.JossonCore.getPathBySteps(JossonCore.java:328)
at com.octomix.josson.JossonCore.getPathBySteps(JossonCore.java:352)
at com.octomix.josson.JossonCore.getPathBySteps(JossonCore.java:249)
at com.octomix.josson.JossonCore.getPathByExpression(JossonCore.java:211)
at com.octomix.josson.JossonCore.getNodeByExpression(JossonCore.java:147)
at com.octomix.josson.JossonCore.getNodeByExpression(JossonCore.java:142)
at com.octomix.josson.Josson.getNode(Josson.java:279)

The variables inside the math equation cannot contains special characters. You need to use substitution. The variable name can whatever you want without special characters and .. So, the statement of B become...
calc(348+(96*A*B), A:SelectedPump.stg, B:ModelMaster.count)
The function eval() in query data.eval(B) works on node data. So the original evaluation statement needs $. to re-start from the root to get the value. For this revised version eval(data.B), eval() works on the root node with parameter data.B. And therefore, $. is not necessary.
String json =
"{\n" +
" \"data\": {\n" +
" \"B\": \"calc(348+(96*A*B), A:SelectedPump.stg, B:ModelMaster.count)\"\n" +
" },\n" +
" \"SelectedPump\": {\n" +
" \"stg\": 10,\n" +
" \"ab\": 200\n" +
" },\n" +
" \"ModelMaster\": {\n" +
" \"count\": 20\n" +
" }\n" +
"}";
Josson josson = Josson.fromJsonString(json);
System.out.println(josson.getNode("eval(data.B)"));
// Output: 19548.0

Answer by Raymond Choi would be the best solution.
Alright, I have found a possible solution to this using Jossons template engine.
String json = "{\"data\":{\"B\":\"calc(348+(96*{{SelectedPump->stg}}*{{ModelMaster->count}}))\"},\"SelectedPump\":{\"stg\":10,\"ab\":200},\"ModelMaster\":{\"count\":20}}";
Jossons jossons = Jossons.fromJsonString(json);
String output = jossons.fillInPlaceholder("{\"s\":\"{{data->B}}\"}");
output = jossons.fillInPlaceholder(output);
System.out.println(output);
System.out.println(Josson.fromJsonString(output).getNode("$.eval(s)"));
It is necessary to adjust the JSON string to use placeholder to access the values from a different/nested node. We also have to create a new JSON string with a template that is filled in. Also also, it does sadly not recursively replace the placeholder, making it necessary to call jossons.fillInPlaceholder() two times. The first time it fetches the calculated formula and the second time it replaces the placeholder that are now present in the formula.
The output is:
output -> {"s":"calc(348+(96*10*20))"}
Josson.fromJsonString(output).getNode("$.eval(s)") -> 19548.0
The proposed code in the question fails, because Josson is not able to resolve nested/different node values. Pretty much as soon as we have a . present in the calc() formula, the syntax check fails. It is however possible to access nodes at the same level. So a JSON like this:
{
"data" : {
"B" : "calc(348+(96*SelectedPumpStg*ModelMasterCount))",
"SelectedPumpStg" : 10,
"ModelMasterCount" : 20
}
}
can be evaluated by:
String json = "{\"data\":{\"B\":\"calc(348+(96*SelectedPumpStg*ModelMasterCount))\",\"SelectedPumpStg\":10,\"ModelMasterCount\":20}}";
Josson josson = Josson.fromJsonString(json.toString());
System.out.println(josson.getNode("data.eval(B)"));
resulting in the same: 19548.0.
Either way, the input JSON has to be adjusted to work with Josson

Related

Accesing only key names of json using jsonPath

I have a simple question, say I have the following json
{
"ALPHA":[
....
],
"BETA":[
....
],
"GAMMA":[
.....
]
}
how do I access the subroot elements, I mean just the names: "ALPHA","BETA","GAMMA" using jsonPath? Be aware that I mean their names not their array!!!
I tried jsonPath("$[*]", ...) but it doesn't work, any sugesstions?
You may consider another library Josson. Just one function keys() can do the job.
https://github.com/octomix/josson
Josson josson = Josson.fromJsonString(
"{" +
" \"ALPHA\":[" +
" 1,2,3,4" +
" ]," +
" \"BETA\":[" +
" 5,6,7" +
" ]," +
" \"GAMMA\":[" +
" 8,9" +
" ]" +
"}");
JsonNode node = josson.getNode("keys()");
System.out.println(node.toPrettyString());
Output
[ "ALPHA", "BETA", "GAMMA" ]
Thanks a lot #Raymond Choi, it should also work.
But based on your answer, that I should use the function keys(), I search a lit bit more and I found that jsonPath indeed has his own function.
So the solution to my question is simple:
jsonPath("$.keys())

Insert Kotlins ${ } expression while splitting String() in order to add dynamic data after the split

Here is an example of a String:
val message = "Customer name is $name saved on $date"
I needed to find every instance of $variable within the string message and replace it with querySnapShot.get(variable) and that has been answered here Previous Answer. querySnapShot here just contains data from within Firestore listener.
Here is the working Kotlin code:
val message = "Customer name is $name saved on $date"
val arr = message.split(" ").toTypedArray()
for (i in 0 until arr.size) {
val s = arr[i]
if (s.contains("$")) {
arr[i] = "+ querySnapshot.get(" + "\"" + s.substring(1) + "\"" + ")"
}
}
Log.d("Mate", java.lang.String.join(" ", *arr))
which prints:
customer name is querySnapShot.get("name") saved on querySnapshot.get("data)
literally as it is.
QUESTION:
How can I add Kotlin's expression ${} correctly while splitting and joining in order for it to treat querySnapshot.get("variable") as an expression that captures and returns dynamic data after joining? And not just a mere String.
Write
arr[i] = querySnapshot.get(s.substring(1))
The solution isn't to try to use Kotlin string templating, it's to stop putting your own code in strings when you want to run it instead!

Gson 'fromJson' issue

I am trying to bind JSON to Java POJO class using com.google.gson.Gson
like this :
MyClass data = gson.fromJson(jsonString, MyClass.class);
When I am using below mentioned it's working fine
{
"data": "{\"key1\":{\"key11\":\"192.192.1.192\",\"key12\":\"WEB\"}}"
}
However, when below-mentioned data is used, I am getting MalformedJsonException
{
"data": "{"key1":{"key11":"192.168.1.158","key12":"WEB"}}"
}
Log :
com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException:
Unterminated object at line 1 column 354 path
You can not use " within a String to quote your JSON keys and values. You either have to escape them (like you did in your first example) or you have use single quotes '.
You are effectively trying to do String concatenation without using +.
This looks for the compiler like a list of Strings with variables in between:
"{"key1":{"key11":"192.168.1.158","key12":"WEB"}}"
The compiler would expect something like this:
"{" + key1 + ":{" + key11 + ":" + 192.168.1.158 + "," + key12 + ":" + WEB + "}}";
If you look at the String this way you immediately see the problem. That's why you should either escape the quotes or use single quotes:
"{\"key1\":{\"key11\":\"192.168.1.158\",\"key12\":\"WEB\"}}"
"{'key1':{'key11':'192.168.1.158','key12':'WEB'}}"

Error with Jongo parsing JSON

I'm using a combination of Java Play Framework, MongoDB and Jongo as my go between for a basic web CRUD app. I keep receiving a JSON parse exception even though my string doesn't contain any illegal characters. It's actually failing on closing curly bracket at the end of the statement. Below is my error and code. The query string is just a string builder, searching if an object is empty or has a value, if it has a value it's appended to a string.
Jongo method:
public static Iterable<OneDomain> findWithQueryString(String queryString){
return domains().find("{#}", queryString).as(OneDomain.class);
}
Controller Methods:
String builder example:
if(queryStringBuilder.toString().equalsIgnoreCase("")){
queryStringBuilder.append("date: {$gte : " + searchObj.dateFrom + ", $lt: " + searchObj.dateTo + "}");
}else{
queryStringBuilder.append(" , ");
queryStringBuilder.append("date: {$gte : " + searchObj.dateFrom + ", $lt: " + searchObj.dateTo + "}");
}
String queryString = queryStringBuilder.toString();
Iterable<OneDomain> filteredIterable = OneDomain.findWithQueryString(queryString);
Gives me this error:
Caused by: com.mongodb.util.JSONParseException:
{"source : Online Lists , blacklist : true , vetted : true , is : false , isNot : true"}
^
with the error on the "}" ending it.
In addition to that, if I try to escape the characters by putting in a \" so it becomes \"date\" it will parse and error out like so:
Caused by: com.mongodb.util.JSONParseException:
{"\"source\" : \"Online Lists\" , \"blacklist\" : true , \"vetted\" : true , \"is\" : false , \"isNot\" : true"}
You're building JSON by hand, and doing it wrong. You need to learn the basic JSON syntax requirements
A basic JSON-encoded object is
{"key1":"value1","key2":"value with \" escaped internal quote"}
Note all of the quotes. Your json string is a single very long object key with no associated value, which is not permitted. All keys must have values.

Adding a " to a string in code

I'm writing some code for web services for my Android app which uses JSON. The url should look like this
url = url + "?maddr=" + mailAddr + "&pwd=FB&lect=" + """ + lectName + """ + "&fb=Test";
This is because the Lectname may be two or more words. However the compiler wont accept """, is there a character I can precede the " with to get the compiler to accept it into my string?
Try " \" ". You have to escape the "
http://en.wikipedia.org/wiki/Escape_character
You need this in (nearly) every programming language.

Categories

Resources