Parse Response via rest template exchange - java

How to create a POJO class Of below mentioned JSOn Structure by a REST Service. Using RestTemplate.exchange i need to parse this in my java.class file and get approved_by value and use in java code. Below is the response structure:
{
"approval_rules_overwritten": true,
"rules": [
{
"id": 1,
"name": "Test",
"rule_type": "RuleTest",
"approvals_required": 2,
"approved_by": [
{
"id": 2,
"name": "ABC",
"username": "ABC_XYZ",
"state": "active",
}
],
"approved": false
}
]
}

Did you create a class representing this JSON ?
In quick in the same class file (different classes would be best in different files)
public class Response {
private Boolean approval_rules_overwritten;
private List<Rule> rules;
public static class Rule {
private Integer id;
private String name;
private String rule_type;
private Integer approvals_required;
private List<Approval> approved_by;
private Boolean approved;
public static class Approval {
private String id;
private String name;
private String username;
private String state;
}
}
}
Also remember to add getters and setters on each class.
Now you can do your classic request:
ResponseEntity<Response> = restClient.exchange(request, Response.class);
and you would get your response.
You now only have to build your rest template and also to catch exceptions that could be thrown from the exchange request.

Related

Not able to deserialize nested JSON array Spring Resttemplate

I am not able to deserialize nested JSON array from response JSON using Spring Rest template.
JSON response which I am consuming is as follows
[
{
"creationTime": "2023-01-13",
"code": "456",
"cid": "123",
"priority": "CRITICAL",
"reviewDate": null,
"systemCall": [
{
"creationTime": "2023-01-13",
"status": null,
"id": "787878",
"modificationTime": "2023-01-13",
"creatorId": "ABC"
},
{
"creationTime": "2023-01-14",
"status": null,
"id": "787879",
"modificationTime": "2023-01-14",
"creatorId": "DEF"
}
],
level: "1"
}
]
And My model classes as follows
public class Resolution {
private String creationTime;
private String code;
private String cid;
private String priority;
private String reviewDate
private List<SystemCallVo> systemCall;
private String level;
public Resolution(){
}
//Getters and Settrs
}
public class SystemCallVo {
private String creationTime;
private String status;
private String id;
private String modificationTime;
private String creatorId;
public SystemCallVo(){
}
//Getters and Setters
}
public class ResolutionVo extends Resolution{
public ResolutionVo(){
}
}
I am calling my endpoint using rest template as follows.
ResponseEntity<List<ResolutionVo>> response = this.restTemplateConfig.restTemplate().exchange(builder.toUriString(), HttpMethod.POST, httpEntity, new ParameterizedTypeReference<List<ResolutionVo>>() {
}, new Object[0]);
Problem is List systemCall object is always null in response received through resttemplate even though systemCall attribute is present in JSON whenever I hit endpoint through swagger.
There is a defect in RestTemplate.exchange that prevents the deserialisation of even moderately complex JSON objects.
Read the response as a String and then deserialise to List<ResolutionVo> with an com.fasterxml.jackson.databind.ObjectMapper instance as follows:
ResponseEntity<String> response = this.restTemplateConfig.restTemplate().exchange(builder.toUriString(), HttpMethod.POST, httpEntity, String.class, new Object[0]);
String body = response.getBody();
List<ResolutionVo> value = objectMapper.readValue(body, new TypeReference<List<ResolutionVo>>() {});
I think this is a related issue.

REST API response only for certain feilds

REST API Request:
{ "name": "abc", "sal": "10000", "location": "Hyd" }
EmployeeRequest.java
id, name, sal, location --> setters and getters
EmployeeResponse.java
id, name, sal, location --> setters and getters
POST : /api/employee --> this should not be change
POST API response :
expected:
{ "id" : "123" }
I dont want other fields except ID in a response
Actual:
`{
"id": "123",
"name": "null",
"sal": "null",
"location": "null"
}
But i want response only ID not other fields for POST response, But its coming all the fields in EmployeeResponse.java
GET API(/api/employees/id) Response
{
"id" : "123"
"name": "abc",
"sal": "10000",
"location": "Hyd"
}
But i want response ALL fields as a GET Response in EmployeeResponse.java
Is there any way to restrict certain properties wont be part of REST API response, even though all properties same Response class. ?
you can use the #JsonIgnore annotation
#JsonIgnoreProperties(value = { "intValue" })
public class MyDto {
private String stringValue;
private int intValue;
private boolean booleanValue;
public MyDto() {
super();
}
}
or #JsonIgnore on field level
public class MyDto {
private String stringValue;
#JsonIgnore
private int intValue;
private boolean booleanValue;
public MyDto() {
super();
}
}

Jackson-databind mapping JSON skip layer

I got a JSON response like this:
{
"status": "success",
"response": {
"entries": [
{
"id": 1,
"value": "test"
},
{
"id": 2,
"value": "test2"
}
]
}
}
And i want to map it with jackson-databind on an object like this:
public class Response {
#JsonProperty("status")
private String status;
#JsonProperty("response.entries")
private Collection<ResponseEntry> entries;
}
So i'm searching for an way to give #JsonProperty a path so it can skip the layer "response".
Welcome to Stack Overflow. You can define a wrapper class for your Collection<ResponseEntry> collection like below :
public class ResponseWrapper {
#JsonProperty("entries")
private Collection<ResponseEntry> entries;
}
The ResponseEntry class could be defined like below :
public class ResponseEntry {
#JsonProperty("id")
private int id;
#JsonProperty("value")
private String value;
}
Once defined these classes you can rewrite your old Response class like below :
public class Response {
#JsonProperty("status")
private String status;
#JsonProperty("response")
private ResponseWrapper responseWrapper;
}
You can flatten using the #JsonUnwrapped annotation.
You can have your classes like this
public class Response {
private String status;
private Collection<ResponseEntry> entries;
}
public class ResponseEntry {
#JsonUnwrapped
private Entry entry;
}
pubic class Entry{
private Integer id;
private String value;
}

Spring Boot - How to send an array of objects using Post request (JSON)

Could someone point me in the right direction as to how to do this?
I have written a separate SizeQtyPrice class with its instance variable in my Item Model. The post request works fine for sending literals but am unsure on sending objects
Note: I am not an experienced coder and completely new to Spring Boot so would really appreciate maybe some background knowledge and pre-requisite info on how to approach or point me in the right direction - (or even tell me if I am too in over my head trying to do this.)
Here is the JSON file I want to send via post request.
{
"name": "Item1",
"description": "Print 1",
"imagePath" : "https://www.tapety-sklep.com/userdata/gfx/abb4fe9b340cb3ff7e72b89a00695b43.jpg",
"detail": "This print is etc.....",
"sizeQtyPrice":[
{
"size": "small",
"qty": 6,
"price": 9.99
},
{
"size": "medium",
"qty": 3,
"price": 15.99
},
{
"size": "large",
"qty": 8,
"price": 20.99
}
]
}
SizeQtyPrice Class (+ getters/setters)
public class SizeQtyPrice {
private String size;
private int qty;
private float price;
public SizeQtyPrice(String size, int qty, float price) {
this.size = size;
this.qty = qty;
this.price = price;
}
Item Model declaring SizeQtyItem[]
public class Item implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String itemCode;
private String name;
private String description;
private String imagePath;
private String detail;
private SizeQtyPrice[] sizeQtyPrice;
Controller Class
#RestController //marks as a controller class
#RequestMapping("/item") //base url
public class ItemResource {
private final ItemService itemService;
#Autowired //injects the service into the constructor
public ItemResource(ItemService itemService) {
this.itemService = itemService;
}
#GetMapping("/all") //get request to retrieve from backend. This is the base URL /item/all
public ResponseEntity<List<Item>> getAllItems() {
List<Item> items = itemService.findAllItems();
return new ResponseEntity<>(items, HttpStatus.OK);
}
#PostMapping("/add")
public ResponseEntity<Item> addItem(#RequestBody Item item) { // JSON format
Item newItem = itemService.addItem(item);
System.out.println(newItem);
return new ResponseEntity<>(newItem, HttpStatus.CREATED);
}
Turns out it was a simple annotation issue in my SizeQtyPrice class. I hadn't annotated the class with #Embeddable
#Embeddable
public class SizeQtyPrice { .....
https://www.baeldung.com/jpa-embedded-embeddable
Edit: I also was not adding a default/empty constructor to my Item class which was giving me the following error:
No Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator.
Adding a default constructor fixed this issue and can now send post requests without issues!

How to deserialize complex JSON to java object

I need to deserialize JSON to java class.
I have JSON like the following:
{
"data": {
"text": "John"
},
"fields":[
{
"id": "testId",
"name": "fieldName",
"options": {
"color": "#000000",
"required": true
}
},
{
"id": "testId",
"name": "fieldName1",
"options": {
"color": "#000000",
"required": false
}
}
]
}
and I need to deserialize this JSON (only "fields" section) to java class like the following:
public class Field {
public final String id;
public final String name;
public final String color;
public final boolean required;
}
and I need to get something like the following:
// The key is the id from field object (it can be the same in the multiple objects.)
Map<String, List<Field>> fields = objectMapper.readValue(json, Map<String, List<Field>>);
How can I do it using Jackson?
As long as jackson doesn't support #JsonWrapped, you have to use the following work around.
First you need to create a custom class which contains the fields:
public class Fields {
public List<Field> fields;
}
Depending on your ObjectMapper configuration you have to add #JsonIgnoreProperties(ignoreUnknown = true) to the Fields class, to ignore any other properties.
Next is that you have to define the nested Options class which is solely used temporarily:
public class Options {
public String color;
public boolean required;
}
And at last add this constructor to your Field class:
#JsonCreator
public Field(#JsonProperty("id") String id, #JsonProperty("name") String name, #JsonProperty("options") Options options){
this.id = id;
this.name = name;
this.color = options.color;
this.required = options.required;
}
The #JsonCreator annotation indicates to jackson that this constructor needs to be used for the deserialization. Also the #JsonProperty annotations are required as arguments to constructors and methods are not preserved in the bytecode
Then you can deserialize your json just like this:
List<Field> fields = objectMapper.readValue(json, Fields.class).fields;

Categories

Resources