java native JSON api for parsing - java

I've following JSON structure coming in,
{
"name": "product new",
"brand": {
"id": 1
},
"category": {
"id": 1
}
}
I can extract
jsonObject = Json.createReader(httpServletRequest.getInputStream()).readObject();
jsonObject.getString("name")
Errors:
jsonObject.getInt("brand.id")
jsonObject.getInt("category.id")
I'm using Java API for JSON.
Edit If I access
System.out.println(jsonObject.get("brand"));
// response {"id":1}
System.out.println(jsonObject.get("brand.id"));
// null
http://www.oracle.com/technetwork/articles/java/json-1973242.html

I don't think the API you're using supports nested expressions. You'll need to access the parent object, and then the specific field:
System.out.println(jsonObject.getJsonObject("brand").getInt("id"));
Or you can use an API that accepts a path expression, like Jackson:
JsonNode node = new ObjectMapper().readTree(httpServletRequest.getInputStream());
System.out.println(node.at("/brand/id").asInt());

Related

Adding changes to the JSON structure

I have the following JSON, generated in the Android application:
{
"Details": {
"ClaimDate": "08/10/2019",
"HFCode": "55555"
},
"Items": [
{
"Item": {
"ItemCode": "Y203",
"ItemPrice": "20",
"ItemQuantity": "1"
}
}
],
"Services": [
{
"Service": {
"ServiceCode": "X105",
"ServicePrice": "200",
"ServiceQuantity": "1"
}
}
]
}
On the server side, I need this structure
{
"details": {
"ClaimDate": "08/10/2019",
"HFCode": "55555"
},
"items": [
{
"itemCode": "Y200",
"itemPrice": 0,
"itemQuantity": 0
}
],
"services": [
{
"serviceCode": "X100",
"servicePrice": 0,
"serviceQuantity": 0
}
]
}
Is there a way to customize this on the Android application side?
I try to do it manually, but I can't get a satisfactory result
You can use a transformer function which will take the first json/object as input and returns the second json/object as output. Unfortunately, since your keys and data types are different, standard libraries will not able to do this. If you want to use Jackson or Gson, you will have to play with Custom (De) Serializers.
If you are using Jackson (One of the most popular JSON libraries) and you just want to transform the given JSON string into another one, then you can achieve this by following way:
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(jsonStr);
ObjectNode rootNew = mapper.createObjectNode();
rootNew.put("details", root.get("Details"));
JsonNode itemNode = root.get("Items").get(0).get("Item");
ObjectNode itemsNodeNew = mapper.createObjectNode();
itemsNodeNew.put("itemCode", itemNode.get("ItemCode"));
itemsNodeNew.put("itemPrice", itemNode.get("ItemPrice"));
itemsNodeNew.put("itemQuantity", itemNode.get("ItemQuantity"));
rootNew.put("items", mapper.createArrayNode().add(itemsNodeNew));
JsonNode serviceNode = root.get("Services").get(0).get("Service");
ObjectNode serviceNodeNew = mapper.createObjectNode();
serviceNodeNew.put("serviceCode", serviceNode.get("ServiceCode"));
serviceNodeNew.put("servicePrice", serviceNode.get("ServicePrice"));
serviceNodeNew.put("serviceQuantity", serviceNode.get("ServiceQuantity"));
rootNew.put("services", mapper.createArrayNode().add(serviceNodeNew));
System.out.println(rootNew.toString());
But if you want to convert the JSON string to POJO for further manipulation, you can directly deserialize and serialize it.

Parse array in JSON using JsonPath in Java

I am using jayway JsonPath library to parse the JSON using the path given. I am able to get the string value if I give the correct path. But I want to get the list of maps when I give the path if its an array. For example, I have a JSON like below:
{
"employees": {
"company": "Google",
"people": [{
"name": "John",
"age": 25,
"location": "zurich"
},
{
"name": "Peter",
"age": 27,
"location": "Lucerene"
}]
}
}
Below is the code I am using to parse the json.
if I give the path $.employees.people, I am getting the String, But I need to List of Maps. Below is the code I am using to Parse Json using jsonpath.
DocumentContext documentContext = JsonPath.parse(jsonStr);
JsonPath jsonPath = JsonPath.compile("$.employees.people");
List<Maps<String,String>> jsonList = documentContext.read(jsonPath) //But this is returning String
Anyone suggest proper approach to get what I expected.
try using,
DocumentContext documentContext = JsonPath.parse(jsonStr);
JsonPath jsonPath = JsonPath.compile("$.employees.people[?]");
List<Maps<String,String>> jsonList = documentContext.read(jsonPath);
if you need more details. readmore...

How to convert value with unicode in Json request into simple characters?

Sometime client send Json-RPC request with Json value as unicorde symboles.
Example:
{ "jsonrpc": "2.0", "method": "add", "params": { "fields": [ { "id": 1, "val": "\u0414\u0435\u043d\u0438\u0441" }, { "id": 2, "val": "\u041c\u043e\u044f" } ] }, "id": "564b0f7d-868a-4ff0-9703-17e4f768699d" }
How do I processing Json-RPC request:
My server get the request like byte[];
Convert it to io.vertx.core.json.JsonObject;
Make some manipulations;
Save to DB;
And I found in DB records like:
"val": "\u0414\u0435\u043d\u0438\u0441"
And the worst in this story. If client try to search this data, he'll get:
"val": "\\u0414\\u0435\\u043d\\u0438\\u0441"
So I think, that I need to convert request data before deserialization to JsonObject.
I tried and it didn't help:
String json = new String(incomingJsonBytes, StandardCharsets.UTF_8);
return json.getBytes(StandardCharsets.UTF_8);
Also I tried to use StandardCharsets.US_ASCII.
Note: Variant with StringEscapeUtils.unescapeJava() I can not, because it unescape all necessary and unnecessary '\' symbols.
If anyone know how to solve it? Or library that already makes it?
Thank a lot.
io.vertx.core.json.JsonObject depends on Jackson ObjectMapper to perform the actual JSON deserialization (e.g. io.vertx.core.json.Json has a ObjectMapper field). By default Jackson will convert \u0414\u0435\u043d\u0438\u0441 into Денис. You can verify this with a simple code snippet:
String json = "{ \"jsonrpc\": \"2.0\", \"method\": \"add\", \"params\": { \"fields\": [ { \"id\": 1, \"val\": \"\\u0414\\u0435\\u043d\\u0438\\u0441\" }, { \"id\": 2, \"val\": \"\\u041c\\u043e\\u044f\" } ] }, \"id\": \"564b0f7d-868a-4ff0-9703-17e4f768699d\" }";
ObjectMapper mapper = new ObjectMapper();
Map map = mapper.readValue(json, Map.class);
System.out.println(map); // {jsonrpc=2.0, method=add, params={fields=[{id=1, val=Денис}, {id=2, val=Моя}]}, id=564b0f7d-868a-4ff0-9703-17e4f768699d}
Most likely the client is sending something else because your example value is deserialized correctly. Perhaps it's doubly escaped \\u0414\\u0435\\u043d\\u0438\\u0441 value which Jackson will convert to \u0414\u0435\u043d\u0438\u0441 removing one layer of escaping?
There is no magic solution for this. Either write your own Jackson deserialization configuration or make the client stop sending garbage.

Update nested field in an index of ElasticSearch with Java API

I am using Java API for CRUD operation on elasticsearch.
I have an typewith a nested field and I want to update this field.
Here is my mapping for the type:
"enduser": {
"properties": {
"location": {
"type": "nested",
"properties":{
"point":{"type":"geo_point"}
}
}
}
}
Of course my enduser type will have other parameters.
Now I want to add this document in my nested field:
"location":{
"name": "London",
"point": "44.5, 5.2"
}
I was searching in documentation on how to update nested document but I couldn't find anything. For example I have in a string the previous JSON obect (let's call this string json). I tried the following code but seems to not working:
params.put("location", json);
client.prepareUpdate(index, ElasticSearchConstants.TYPE_END_USER,id).setScript("ctx._source.location = location").setScriptParams(params).execute().actionGet();
I have got a parsing error from elasticsearch. Anyone knows what I am doing wrong ?
You don't need the script, just update it.
UpdateRequestBuilder br = client.prepareUpdate("index", "enduser", "1");
br.setDoc("{\"location\":{ \"name\": \"london\", \"point\": \"44.5,5.2\" }}".getBytes());
br.execute();
I tried to recreate your situation and i solved it by using an other way the .setScript method.
Your updating request now would looks like :
client.prepareUpdate(index, ElasticSearchConstants.TYPE_END_USER,id).setScript("ctx._source.location =" + json).execute().actionGet()
Hope it will help you.
I am not sure which ES version you were using, but the below solution worked perfectly for me on 2.2.0. I had to store information about named entities for news articles. I guess if you wish to have multiple locations in your case, it would also suit you.
This is the nested object I wanted to update:
"entities" : [
{
"disambiguated" : {
"entitySubTypes" : [],
"disambiguatedName" : "NameX"
},
"frequency" : 1,
"entityType" : "Organization",
"quotations" : ["...", "..."],
"name" : "entityX"
},
{
"disambiguated" : {
"entitySubType" : ["a", "b" ],
"disambiguatedName" : "NameQ"
},
"frequency" : 5,
"entityType" : "secondTypeTest",
"quotations" : [ "...", "..."],
"name" : "entityY"
}
],
and this is the code:
UpdateRequest updateRequest = new UpdateRequest();
updateRequest.index(indexName);
updateRequest.type(mappingName);
updateRequest.id(url); // docID is a url
XContentBuilder jb = XContentFactory.jsonBuilder();
jb.startObject(); // article
jb.startArray("entities"); // multiple entities
for ( /*each namedEntity*/) {
jb.startObject() // entity
.field("name", name)
.field("frequency",n)
.field("entityType", entityType)
.startObject("disambiguated") // disambiguation
.field("disambiguatedName", disambiguatedNameStr)
.field("entitySubTypes", entitySubTypeArray) // multi value field
.endObject() // disambiguation
.field("quotations", quotationsArray) // multi value field
.endObject(); // entity
}
jb.endArray(); // array of nested objects
b.endObject(); // article
updateRequest.doc(jb);
Blblblblblblbl's answer couldn't work for me atm, because scripts are not enabled in our server. I didn't try Bask's answer yet - Alcanzar's gave me a hard time, because I supposedly couldn't formulate the json string correctly that setDoc receives. I was constantly getting errors that either I am using objects instead of fields or vice versa. I also tried wrapping the json string with doc{} as indicated here, but I didn't manage to make it work. As you mentioned it is difficult to understand how to formulate a curl statement at ES's java API.
A simple way to update the arraylist and object value using Java API.
UpdateResponse update = client.prepareUpdate("indexname","type",""+id)
.addScriptParam("param1", arrayvalue)
.addScriptParam("param2", objectvalue)
.setScript("ctx._source.field1=param1;ctx._source.field2=param2").execute()
.actionGet();
arrayvalue-[
{
"text": "stackoverflow",
"datetime": "2010-07-27T05:41:52.763Z",
"obj1": {
"id": 1,
"email": "sa#gmail.com",
"name": "bass"
},
"id": 1,
}
object value -
"obj1": {
"id": 1,
"email": "sa#gmail.com",
"name": "bass"
}

Java - How to get object value in JSON array?

i have a JSON like example below and i'm trying to get some values, for example value of.
results.shipper.id
{
"results": [
{
"updated": false,
"notification": false,
"some_data": {
"id": 15989,
"pieces": 0,
},
"shipper": {
"updated": false,
"notification": false,
"id": 1587,
"parent": {
"updated": false
},
I'm trying to get value by this way:
String test = shipmentData.getJSONObject("shipper").getString("id");
But it always throws a exception. I think, that exception is caused because of the i am not accessing to the values via "results" array.
How can i easy access to the value what i need.
I tried find some helpers (Gson, fast-json, etc..) but it seems to be a quite complicated for using (i would like to work with JSON tree for direct access to values "on-the-fly" or access to values like to a object, it means.. Object.InnerObject.value ).
So question is how can i do it right?
Thanks for any advice.
JSON needs to be traversed in order to access id:
JSONArray results = shipmentData.getJSONArray("results");
JSONObject first = results.getJSONObject(0);
JSONObject shipper = first.getJSONObject("shipper");
Integer id = shipper.getInt("id");
Parse int to string:
String id = String.valueOf(shipper.getInt("id"));

Categories