Parse Json String using jackson Parser - json

I am able to parse json below:
{
"jobId": "xxx",
"jobName": "xxx",
"jobInput": "xxx"
}
final ObjectMapper mapper = new ObjectMapper();
Map<?, ?> map = mapper.readValue(jsonString, Map.class);
I need to parse the below json string using jackson parser in java.
{
"Test1": {
"jobId": "xxx",
"jobName": "xxx",
"jobInput": "xxx"
},
"Test2": {
"jobId": "xxx",
"jobName": "xxx",
"jobInput": "xxx"
}
}

With Jackson, you can do the following:
ObjectMapper mapper = new ObjectMapper();
TypeReference<Map<String, Object>> typeRef = new TypeReference<Map<String, Object>>() {};
Map<String, Object> data = mapper.readValue(json, typeRef);
If you prefer to use a custom class to hold the values instead of a Map, use:
ObjectMapper mapper = new ObjectMapper();
Data data = mapper.readValue(json, Data.class);
public class Data {
#JsonProperty("Test1")
private Job test1;
#JsonProperty("Test2")
private Job test2;
// Default constructor, getters and setters
}
public class Job {
private String jobId;
private String jobName;
private String jobInput;
// Default constructor, getters and setters
}

How about just let Jackson parse a Map? Make the return type as Map<String, YourFirstDTO> and I think it will do.

Related

Deserialize this Json Object using Jackson?

I have been trying to deserialize the data received from this API:
{
"result": "success",
"timestamp": 1521038012878,
"data": {
"GB": 14,
"DE": 2,
"US": 2
},
"totalIsPublic": true,
"advanced": false,
"totalDownloads": {
"GB": 14,
"DE": 2,
"US": 2
}
}
Here is the POJO class:
public class BintrayDownloadCounts {
private List<Integer> totalDownloads = new ArrayList<>();
#JsonProperty("totalDownloads")
public List<Integer> getTotalDownloads() {
return totalDownloads;
}
public void setTotalDownloads(List<Integer> totalDownloads) {
this.totalDownloads = totalDownloads;
}
}
When I tried deserializing using :
downloadCounts = mapper.readValue(json, BintrayDownloadCounts.class);
I get this error:
com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.Integer out of START_OBJECT token
I have seen many questions containing this error but I am unable to figure out a solution for this particular use case. It may be noted that the totalDownloads object is dynamic i.e. its contents are not constant.
The totalDownloads property is not an array, so it cannot be mapped to a List<Integer>. Use Map<String, Integer> instead and ensure that you tell Jackson to ignore the properties that are not mapped to avoid mapping errors:
#JsonIgnoreProperties(ignoreUnknown = true)
public class BintrayDownloadCounts {
#JsonProperty("totalDownloads")
private Map<String, Integer> totalDownloads;
public Map<String, Integer> getTotalDownloads() {
return totalDownloads;
}
public void setTotalDownloads(Map<String, Integer> totalDownloads) {
this.totalDownloads = totalDownloads;
}
}
Then you are good to go:
ObjectMapper mapper = new ObjectMapper();
BintrayDownloadCounts downloadCounts = mapper.readValue(json, BintrayDownloadCounts.class);

Spring Boot: Convert complex json string response to object

I want to convert a complex json string–which I get from a GET request–to our database. I need to loop through all the objects and find some specific ones. The problem is that all objects are different in some way. They could look like these three examples, but there are many more:
{
"created": 1493209170473990,
"id": "fu:9843464EDF4D053072ACEAC2362EE0D8",
"type": "user-created"
},
{
"created": 1493209170883075,
"data": {
"process_type": "wallet-tx"
},
"id": "fu:6BE085BF29D7C8AF4C238615CA85F31A",
"process": "0CEB2F401E0FB9D9A44A124D0710B521",
"type": "process-created"
},
{
"created": 1495535185484487,
"data": {
"message": "electronic delivery"
},
"document": "25FBED0A80FEEBD6FF154D21D8E35D7E",
"id": "fu:3C17584381C0AFB4836F73057DB7DEAB",
"type": "info"
}
I need to find some objects with a specific type, but I cant get them out of a string. I get the request data with this call:
#RequestMapping(value="/events", method=RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
#CrossOrigin(origins = "http://localhost:4200", maxAge = 3600)
public String getEvents() {
int created_after = 0;
final String url = server + "/rest/client/events/" + created_after;
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
headers.set("Auth-Token", token); // user_token
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
return response.getBody();
}
I use Angular in my frontend, which could easy convert the string to an Object, but then I have to pass this again to my backend to work with the data. I want to keep everything in the backend. Do you have any idea how to solve it?
If you need more information, please ask. Thanks
EDIT:
My JSON output looks like this:
[
{
"created": 1493209170473990,
"id": "fu:9843464EDF4D053072ACEAC2362EE0D8",
"type": "user-created"
},
{
"created": 1493209170653925,
"data": {
"verify_id": "12581C42DD2DF7D80F802C50ABD144F8"
},
"id": "fu:06111B0A9C5B760B9269044DA97D3D6F",
"type": "post-address-verification-confirmed"
},
{
"created": 1493209171320041,
"data": {
"after": {
"attempt": 1
}
},
"id": "fu:7B5B2AD57C1CE97BB642931C2C3C819D",
"process": "0CEB2F401E0FB9D9A44A124D0710B521",
"type": "process-updated"
},
...
]
The way I understand it, your objects have some common properties, as well as some optional ones. You can model the optional properties using #JsonAnyGetter and #JsonAnySetter:
class Data {
#JsonProperty
private Long created;
#JsonProperty
private String id;
#JsonProperty
private String type;
private Map<String, Object> optional = new HashMap<>();
public Data() { // empty public constructor is required
}
// getters/setters for all properties omitted for brevity
#JsonAnySetter
public void addOptional(String name, Object value) {
optional.put(name, value);
}
#JsonAnyGetter
public Object getOptional(String name) {
return optional.get(name);
}
}
Then you can deserialize your objects using
ObjectMapper objectMapper = new ObjectMapper();
Data data = objectMapper.readValue(j, Data.class);
or, if you've got an array of your Data objects as input,
Data[] data = objectMapper.readValue(j, Data[].class);
All properties except created, id and type will be placed in the optional map.
If you don't know what the structure of the JSON is going to be then you can serialize your JSON string to a Map which maps the field names in the json to their value.
This can be done using the Jackson ObjectMapper:
String jsonObject = <the string JSON response you obtained>;
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> jsonMap = objectMapper.readValue(jsonString,
new TypeReference<Map<String, Object>>(){});
If it's a list of JSON objects you expect then you can first map this to an array of JSON strings and then convert each one to a map:
ObjectMapper objectMapper = new ObjectMapper();
String[] jsonStrings = objectMapper.readValue(jsonString, String[]);
List<Map<String, Object>> jsonMaps = new ArrayList<>();
for (String json : jsonStrings) {
jsonMaps.add(objectMapper.readValue(json,
new TypeReference<Map<String, Object>>(){});
}

Using javax.ws.rs.core.Response.readEntity to extract a list of strings from a JSON object

If my response is like:
{
"values": [ "1", "2" ]
}
How should I use readEntity to populate a List<String> with the values: 1, 2?
You can read the entity as a Map<String, List<String>>:
Map<String, List<String>> map =
response.readEntity(new GenericType<Map<String, List<String>>>() { });
List<String> values = map.get("values");
Or define your own POJO:
public class MyBean {
private List<String> values;
// Getters and setters
}
List<String> values = response.readEntity(MyBean.class).getValues();
You obviously must have a JSON provider such as Jackson registered.

Map JSON string array to List<String> using Jackson

I have following JSON returned from server.
String json = {
"values": ["name","city","dob","zip"]
};
I want to use ObjectMapper to return the List<String> values. Something like:
List<String> response = mapper.readValue(json, List.class)
I have tried several ways but none of them worked. Any help is appreciated.
Edit: I don't want additional wrapper objects. I want to straight away get the List<String> out.
The TypeFactory in Jackson allows to map directly to collections and other complex types:
String json = "[ \"abc\", \"def\" ]";
ObjectMapper mapper = new ObjectMapper();
List<String> list = mapper.readValue(json, TypeFactory.defaultInstance().constructCollectionType(List.class, String.class));
You could define a wrapper class as following:
public class Wrapper {
private List<String> values;
// Default constructor, getters and setters omitted
}
Then use:
Wrapper wrapper = mapper.readValue(json, Wrapper.class);
List<String> values = wrapper.getValues();
If you want to avoid a wrapper class, try the following:
JsonNode valuesNode = mapper.readTree(json).get("values");
List<String> values = new ArrayList<>();
for (JsonNode node : valuesNode) {
values.add(node.asText());
}
There is another way you might be interested in, partly similar to accepted answer but can be written as one-liner (line breaks should help with understanding).
Input JSON:
{
"values": ["name", "city", "dob", "zip"]
}
Code snippet:
String json = "{\"values\":[\"name\",\"city\",\"dob\",\"zip\"]}";
ObjectMapper mapper = new ObjectMapper();
List<String> list = Arrays.asList(
mapper.convertValue(
mapper.readTree(json).get("values"),
String[].class
)
);
list.forEach(System.out::println);
This code snippet outputs the following:
name
city
dob
zip
Please note that Arrays.asList() returns a list of fixed size because it is backed by a given array. To get a resizable list just wrap it like that:
List<String> resizableList = new ArrayList<>(
Arrays.asList(new String[] {"a", "b", "c"})
);
Of course this solution can be adapted to more complex cases, not just Strings.
For example, for a given POJO User:
class User {
private int id;
private String name;
public int getId() {
return id;
}
public String getName() {
return name;
}
#Override
public String toString() {
return String.format(
"[User = {id: %d, name: \"%s\"}]",
id,
name
);
}
}
and input JSON:
{
"values": [{
"id": 1,
"name": "Alice"
}, {
"id": 2,
"name": "Bob"
}
]
}
following code snippet:
ObjectMapper mapper = new ObjectMapper();
String json = "{\"values\":[{\"id\":1,\"name\":\"Alice\"},{\"id\":2,\"name\":\"Bob\"}]}";
List<User> list = Arrays.asList(
mapper.convertValue(
mapper.readTree(json).get("values"),
User[].class
)
);
list.forEach(System.out::println);
yelds the following output:
[User = {id: 1, name: "Alice"}]
[User = {id: 2, name: "Bob"}]

Gson (Json) parsing - POJO mapping - error (this is not a JSON Array)

For -
Config rfqObj = new Gson().fromJson(data, new TypeToken<Config>() {}.getType());
I'm getting the following exception -
The JsonDeserializer
main.java.com.google.gson.DefaultTypeAdapters$CollectionTypeAdapter#30de3c87
failed to deserialized json object {} given the type
main.java.com.google.gson.ParameterizedTypeImpl#7c3d0336] with root
cause java.lang.IllegalStateException: This is not a JSON Array.
JSON data is -
{
"quantities": {
"142": "0",
"143": "20",
"144": "25"
},
"characteristics": {},
"details": {
"8": "HT Test Report",
"9": "Others",
"13": "nTest"
},
"materials": {},
"additionalProcesses": {},
"suppliers": {}
}
And here is the POJO -
public class Config {
Map<Long, String> quantities = new HashMap<Long, String>();
Map<Long, String> characteristics = new HashMap<Long, String>();
Map<Long, String> details = new HashMap<Long, String>();
Map<Long, String> materials = new HashMap<Long, String>();
Map<Long, String> additionalProcesses = new HashMap<Long, String>();
public Set<Suppliers> suppliers = new HashSet();
//this is for the nested class
public static class Suppliers {
// defining attributes of this class
public Long id;
public String name;
public Long contactId;
public String contactInfo;
public String contactMethod;
public String contactName;
public String message;
}
}
The reason you are getting the error is that your JSON text is an object with the following property:
"suppliers": {}
But because your Config object wants the property suppliers to be a set; Gson is expecting a JSON array, not a JSON object.
If you can somehow get your JSON text to include
"suppliers": []
you should be able to deserialize this into a Java set.