I have a JSON that looks like this
[
{
"itemLabel":"Social Media",
"itemValue":90
},
{
"itemLabel":"Blogs",
"itemValue":30
},
{
"itemLabel":"Text Messaging",
"itemValue":60
},
{
"itemLabel":"Email",
"itemValue":90
},
]
I want to place all of those objects into an array to manipulate it easier in one of my code. Thus I want to do something like
[
{
"data": [
{
"itemLabel": "Social Media",
"itemValue": 90
},
{
"itemLabel": "Blogs",
"itemValue": 30
},
{
"itemLabel": "Text Messaging",
"itemValue": 60
},
{
"itemLabel": "Email",
"itemValue": 90
}
]
}
]
How do I go about to add in that data array element using Jackson? I have done mostly read using Jackson but have not done too many writes. Any help would be appreciated.
I'm not completely sure what are you intending and there is probably a more elegant solution to this (using POJOs rather than Collections and Jacksons JSON representation), but I guess this example will clear it out to you. But if you have some more complicated processing you might want to write custom (de)serializers or something like that. Written using Jackson 2.3.3
ObjectMapper mapper = new ObjectMapper();
JsonNode parsedJson = mapper.readTree(json); //parse the String or do what you already are doing to deserialize the JSON
ArrayNode outerArray = mapper.createArrayNode(); //your outer array
ObjectNode outerObject = mapper.createObjectNode(); //the object with the "data" array
outerObject.putPOJO("data",parsedJson);
outerArray.add(outerObject);
System.out.println(outerArray.toString()); //just to confirm everything is working
Related
I have a rather large JSON object (this is a subset) I'm trying to parse:
{
"items": [
{
"Name": "Wallet",
"tags": [
"wallet",
"cardholder"
],
"features": {
"material": {
"location": "in-house"
},
"stitching": {
"location": "in-house"
}
},
"color": null,
"store": {
"address": "123 Main Street"
}
}
],
"jItem": 0
}
I have Java POJO's for all JSON objects except for the features object, which contains objects where the key is a dynamic value. My current only-POJO's code does this:
...
itemsJson = doGet(url);
ObjectMapper objMapper = new ObjectMapper();
Items items = objMapper.readValue(itemsJson, Items.class);
...
This gives me a hierarchy of Java POJO's representing my data. The one hitch is features. How can I parse the features data, with the keys as values, within this larger object? I've looked at other SO posts:
Deserialize JSON in Jackson where key is a value
Deserializing jackson dynamic key value
Jackson JSON key as value in Java
but none of these solutions have 1. an object where the key is the value and 2. an object where the key is the value is contained within an object. I do have parsing just the features working using this "just features JSON":
{
"features": {
"material": {
"location": "in-house"
},
"stitching": {
"location": "in-house"
}
}
}
with this code:
...
JsonNode jsonNodeRecord = objectMapper.readTree(App.class.getResourceAsStream("/data.json"));
List<JsonNode> recordNodes = jsonNodeRecord.findValues("features");
...
which gives me JsonNode's. This isn't ideal because I don't have my features data in a POJO.
The Question:
It's not clear to me how to integrate parsing the JSON using POJO's for everything except for features, with either the JsonNode code above or a custom deserializer as in the #1 SO link above.
I need to transform a Json into another Json according to the parameter coming as part of Rest request. This service is developed in Java. I know, Jackson API can be used easily and there are some libraries also available. But my requirement is to delivery response with new Json faster as much as possible.
If I can be given few option I can measure the performance of those.
Let's assume I have this Json in data storage:
{
"bookId": "23228232-2dfa232",
"bookName": "Json Transformation",
"bookPublisher": "Tech Publication",
"bookRating": [
{
"source": "All book rank",
"maxRating": "10",
"rating": "3.4"
},
{
"source": "Tech Books",
"maxRating": "5",
"rating": "2"
},
{
"source": "Popular",
"maxRating": "3",
"rating": "1"
}
],
"bookAuthor": [
{
"name": "Jone",
"specialities": [
"Json",
"Javascript",
"Typescript",
"nodejs"
]
},
{
"name": "Mike",
"specialities": [
"Java",
"Spring",
"ElasticSearch"
]
}
]
}
Below rest calls should have respective results from this Json:
Get only authors
/authorName/23228232-2dfa232
{
authorName: [
"Jone",
"Mike"
]
}
Get Average Rating
/popularity/23228232-2dfa232
{
rating: "1.78"
}
So, the question is how to do this kind of transformation efficiently with any available library? As I mentioned above, I can simply use any Json library in Java and transform the Json, but I am not sure, if that will be efficient.
You can try little json java library for searching json data.
JsonValue json = JsonParser.parse(stringvariablewithjsondata);
List<JsonValue> authors = json.findAll(SPM.path("bookAuthor", "name")));
List<String> ratings = json.findAllLiterals(SPM.path("bookRating", "rating")));
and compute result like
JsonArray values = JsonFactory.array();
for(JsonValue value : authors) values.add(value);
JsonObject result = JsonFactory.object().add("authorName", values);
return result.toCompactString()
You can use JSON-Java --> https://www.baeldung.com/java-org-json
Or the Google JSON, aka GSON and a few others as listed here --> https://javarevisited.blogspot.com/2016/09/top-5-json-library-in-java-JEE.html
To see popularity and use statistics, which might help you chose which ones to test first: https://www.baeldung.com/java-json
You can use GSON as it easily maps JSON with POJO classes (Especially nested ones)
For a quick reference for performance comparison,
I have the following JSON response from shipcloud.io:
[
{
"name": "dhl",
"display_name": "Deutsche Post DHL",
"services": [
"standard",
"returns",
"one_day",
"one_day_early"
],
"package_types": [
"parcel",
"bulk"
]
},
{
"name": "dpag",
"display_name": "Deutsche Post",
"services": [
"standard"
],
"package_types": [
"letter",
"parcel_letter",
"books"
]
},
{
"name": "dpd",
"display_name": "DPD - Dynamic Parcel Distribution",
"services": [
"standard",
"returns",
"one_day",
"one_day_early"
],
"package_types": [
"parcel",
"parcel_letter"
]
}
]
How can I deserialize this JSON array with Jackson? Usually I use a simple POJO and define
the property name of the list / array (#JsonProperty("blub") e.g.). Problem is, there is no property name used here...
I tried it using an empty property name, but it didn't work.
I'm just getting this error message:
Can not deserialize instance of Response.CarriersResponse out of
START_ARRAY token
If you want to use jackson, this is the solution that works for me:
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, false);
You are deserializing multiple objects of the type, so you need to do it as a list, like this
// somewhere in an example TypeReferences class
public static final TypeReference<List<Response.CarriersResponse>> CARRIER_RESPONSES = new TypeReference<List<Response.CarriersResponse>>() {
};
// elsewhere where you're calling the mapper
List<Response.CarriersResponse> responses = mapper.readValue(text, TypeReferences.CARRIER_RESPONSES);
You could instantiate it in-place, but that's a design decision between performance vs total memory consumption.
Try to deserialize to Response.CarriersResponse[] class.
Response.CarriersResponse[] responses = mapper.readValue(text, Response.CarriersResponse[].class);
I have a nested json structure:
"info": [
{
"name":"Alice",
"phone": [{
"home": "1234567890",
"mobile": "0001112223"
}]
},
{
"name":"Bob",
"phone": [{
"home": "3456789012",
"mobile": "4445556677"
}]
}
]
I'm using jackson.
I only want to extract the information about "Bob" and read it into a tree. I do not want to read the whole structure into the tree (I know how to do that) and then extract the information on Bob. I'd like to use the streaming API (JsonParser) to first extract all the information with "Bob" and then make that into a jsontree.
I thought I'd read it into a byte array and then convert that into a tree like so:
JsonToken token = null;
byte[] data;
int i = 0;
while( jParser.nextToken()!=JsonToken.END_ARRAY) {
data[i] = jParser.getByteValue();
i ++;
}
JsonNode node = null;
ObjectMapper objectMapper = new ObjectMapper();
try {
node = objectMapper.readValue(jParser, JsonNode.class);
}
catch(Exception e) {
e.printStackTrace();
}
However, this is not returning the result I want. There's a jsonParse exception so I think this isn't the way to go.
Use of JSON pointer should work here. Functionally, reading it as JsonNode, extracing could look something like:
JsonNode stuff = mapper.readTree(source).at("/info/1");
but you can also get it without reading it all in with
JsonNode stuff = mapper.reader().at("/info/1").readTree(source);
or whatever path expression you want. Note, however, that unlike with XPath (et al) you can not use filtering of sub-trees to check (for example) that "name" property of Object to read matches "Bob".
So, I am accessing a third-party API and it's giving me this JSON object, but I'm having a whale of a time trying to find an elegant way to parse the resources sub-object using Jackson.
I'm assuming I have to write a custom deserializer, though I'm wondering if there's another way...
{
"somekey": "somevalue",
"resources": [
"list",
[
{
"#type": "com.yada.Yada",
"resource": {
"#type": "ServiceObjectReference",
"id": "emp1234",
"displayName": "Bob Smith"
},
"type": "TYPE_PERSON",
"resourceType": 200
},
{
"#type": "com.yada.Yada",
"resource": {
"#type": "ServiceObjectReference",
"id": "emp1235",
"displayName": "Sue Smith"
},
"type": "TYPE_PERSON",
"resourceType": 200
}
]
]
}
Since the value of resources is an array with different object type, probably you don't want to use POJO for the mapping. Not sure about your implementation of custom deserializer, but you might want to use ObjectMapper#readTree method, than read the node value based on its type
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(your_json_input);
JsnoNode resourcesNode = rootNode.path("resources");
for (JsonNode resourceNode : resourcesNode ) {
if (resourceNode.isObject()) {
// the node is an object, you could do POJO mapping now or keep using path() method to go deeper
} else {
// simply get the String value
String list = resourceNode.getTextValue();
}
}
It looks like the producer of the json uses polymorphic type handling.
We can all agree that this is not something to use in a public api.
However, you could try to annotate your classes so that jackson can make use of this though.
The annotation #JsonTypeInfo would be your starting point
It would look something like this:
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, visible = true)
#JsonSubTypes({
#JsonSubTypes.Type(value = MyYada.class, name="com.yada.Yada")
})
public class MyYada
I did some more research and it looks like this is a "2-element JSON array". It can be parsed using JsonTypeInfo.As(WRAPPER_ARRAY)
http://jackson.codehaus.org/1.9.9/javadoc/org/codehaus/jackson/annotate/JsonTypeInfo.As.html#WRAPPER_ARRAY