I am trying to parse a json and get hold of value inside an array -
{
"hits": {
"hits": [
{
"name": [
{
"family": "Doe",
"given": "Jon",
"middle": "Smith",
"use": "Commercial"
}
]
}
]
}
}
I realized that i have a one more array at root level so i decided to parse hits which is a list and then name which is another list. I am able to see entire name array in the response but instead i would rather want to see only given value that is mapped to fstNm
private String fstNm;
private List<Map<String,Object>> name;
public String getFstNm() { return fstNm; }
#JsonProperty("hits")
public void setFstNm(List<Map<String, Object>> hits) {
name = (List) hits.get(0).get("name");
this.fstNm= (String) name.get(0).get("given");
}
expected output-
{
"fstNm": "Jon"
}
I would appreciate any help here.
Just change the setFstNm() method as below
#JsonProperty("hits")
public void setFstNm(Map<String, List<Map<String, Object>>> hits) {
name = (List) hits.get("hits").get(0).get("name");
this.fstNm = (String) name.get(0).get("given");
}
Not sure why you have to have name be the same object type as hits
private List<Map<String,Object>> name;
I think you can accomplish getting all the values of name by declaring it as
`ArrayList<String> name;`
From there you can try to set name something like
ArrayList<String> name = (List) hits.get(0).get("name");
Then you can create a get method to get name and then access it in your setter like
ArrayList<String> name = getName();
fstNm = name.get(2);
Related
I have JSON from payfort to read the transactions, tried to parse it to POJO but always gave to me the mismatch erorr
[
[
{
"response_code": "04000",
"card_holder_name": null,
"acquirer_mid": "***",
"payment_link_id": null,
"order_description": "21882 - SAR"
}
],
{
"data_count": 70
}
]
This is my root pojo and I parse it using string
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
public class DownloadReportResponse {
private TransactionCount transactionCount;
private List<TransactionsResponse> transactions;
}
Parsing :
List<DownloadReportResponse> properties = new ObjectMapper().readValue(report, new TypeReference<>() {
});
Expanding on my comment, you could try something like this:
ObjectMapper om = new ObjectMapper();
//read the json into a generic structure
JsonNode tree = om.readTree(json);
//check if the top level element is an array
if(tree.isArray()) {
//iterate over the elements
tree.forEach(element -> {
//distinguish between nested list and object
if(element.isArray()) {
List<TransactionsResponse> responses = om.convertValue(element, new TypeReference<List<TransactionsResponse>>(){});
//do whatever needed with the list
} else if(element.isObject()) {
TransactionCount txCount = om.convertValue(element, TransactionCount .class);
//use the count as needed
}
});
}
This depends on the knowledge that you get an array which contains an inner array of TransactionsResponse elements or objects of type TransactionCount but nothing else.
However, if you have a chance to modify the response I'd suggest you shoot for something like this which is way easier to parse and understand:
{
"transactions":[ ... ],
"transactionCount": {
"data_count": 70
}
}
I have a JSON structure where some objects can have arbitrary names and i want to normalize this structure, such that the objects become anonymous, but can be identified by a "name" property.
From
{
{
"arbitrary_name": {
...
}
}
to
{
"name": "arbitrary_name",
...
}
For the first step, i want to add a name property to the "arbitrary-name" object and in the next step remove the "arbitrary-name" object and move it's properties one level up.
First, i'm querying the JSON structure (using https://github.com/json-path/JsonPath) for all paths pointing to objects, which need to be normalized. They are all positioned under an array with name "children". Then i'm iterating this paths, get the objects' values and add a name property.
My approach works fine on the top-level object, but if they are nested (child objects -> service.children[0].arbitrary_name1.children[0]), JsonPath throws an exception and i don't get it what property is missing. I printed all possible paths in this structure and the queried path (which causes the exception) is printed too.
My input looks like this:
{
"service": {
"foo": "bar",
"children": [
{
"arbitrary_name1": {
"foo": "bar",
"children": [
{
"arbitrary_name_2": {
"foo": "bar"
}
}
]
}
}
]
}
}
My code:
final File src = Files.readString(xxx); // Path to file with JSON content
final Configuration c = Configuration.defaultConfiguration().setOptions(Option.ALWAYS_RETURN_LIST, Option.AS_PATH_LIST);
final DocumentContext pathsContext = JsonPath.parse(src, c);
final DocumentContext valuesContext = JsonPath.parse(src);
final Collection<String> pathsToObjects = pathsContext.read("$..children[*]");
/* prints:
$['service']['children'][0]
$['service']['children'][0]['arbitrary_name1']['children'][0]
*/
for (String jsonPath : pathsToObjects) {
Map<String, Map> valuesOfOuterObject = valuesContext.read(jsonPath); // Exception on 2nd path
String name = valuesOfOuterObject.keySet().stream().findFirst().get();
final Map<String, Object> valuesOfInnerObject = valuesOfOuterObject.get(name);
valuesOfInnerObject.put("name", name);
valuesContext.set(jsonPath, valuesOfInnerObject);
}
The corresponding exception says:
com.jayway.jsonpath.PathNotFoundException: Missing property in path $['service']['children'][0]['arbitrary_name1']
What am i missing or is there an easier approach?
I am fetching some json from server like this
"applications": [
{
"packageName": "com.facebook.mlite",
"defaultPermissionPolicy": "PROMPT",
"delegatedScopes": [
"DELEGATED_SCOPE_UNSPECIFIED",
"CERT_INSTALL",
"MANAGED_CONFIGURATIONS",
"BLOCK_UNINSTALL",
"PERMISSION_GRANT",
"PACKAGE_ACCESS",
"ENABLE_SYSTEM_APP"
],
"permissionGrants": [
{
"permission": "tt",
"policy": "PROMPT"
}
],
"disabled": false,
"minimumVersionCode": 0
},
{
"packageName": "com.facebook.mlite",
"defaultPermissionPolicy": "PROMPT",
"delegatedScopes": [
"DELEGATED_SCOPE_UNSPECIFIED",
"CERT_INSTALL",
"MANAGED_CONFIGURATIONS",
"BLOCK_UNINSTALL",
"PERMISSION_GRANT",
"PACKAGE_ACCESS",
"ENABLE_SYSTEM_APP"
],
"permissionGrants": [
{
"permission": "tt",
}
],
}
]
Now there is a json array "application":[] in which there are several json object. Now these object are not same. Some json objects are missing like first object contains installType but second one doesn't. Now i want to add this in a list for a recyclerview if a json object is missing i want to send empty tring in contrustor of my pojo class
public Application(String defaultPermissionPolicy, List<String> delegatedScopes, List<com.ariaware.enrolldevice.PolicyPojos.PermissionGrants> permissionGrants, Boolean disabled, String installType, Integer minimumVersionCode, String packageName) {
this.defaultPermissionPolicy = defaultPermissionPolicy;
this.delegatedScopes = delegatedScopes;
PermissionGrants = permissionGrants;
this.disabled = disabled;
this.installType = installType;
this.minimumVersionCode = minimumVersionCode;
this.packageName = packageName;
}
This is constructor of my class. Now how will i loop through json array and check either if an object exists or not or if doesn't exist then send empty string. I need to check every object
You could implement another constructor which accepts a JSONObject as a parameter and create the object. Inside the constructor use optString which returns an empty string if the field doesn't exist (also accepts another parameter for the fallback value).
public Application(JSONObject jsonObject) {
this.installType = jsonObject.optString("installType");
// example of an array
JSONArray scopes = jsonObject.optJSONArray("delegatedScopes");
this.delegatedScopes = new ArrayList<>();
for (int i = 0; i < scopes.length(); i++)
this.delegatedScopes.add(scopes.optString(i));
//other initialization...
}
Finally, you retrieve each JSONObject from the applications array.
try {
JSONArray res = data.optJSONArray("applications");
Application[] items = new Application[res.length()];
for (int i = 0; i < res.length(); i++)
items[i] = new Application(res.getJSONObject(i));
} catch (JSONException e) {
e.printStackTrace();
}
I've got the URI like this:
http://localhost:8080/profile/55cbd?id=123&type=product&productCategories.id=ICTLicense&productCategories.name.firstName=Jack&productCategories.name.lastName=Sparrow&groups=a&groups=b
I need a JSON object like this:
{
"id": "123",
"type": "product",
"productCategories": {
"id": "ICTlicense",
"name": {
"firstName": "Jack",
"lastName": "Sparrow"
}
},
"groups":["a", "b"]
}
Query parameters nesting can be dynamic, like for example abc.def.ghi.jkl.mno=value1&abc.xyz=value2 will result in
{
"abc": {
"def": {
"ghi": {
"jkl": {
"mno": "value1"
}
}
},
"xyz": "value2"
}
}
I have tried this but it can not handle the nesting.
final Map<String, String> map = Splitter.on('&').trimResults().withKeyValueSeparator('=').split(request.getQuery());
How to do this in Java?
With the way that your URI string is structured it wouldn't be possible to nest it the way you'd like, here's why.
id=123 This is simple enough since id would just be an int
productCategories.id=ICTLicense This would also be simple enough since we can assume that productCategories is an object and id is a key inside of the object
However, it gets more complex when you start using arrays, for instance:
&groups=a&groups=b
How do you know that groups is an array, and not simply a key called groups with a value of a or b
Also, you store all your data to Map<String, String>,
This wouldn't support arrays as it stores objects to key-value, so you wouldn't be able to have multiple keys of groups with different values.
I'd also suggest you use a library like Gson and parse your data to a JsonObject
https://github.com/google/gson
If you were to use Gson, you could do something similar to this:
public JsonObject convertToJson(String urlString) {
//Create a JsonObject to store all our data to
JsonObject json = new JsonObject();
//Split the data part of the url by the props
String[] props = urlString.split("&");
//Loop through every prop in the url
for (String prop : props) {
//Create a list of all the props and nested props
String[] nestedProps = prop.split("=")[0].split("\\.");
//Get the actual key for our prop
String key = nestedProps[nestedProps.length - 1];
//Get the value
String value = prop.split("=")[1];
//Loop through our props array
for (String nestedProp : nestedProps) {
//If the property already exists, then skip
if (json.has(nestedProp)) continue;
//If the prop is the key, add it to the json object
if(nestedProp.equalsIgnoreCase(key)) {
json.addProperty(nestedProp, value);
continue;
}
//If the above checks fail, then create an object in the json
json.add(nestedProp, new JsonObject());
}
}
return json;
}
I have json which I am trying to parse using Jackson. JSON looks as -
coupons: {
1: {
title: "Mode von",
description: "",
type: "offer",
code: "-",
expiry: "0000-00-00",
link: ""
},
2: {
title: "Prime 1",
description: "",
type: "offer",
code: "-",
expiry: "0000-00-00",
link: "http://test.com/"
}
}
The number of coupons are not constant here and would vary from response to response.
My dilemma is to create corresponding java class which could hold such object.
I tried with Map as -
public class Coupons {
Map<String, String>coupons = new HashMap<String, String>();
public Map<String, String> getCoupons() {
return coupons;
}
}
But -
System.out.println(coupons.getCoupons().get("type"));
System.out.println(coupons.getCoupons().get("code"));
always get me null. What would be right java class for this json?
your first level of keys are the index numbers 1, 2, 3, etc.
so in order to get the type and code, you have to specificy the key.
you could do this:
var coupons = coupons.getCoupons(); //<--breakpoint to see if this is really populated.
foreach( String key in coupons.Keys ){ //<- pseudo code, iterate over keys
var obj = coupons.get(key);
var type = obj.get("type");
etc..
}
hope this helps you move on