I struggled a while trying to find way to deserialize this following structure into java object using fasterxml.jackson.
Obviously the "NewYork" and "Boston" are the keys, not an schema I must unmarshall into map
Map<String, Object> jsonMap = mapper.readValue(jsonString,
new TypeReference<Map<String,Object>>(){});
But the jsonMap return is LinkedHashMap, with key is "NewYork", value is another LinkedHashMap. In the second inner map, the key is "schedules", and value are list of LinkedHashMap. The third inner map, the key, value are
"date": "2020-10-31",
"flightNo": "UA110",
"depart": "17:30PM"
What I want is java model like this
public class FlightInfo {
Map<String, List<Schedule>> info;
}
I did some search, thinking about JsonNode, Json node must know the property name, in my case, NewYork and Boston are not determined.
I could not find way to do that.
{
"NewYork": {
"schedules": [
{
"date": "2020-10-31",
"flightNo": "UA110",
"depart": "17:30PM"
},
{
"date": "2020-11-01",
"flightNo": "UA230",
"depart": "18:30PM"
}
]
},
"Boston": {
"schedules": [
{
"date": "2020-11-01",
"flightNo": "AM110",
"depart": "08:00AM"
},
{
"date": "2020-11-01",
"flightNo": "CA230",
"depart": "10:30AM"
}
]
}
}
Thanks
The JSON string is not adapt to your expected data model Map<String,Object> or Map<String, List<Schedule>>. Actually there are two level mappings, NewYork -> schedules -> List Of Schedule
So we should use the below TypeReference with two level Map to do deserialize
mapper.readValue(jsonString, new TypeReference<Map<String, Map<String, List<Schedule>>>>(){});
Certainly, if you persist to use one level mapping, you could modify the data, like the following. And thus we could use a simple version TypeReference<Map<String, List<Schedule>>>
{
"NewYork": [
{
"date": "2020-10-31",
"flightNo": "UA110",
"depart": "17:30PM"
},
{
"date": "2020-11-01",
"flightNo": "UA230",
"depart": "18:30PM"
}
],
"Boston": [
{
"date": "2020-11-01",
"flightNo": "AM110",
"depart": "08:00AM"
},
{
"date": "2020-11-01",
"flightNo": "CA230",
"depart": "10:30AM"
}
]
}
Related
Problem:Sometimes an Access Request Target is a Single Target, Sometimes it is an array
Question: How can I make Jackson deserialize to either a Single Target or an Array depending on what is found?
Single Target JSON
"access_request": {
"targets": {
"target": {
"#type": "ANY",
"id": 1189118
}
}
}
Array of Target JSON
"access_request": {
"targets": {
"target": [
{
"#type": "Object",
"id": 1189167,
"object_name": "OUTSIDE",
"object_type": "acl",
"object_details": "2.2.2.2",
"management_id": 29,
"management_name": "ace2"
},
{
"#type": "Object",
"id": 1189168,
"object_name": "ONRAMP",
"object_type": "acl",
"object_details": "1.1.1.1",
"management_id": 29,
"management_name": "ace1"
}
]
}
}
'Target' POJO:
#JsonPropertyOrder({
"target"
})
#Generated("jsonschema2pojo")
public class Targets implements Serializable
{
#JsonProperty("target")
private Target target = new Target();//How can I make Jackson deserialize to either a Single Target or an Array<Target> depending on what is found?
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
.
.//Getters, Setters
.
}
Use a single field of type List, and activate the feature ACCEPT_SINGLE_VALUE_AS_ARRAY
YourTargetClass result = mapper.reader(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
.forType(YourTargetClass.class)
.readValue(json);
I'm using a Map<String, Map> resultMap having values like this:
[
{main={group={street={cnt=Burundi, zip=123}, code=asd, subtype={OrgType=1,2}}}},
{main={info={text=bbb}}},
{main={group={subId=5, attrib={attribId=1,2}}}}
]
I have to create a JSON out of those Maps that should look like this:
{ "main": [
{
"group": {
"street": {
"cnt": "Burundi",
"zip": "123"
},
"code": "asd",
"subtype": {
"OrgType": "1,2"
},
"subId": "5",
"attribId": "1,2"
},
"info": {
"text": "bbb"
}
}
]
}
Any idea how could I merge those Maps doing a GSON.toJson(resultMap); to obtain this JSON ?
I tried to merge the Map
public String produceJsonFromMap(Map<String, Map> initialMap) {
Map<String, Object> resultMap = new HashMap<>();
for(Map map: initialMap.values()) {
resultMap.putAll(map);
}
return GSON.toJson(resultMap);
}
But this overwrites my previous maps and I don't know how can I obtain the desired merged map...
I am consuming an external web service and receiving a JSON response. In this response, there is an object "entities" containing multiple arrays in it, with a name before each array.
I want to add the name before the array in the array object itself.
For example this is the original response:
{
"entities": {
"entity": [
{
"confidence": 1,
"value": "user",
"type": "value"
},
{
"confidence": 1,
"value": "insurance form",
"type": "value"
}
],
"ui_page_step": [
{
"confidence": 1,
"value": "step 1",
"type": "value"
}
],
"userrole_ano": [
{
"confidence": 0.96535832252792,
"value": "anonymous user"
}
]
}
}
I need to convert it to:
{
"entities": {
"entity": [
{
"name": "entity",
"confidence": 1,
"value": "user",
"type": "value"
},
{
"name": "entity",
"confidence": 1,
"value": "insurance form",
"type": "value"
}
],
"ui_page_step": [
{
"name": "ui_page_step",
"confidence": 1,
"value": "step 1",
"type": "value"
}
],
"userrole_ano": [
{
"name": "userrole_ano",
"confidence": 0.96535832252792,
"value": "anonymous user"
}
]
}
}
How can I convert the original response to the desired one in Java?
Here is a (one of several possible) solutions:
It uses Jackson library to parse the Json into a java Map that is (relatively) easier to navigate and modify than JSONObject.
the method putCollectionNamesInsideEntries() assumes one root "entities" entry that has several collections as values. it iterates over all of them, adding "name" entry with name of collection.
the map is serialized back to Json (and sent to System.out)
import java.io.*;
import java.nio.file.*;
import java.util.*;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonTest
{
public static void main(String[] args) {
try (InputStream is = Files.newInputStream(Paths.get("C:/temp/test.json"))) {
ObjectMapper mapper = new ObjectMapper();
// deserialize json into map
Map<String, Object> map = (Map<String, Object>)mapper.readValue(is, Map.class);
putCollectionNamesInsideEntries(map);
// serialize map into json
mapper.writeValue(System.out, map);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void putCollectionNamesInsideEntries(Map<String, Object> map) {
// get root "entities" entry
Map<String, Object> entitiesMap = (Map<String, Object>)map.get("entities");
for (Map.Entry<String, Object> entitiesEntry : entitiesMap.entrySet()) {
// iterate over collection entries
if (entitiesEntry.getValue() instanceof Collection) {
Collection coll = (Collection)entitiesEntry.getValue();
// iterate over entries in collection
for (Object collEntry : coll) {
if (collEntry instanceof Map) {
// add "name" with ame of collection (key entry under "entries")
((Map<String, Object>)collEntry).put("name", entitiesEntry.getKey());
}
}
}
}
}
}
I'm trying to deserialize a JSON object (from JIRA REST API createMeta) with unknown keys.
{
"expand": "projects",
"projects": [
{
"self": "http://www.example.com/jira/rest/api/2/project/EX",
"id": "10000",
"key": "EX",
"name": "Example Project",
"avatarUrls": {
"24x24": "http://www.example.com/jira/secure/projectavatar?size=small&pid=10000&avatarId=10011",
"16x16": "http://www.example.com/jira/secure/projectavatar?size=xsmall&pid=10000&avatarId=10011",
"32x32": "http://www.example.com/jira/secure/projectavatar?size=medium&pid=10000&avatarId=10011",
"48x48": "http://www.example.com/jira/secure/projectavatar?pid=10000&avatarId=10011"
},
"issuetypes": [
{
"self": "http://www.example.com/jira/rest/api/2/issueType/1",
"id": "1",
"description": "An error in the code",
"iconUrl": "http://www.example.com/jira/images/icons/issuetypes/bug.png",
"name": "Bug",
"subtask": false,
"fields": {
"issuetype": {
"required": true,
"name": "Issue Type",
"hasDefaultValue": false,
"operations": [
"set"
]
}
}
}
]
}
]
}
My problem is: I don't know the keys into "fields" (in the example below "issuetype", "summary", "description", "customfield_12345").
"fields": {
"issuetype": { ... },
"summary": { ... },
"description": { ... },
"customfield_12345": { ... }
}
It would be awesome if I could deserialize it as an array with the key as "id" in my POJO so the above example will looke like the following:
class IssueType {
...
public List<Field> fields;
...
}
class Field {
public String id; // the key from the JSON object e.g. "issuetype"
public boolean required;
public String name;
...
}
Is there a way I can achieve this and wrap in my model? I hope my problem is somehow understandable :)
If you don't know the keys beforehand, you can't define the appropriate fields. The best you can do is use a Map<String,Object>.
If there are in fact a handful of types, for which you can identify a collection of fields, you could write a custom deserializer to inspect the fields and return an object of the appropriate type.
I know it's old question but I also had problem with this and there are results..
Meybe will help someone in future : )
My Response with unknow keys:
in Model Class
private JsonElement attributes;
"attributes": {
"16": [],
"24": {
"165": "50000 H",
"166": "900 lm",
"167": "b.neutr.",
"168": "SMD 3528",
"169": "G 13",
"170": "10 W",
"171": "230V AC / 50Hz"
}
},
So I also checked if jsonElement is jsonArray its empty.
If is jsonObject we have data.
ProductModel productModel = productModels.get(position);
TreeMap<String, String> attrsHashMap = new TreeMap<>();
if (productModel.getAttributes().isJsonObject())
{
for (Map.Entry<String,JsonElement> entry : productModel.getAttributes().getAsJsonObject().entrySet())
{
Log.e("KEYS", "KEYS: " + entry.getKey() + " is empty: " + entry.getValue().isJsonArray());
if (entry.getValue() != null && entry.getValue().isJsonObject())
{
for (Map.Entry<String, JsonElement> entry1 : entry.getValue().getAsJsonObject().entrySet())
{
Log.e("KEYS", "KEYS INSIDE: " + entry1.getKey() + " VALUE: " + entry1.getValue().getAsString());
// and there is my keys and values.. in your case You can get it in upper for loop..
}
}
}
There is a perfectly adequate JSON library for Java that will convert any valid JSON into Java POJOs. http://www.json.org/java/
I am using an API where I supply an input string, and it returns some keyword autocompletions and product nodes.
My goal is to deserialize the response and get a list of the autocompletion Strings I can use. I'm trying implement this in an android application with the Retrofit library, which uses gson.
First off, I'm not sure the response I have is a typical JSON response. The 'nodes' item has key / value pairs, but the input string and the autocompletions list don't seem to have keys I can use.
["pol",
["polaroid camera",
"polo",
"polo ralph lauren",
"polo ralph lauren men",
"polar heart rate monitor",
"polaroid",
"polo shirt",
"polar watch",
"police scanner",
"polar"],
[{
"nodes": [{
"alias": "electronics",
"name": "Electronics"
},
{
"alias": "electronics-tradein",
"name": "Electronics Trade-In"
}]
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
},
{
}],
[]]
This is my attempt at the java classes for gson to deserialize to. However, it doesn't work as from what I understand, gson needs the class variables to match the JSON keys (true for Node class but not the rest).
class Response {
String input;
List<String> keywords;
List<Node> nodes;
}
class Node {
String alias;
String name;
}
the json only has a couple of keys in it, this is largely a Json Array.
if you can change the JSON, make it more like this
{
"input" : "pol",
"keywords" : ["polaroid camera","polo",...],
"nodes": [{
"alias": "electronics",
"name": "Electronics"
},
{
"alias": "electronics-tradein",
"name": "Electronics Trade-In"
}]
}