how to retrieve a part of JSON HTTP response as POJO - java

I am currently working on a project where i need to make a rest call to an external API and parse the JSON response to a POJO and return back the POJO as JSON for another rest request. I am able to parse the JSON response, but my requirement is to parse only one particular node from it. How can i achieve this? I am using Spring Boot and Spring Rest Template to make the external rest call. Please help!!!
#RestController
public class ProductsController {
private static final Logger LOGGER = LoggerFactory.getLogger(ProductsController.class);
#RequestMapping(value = "/myRetail/product/{id}", method = RequestMethod.GET, produces = {
MediaType.APPLICATION_JSON_UTF8_VALUE, MediaType.APPLICATION_XML_VALUE })
#ResponseBody
public Item getSchedule(#Valid Payload payload) {
String URL = "<External API>";
LOGGER.info("payload:{}", payload);
Item response = new Item();
RestTemplate restTemplate = new RestTemplate();
Item item = restTemplate.getForObject(URL, Item.class);
LOGGER.info("Response:{}", item.toString());
return response;
}
}
JSONResponse (This is a part of whole i receive)
{
"ParentNode": {
"childNode": {
"att": "13860428",
"subchildNode 1": {
"att1": false,
"att2": false,
"att3": true,
"att4": false
},
"att4": "058-34-0436",
"att5": "025192110306",
"subchildenode2": {
"att6": "hello",
"att7": ["how are you", "fine", "notbad"],
"is_required": "yes"
},
............
}
Required JSONpart from the above whole response:
"subchildenode2": {
"att6": "hello",
"att7": ["how are you", "fine", "notbad"],
"is_required": "yes"
}

Use the org.json library. With this library you can parse the payload to a JSONObject and navigate to your required subpart of the document.
So you have to get the payload as a JSON-String and parse it to the JSONObject from the library. After that you can navigate to your required subpart of the document and extract the value and then parse it to your required Java POJO.
Have look at: How to parse JSON

Just map the path to the needed object:
{
"ParentNode": {
"childNode": {
"subchildenode2": {
"att6": "hello",
"att7": ["how are you", "fine", "notbad"],
"is_required": "yes"
}
}
}
And then simply:
Response responseObject= new Gson().fromJson(json, Response.class);
SubChildNode2 att6 = responseObject.getParentNode().getChildNode().getSubChildNode2();

Related

Method is not being detected when using the Custom class as input parameter type for the REST API service

I am developing a Web application using Vuejs/Nuxtjs which makes call to my Java Service using the Axios but during the call I get the error:
POST http://localhost:9001/generate 500 (Internal Server Error)
I am getting this error because my Java service type accepts the input parameter of Custom data type InputParameter. If I change to String then it works fine. So I would like to know what changes should I make to front-end call or to my Java Service so it can work with InputParameter type.
Following is the Vuejs call that I am making to Java service:
const headers = { 'Content-Type': 'application/json' }
this.$axios.post('/generate', { ...JSON.parse(inputParameter) }, { headers })
.then((response) => {
console.log(JSON.stringify(response.data))
})
.catch((error) => {
console.log(error)
})
Following is my Java service method which is NOT working with custom data type InputParameter, the call does not detect the method and execution does not go within the method:
#Path("/generate")
#Produces(MediaType.APPLICATION_JSON)
#APIResponses(value = {
#APIResponse(responseCode = "200", description = "returns list of JSON Objects"),
#APIResponse(responseCode = "500", description = "An internal Server Error occurred")
})
public String generate(final InputParameter inputParameter){
System.out.println(inputTemplate.toString());
return null;
}
If I change the above JAVA Service method input parameter data type to String then the method is detected and input is printed:
#Path("/generate")
#Produces(MediaType.APPLICATION_JSON)
#APIResponses(value = {
#APIResponse(responseCode = "200", description = "returns list of JSON Objects"),
#APIResponse(responseCode = "500", description = "An internal Server Error occurred")
})
public String generate(final String inputParameter){
System.out.println(inputTemplate);
return null;
}
I am not understanding whats wrong here. Can someone please help?
Things I have tried:
Adding #Consumes(MediaType.APPLICATION_JSON).
Changing the method to public String generate(#RequestBody final InputParameter inputParameter)
My InputParameter class looks something like this:
#Data
#AllArgsConstructor
#NoArgsConstructor
public class InputParameter {
private List<String> names;
private List<String> jobs;
}
My InputParameter which I am passing to Java Service looks something like this:
{
"names":[
"Batman",
"Superman",
"Ironman"
],
"jobs":[
"Fighting",
"Fyling",
"Teching"
]
}
Dear in the back end the api is accepting an object of type InputParameter. For solving the problem you have to create a class the same as InputParameter class and generate an object of that and send that object to the back end.
Let me know if you need more help!
Posting the answer can be helpful to someone else in the future. I tried some things but nothing worked and finally following worked for me:
#POST
#Path("/generate")
#Produces(MediaType.APPLICATION_JSON)
#APIResponses(value = {
#APIResponse(responseCode = "200", description = "returns list of JSON Objects"),
#APIResponse(responseCode = "500", description = "An internal Server Error occurred")
})
public String generate(final InputParameter inputParameter){
System.out.println(inputTemplate.toString());
return null;
}
There was also one small setting that I had to change related to Jackson ObjectMapper which is not relevant here because it's my project-specific that I missed in another class. Maybe that was the issue I was facing. Now everything is working as expected.

Java RestTemplate response mapping with nested list of objects

Hi I am hitting an endpoint with rest template and getting the response.
When I use String as return type and print the response it's an XML response with multiple tags.
and when I use Object as return type then RestTemplate is mapping only last tag from the list.
With String.class as return type
Request:
ResponseEntity<String> response = restTemplate.postForEntity(urlTemplate, httpEntity, String.class);
System.out.println(response.getBody());
Response:
<Order>
<OrderLines>
<OrderLine LineID="1"></OrderLine>
<OrderLine LineID="2"></OrderLine>
<OrderLine LineID="3"></OrderLine>
</OrderLines>
</Order>
With Object.class as return type
Request:
ResponseEntity<Object> response = restTemplate.postForEntity(urlTemplate, httpEntity, Object.class);
System.out.println(response.getBody());
Response:
{
"OrderLines": {
"OrderLine": {
"LineID": "3"
}
}
}
Expected Response with Object.class as return type is:
{
"OrderLines": {
"OrderLine": [
{
"LineID": "1"
},
{
"LineID": "2"
},
{
"LineID": "3"
}
]
}
}
Please suggest the solution to this.
You can create a model class to Map the expected Response with Object.class as return type, But instant you will need to have it like OrderLines.class ( which is your newly created model )
Then you can use ObjectMapper or Gson to map the response like the following.
OrderLines obj = gson.fromJson(stringResponse, OrderLines.class);
return obj;
This will have the created model object to be returned after getting the information needed from the string returned type.

JSON.stringify from typescript/javascript do not match json-String param/request-body in Java controller

I am using jdk 1.8. I have a rest end point in java controller as :
#PostMapping("/filters")
public ResponseEntity<StatsDTO> listWithFilter(
#RequestBody(required = false) String filter
) {
try {
...............
}
}
Test snippet against above controller is passing (getting back expected result in this snippet) as :
#Test
public void findReferralTest15() throws IOException {
String result = webClient.post()
.uri(endpoint(helper.entity + "/filters"))
.contentType(MediaType.APPLICATION_JSON)
.header(HttpHeaders.AUTHORIZATION, clientUser())
.body(BodyInserters.fromObject(buildJsonForQuery15()))
.exchange()
.expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
.expectStatus().isOk()
.expectBody(String.class).returnResult().getResponseBody();
ObjectMapper mapper = new ObjectMapper();
ResponseList referralList = mapper.readValue(result, ResponseList.class);
}
public String buildJsonForQuery15() {
String json = "{\"billType\":{\"INTAKE\":true}}";
return json;
}
Now when I am trying to integrate with front end (Angular 7 on typescript), I have to do JSON.stringify twice (to a json object or filter to be submitted as requestbody) to make it work with the back end. I am getting null otherwise as the value of the "filter" ( in the request body) at the java controller end.
So with double JSON.stringify submitted result from our front end is (WHEN IT WORKS):
"{\"billType\":{\"INTAKE\":true}}"
So with single JSON.stringify submitted result from our from end is (WHEN IT DOESN'T WORK):
{"billType":{"INTAKE":true}}
Question : What should be the data type of requestBody "filter", in the java controller, to make it work with single JSON.stringify?
I tried json.org.JsonObject as datatype for "filter" but it did not make any difference.
Thanks in advance.
Front end snippet:
const fullUrl = `${this.referralsUrl}/filters?first=${first}&max=${max}`;
const headerDict = {
"Content-Type": "application/json; charset=utf-8",
Accept: "application/json",
"Access-Control-Allow-Headers": "Content-Type"
};
const headers = new HttpHeaders(headerDict);
if (filters) {
const requestBody = JSON.stringify(filters);
return this.http
.post<Page<ClinAssistReferral>>(fullUrl, JSON.stringify(requestBody), { headers })
.pipe(
map((data: any) => {
...........
}
}
If the body is not dynamic, making a DTO for the request is preferred.
If body is dynamic, I would suggest you to try JsonNode from jackson. See if this library can
import com.fasterxml.jackson.databind.JsonNode;
...
#PostMapping("/filters")
public ResponseEntity<StatsDTO> listWithFilter(
#RequestBody(required = false) JsonNode filter
) {
try {
var intake = filter.get("billType").get("INTAKE").asBoolean()
...............
}
}

Adding additional field in Response Object

I am getting below response when I am calling an API.
Response postRequestResponse = ConnectionUtil.getwebTarget()
.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true)
.path("bots")
.path(ReadSkillID.readSkillId())
.path("dynamicEntities").path(dynamicEntityID)
.path("pushRequests").path(pushRequestID).path(operation)
.request()
.header("Authorization", "Bearer " + ConnectionUtil.getToken())
.get();
Below output I am getting.
{
"createdOn": "2020-08-17T12:19:13.541Z",
"updatedOn": "2020-08-17T12:19:23.421Z",
"id": "C84B058A-C8F9-41F5-A353-EC2CFE7A1BD9",
"status": "TRAINING",
"statusMessage": "Request Pushed into training, on user request"
}
I have to return this output to client with an additional field in the response. How can modify the above response and make it
{
"EntityName": "NewEntity", //New field
"createdOn": "2020-08-17T12:19:13.541Z",
"updatedOn": "2020-08-17T12:19:23.421Z",
"id": "C84B058A-C8F9-41F5-A353-EC2CFE7A1BD9",
"status": "TRAINING",
"statusMessage": "Request Pushed into training, on user request"
}
I am adding this additional field here
"EntityName": "NewEntity"
How can I do that. many things I tried but got exception.
get JSON from postRequestResponse (i have no idea what framework you are using, so you have to figer it out on your own, but the Response datatype will probably have a getResponseBody or similar method returing the JSON)
add EntityName
serialize it again to json.
class YourBean {
#Autowired
private ObjectMapper objectMapper;
public void yourMethod() {
// 1
final InputStream jsonFromResponse = ...
// 2
Map dataFromResponse = objectMapper.readValue(jsonFromResponse, Map.class);
dataFromResponse.put("EntityName", "NewEntity");
// 3
final String enrichedJson = objectMapper.writeValueAsString(dataFromResponse);
}
}
enrichedJson contains EntityName and whatever comes from the API.

How to get HTML content as JSON value in spring boot

I am developing an API , where I receive some article related data as a POST request. The receiver I have as following:
#ApiOperation(value = "Add a new Article", produces = "application/json")
#RequestMapping(value = "/create", method = RequestMethod.POST)
public ResponseEntity createPost(#RequestBody String postContent) {
try {
// Here I need to conver the postContent to a POJO
return new ResponseEntity("Post created successfully", HttpStatus.OK);
} catch (Exception e) {
logger.error(e);
return responseHandler.generateErrorResponseJSON(e.getMessage(),
HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Now it works for simple request like:
{
"id": "1",
"title": "This is the Post Title",
"body": "This is the Post Body",
"authorName": "Test",
"tagList": [
"tag-1",
"tag-2",
"tag-3"
]
}
But in real scenario I will get receive a HTML content as the value of the "body" key in request JSON, which can have "",<,> or many thing. Then the String to JSON conversion will fail. Is there any api, library or example, where I can have HTML content as the value of a JSON key.
Following is my input request where the code is failing to parse the JSON to Object:
{
"menuId": "1",
"title": "This is the Post Title",
"body": "<p style="text-align:justify"><span style="font-size:16px"><strong>Mediator pattern</strong> is a Behavioral Design pattern. It is used to handle complex communications between related Objects, helping by decoupling those objects.</span></p>",
"authorName": "Arpan Das",
"tagList": [
"Core Java",
"Database",
"Collection"
]
}
Now How I am parsing the json is like:
public Post parsePost(String content) {
Post post = new Post();
JSONParser jsonParser = new JSONParser();
try {
JSONObject jsonObject = (JSONObject) jsonParser.parse(content);
post.setMenuId((Integer) jsonObject.get(Constant.MENU_ID));
post.setTitle((String) jsonObject.get("title"));
post.setBody((String) jsonObject.get("body"));
post.setAuthorName((String) jsonObject.get("authorName"));
post.setAuthorId((Integer) jsonObject.get("authorId"));
post.setTagList((List) jsonObject.get("tag"));
} catch (ParseException e) {
e.printStackTrace();
}
return post;
}
It is giving a parse exception :
Unexpected character (t) at position 77.
The library I am using for parsing the JSON is:
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>

Categories

Resources