I have userDTO like below, and
I am trying to convert userDTO to json string and calling rest API endpoint from my Controller, but the called rest API end point throws error as "data" is not valid JSONobject
public class UserDTO {
private String userId;
private String firstname;
private String lastname;
private List<Order> orders;
some more data member plus // setter / Getters
}
My controller class:- [converting userDTO to json string]
public class OrderController {
UserDTO userRecord = new UserDTO ();
// userRecord some values here
final HttpStatus httpStatus;
HttpEntity<?> httpEntity;
final HttpHeaders headers = new HttpHeaders();
final ObjectMapper mapper = new ObjectMapper();
headers.setContentType(MediaType.APPLICATION_JSON);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
String jsonInput;
// I guess this is the point creating that issue. May be Im doing in wrong way....
jsonInput = mapper.writeValueAsString(new JSONObject().put("data",userRecord ));
httpEntity = new HttpEntity<Object>(jsonInput, headers);
// calling the rest API endpoint
ResponseEntity<String> responseEntity = restTemplate.exchange(
URL, HttpMethod.POST, httpEntity,
String.class,someId);
}
Server Sinippet:-
public MicroserviceResponse createOrder(#PathVariable("cId") final String cId, #RequestBody final String requestBody) throws Exception {
ObjectMapper mapper = new ObjectMapper();
requestJSON = new JSONObject(requestBody).getJSONObject("data");
final String jsonData = requestJSON.toString();
UserDTO orderSource = mapper.readValue(jsonData,
UserDTO .class);
}
Problem:-
Called API [server] throws "data is not valid JSONObject. Am i missing something here ? please guide me.
Trying to send below kind of JSON format
{
"data":{
"username":"test",
"orderId": "123097R",
"firstName":"xydz",
"lastName":"xyzd",
"email":"xx#gmail.com"
}
}
As there are no detailed server logs provided - I assume that the mentioned error is happening at the REST layer.
Please try this - create a payload Java class:
public class RestPayload implements java.io.Serializable {
private UserDTO data;
public UserDTO getUserDTO (){
return this.data;
}
public void setUserDTO(UserDTO data){
this.data = data;
}
}
And then modify your current rest operation to :
#POST
public MicroserviceResponse createOrder(#PathVariable("cId") final String cId, #RequestBody final RestPayload restPayload ) throws Exception {
UserDTO orderSource = restPayload.getUserDTO();
}
UPDATE:
You can also play with the raw JSON and modify the values according to your needs.
Try this - the below code shows how to add "data" as a parent object to the UserDTO :
Gson gson = new Gson();
JsonElement userDtoJsonElement = gson.toJsonTree(userDTO);
JsonObject dataObject = new JsonObject();
dataObject.add("data", userDtoJsonElement);
System.out.println(gson.toJson(dataObject));
Related
I am using SpringBoot Java 11 and have a REST endpoint:
REST Service
#Operation(summary = "Endpoint called by the UI to get the journal entries (using the posted form)")
#PostMapping(path = "/journal-entries/{memberId}/{firstRow}/{noRows}/{overrideFilterForMerchants}")
public ResponseEntity<PowWowControllerDTO> getEntries(#RequestBody PowWowDashboardDTO powWowDashboardDTO, #Parameter(description="memberId") #NotBlank #PathVariable final Long memberId, #Parameter(description="first row") #NotBlank #PathVariable final int firstRow, #Parameter(description="no rows") #NotBlank #PathVariable final int noRows, #Parameter(description="has override role") #NotBlank #PathVariable final boolean overrideFilterForMerchants) {
PowWowControllerDTO dto = new PowWowControllerDTO();
try {
dto = powWowJournalService.getJournalEntries(powWowDashboardDTO, memberId, firstRow, noRows, overrideFilterForMerchants);
dto.setStatus("Success");
} catch (Exception e) {
dto.setStatus("Error: "+e.getMessage());
logger.error("Exception in REST endpoint: getEntries", e);
}
return new ResponseEntity(dto, HttpStatus.OK);
}
When this endpoint is called, in debug, I can see that the PowWowControllerDTO is populated as expected.
I have an old Struts Java 7 application that needs to consume the above endpoint:
REST Client
PowWowControllerDTO dto = new PowWowControllerDTO();
String jsonString = response.getText();
if (jsonString != null) {
logger.info(jsonString);
Gson gson = new Gson();
dto = gson.fromJson(jsonString, PowWowControllerDTO.class);
This gets an exception trying to convert the response to a DTO.
Error
Error to get data from response:
com.google.gson.stream.MalformedJsonException: Expected EOF at line 1
column 48448
I can see from the jsonString that there is a response which looks like a number of empty objects, that does contain:
"message":"Could not write JSON: Infinite recursion
(StackOverflowError); nested exception is
com.fasterxml.jackson.databind.JsonMappingException: Infinite
recursion (StackOverflowError)
PowWowControllerDTO
public class PowWowControllerDTO {
private List<PowWowJournalEntities> journals = new ArrayList<>();
private int firstRow;
private int lastRow;
private Long noRows;
private String status;
PowWowJournalEntities
public class PowWowJournalEntities {
private PowWowJournalHeaderEntity powWowJournalHeaderEntity;
private List<PowWowTransactionEntity> powWowTransactionEntities = new ArrayList<>();
private List<PowWowAuditTrailEntity> powWowAuditTrailEntities = new ArrayList<>();
private PowWowJournalEntryObjectEntity powWowJournalEntryObjectEntity;
PowWowJournalHeaderEntity
#Entity
#Table(name = "powwowjournalheader")
public class PowWowJournalHeaderEntity {
I have model:
public class StudyModel {
#Id
private String ID;
private boolean isStable;
private String LastUpdate;
private MainTest test;
public static class MainTest {
private String test1;
private String test2;
}
}
I want to parse it to my model.
It works correctly but when it goes to MainTest where on json file I have couple values it fails and I have null on the rest of fields.
How I can deal with it?
public StudyModel getStudyDetails(String studyId){
RestTemplate restTemplate = new RestTemplate();
String url = URL + "studies/" + studyId;
ResponseEntity<String> serverResponse = restTemplate.getForEntity(url, String.class);
Gson g = new Gson();
String json = serverResponse.getBody();
StudyModel study = g.fromJson(json, StudyModel.class);
return study;
}
RestTemplate can handle deserialization for you
ResponseEntity<StudyModel> serverResponse = restTemplate.getForEntity(url, StudyModel.class);
StudyModel studyModel = serverResponse.getBody();
I am trying to map this Json response I consume through a secured RESTful API; however, the mapping is for some reason not happening correctly as I keep getting a NULL response instead of populated object.
This is my entity:
#JsonTypeName("order")
#JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT ,use = JsonTypeInfo.Id.NAME)
public class Order {
#JsonProperty("id")
private long customerd;
#JsonProperty("email")
private String customeEmail;
public long getCustomerd() {
return customerd;
}
public void setCustomerd(long customerd) {
this.customerd = customerd;
}
public String getCustomeEmail() {
return customeEmail;
}
public void setCustomeEmail(String customeEmail) {
this.customeEmail = customeEmail;
}
}
This is my service method:
public Order orderDetails (#RequestBody Order order){
String username = "username";
String password = "password";
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(username, password);
// request url
String url = "https://test.myshopify.com/admin/orders/2013413015655.json";
RestTemplate restTemplate = new RestTemplate();
HttpEntity request = new HttpEntity(headers);
ResponseEntity<Order> response = restTemplate.exchange(
url, HttpMethod.GET, request, Order.class);
return order;
}
This is my Controller Method:
#GetMapping("/orderdetails")
#ResponseStatus(HttpStatus.FOUND)
public Order getBasicAut(Order order){
return basicAuth.orderDetails(order);
}
You should configure your REST to produce the JSON content
#GetMapping(path = "/orderdetails", produces = {MediaType.APPLICATION_JSON_VALUE})
Specifically, those codes below work well
#RestController
public class JsonController {
#GetMapping(path = "/orderdetails", produces = {MediaType.APPLICATION_JSON_VALUE})
#ResponseStatus(HttpStatus.FOUND)
public Order sendJsonBack() {
final Order order = new Order();
order.setCustomerd(123L);
order.setCustomeEmail("mail#gmail.com");
return order;
}
}
#Data
class Order implements Serializable {
private static final long serialVersionUID = -4258392267221190600L;
#JsonProperty("id")
private long customerd;
#JsonProperty("email")
private String customeEmail;
}
The issue was with what my methods were returning. They both have to return a ResponseEntity of type Order as in:
public ResponseEntity<Order> orderDetails (#RequestBody Order order){
String username = "username";
String password = "password";
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(username, password);
// request url
String url = "https://test.myshopify.com/admin/orders/2013413015655.json";
RestTemplate restTemplate = new RestTemplate();
HttpEntity request = new HttpEntity(headers);
ResponseEntity<Order> response = restTemplate.exchange(
url, HttpMethod.GET, request, Order.class);
return response;
}
And my Controller to:
#GetMapping("/orderdetails")
#ResponseStatus(HttpStatus.FOUND)
public ResponseEntity<Order> getBasicAut(Order order){
return basicAuth.orderDetails(order);
}
I want to send to the controller a complex object consisting of files and simple types.
public class ContributionNew<T extends MovieInfoDTO> {
private List<T> elementsToAdd;
private Map<Long, T> elementsToUpdate;
private Set<Long> idsToDelete;
private Set<String> sources;
private String comment;
}
public class Photo extends MovieInfoDTO {
private MultipartFile photo;
}
#PostMapping(value = "/{id}/contributions/photos")
#ResponseStatus(HttpStatus.CREATED)
public
ResponseEntity<Void> createPhotoContribution(
#ApiParam(value = "The movie ID", required = true)
#PathVariable("id") final Long id,
#ApiParam(value = "The contribution", required = true)
#RequestBody #Valid final ContributionNew<Photo> contribution
) {
I want to create a test to send an object, but I do not know how to finish it.
#Test
public void testCreatePhotoContribution() throws Exception {
ContributionNew<Photo> contribution = new ContributionNew<>();
MockMultipartFile multipartFile = new MockMultipartFile("photo", "C:\\Users\\Jonatan\\Pictures\\2.png",
"image/png", "Spring Framework".getBytes());
Photo.Builder photoBuilder = new Photo.Builder(
multipartFile
);
contribution.getElementsToAdd().add(photoBuilder.build());
mockMvc
.perform(post("/api/v1.0/movies/{id}/contributions/photos", 1)
.contentType(...)
.content(...))
.andExpect(status().isCreated());
}
I do not know how to send such an object as #ResuestBody? I do not know how to finish this test.
You can do something like this.
ObjectMapper = new ObjectMapper(); // You can also Autowire this
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mockMvc
.perform(post("/api/v1.0/movies/{id}/contributions/photos", 1)
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(contribution)))
.andExpect(status().isCreated());
My question is kind of similar to Prevent GSON from serializing JSON string but the solution there uses GSON library and I am restricted to using Jackson (fasterxml).
I have an entity class as follows:
package com.dawson.model;
import com.dawson.model.audit.BaseLongEntity;
import lombok.extern.log4j.Log4j;
import javax.persistence.*;
#Table(name = "queue", schema = "dawson")
#Entity
#Log4j
public class Queue extends BaseLongEntity {
protected String requestType;
protected String body;
protected Queue() {
}
public Queue(String requestType, String body) {
this.requestType = requestType;
this.body = body;
}
#Column(name = "request_type")
public String getRequestType() {
return requestType;
}
public void setRequestType(String requestType) {
this.requestType = requestType;
}
#Column(name = "body")
#Lob
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}
I want to populate the body field with the json string representation of a map and then send this as part of the ResponseEntity. Something as follows:
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.writer().withDefaultPrettyPrinter();
HashMap<String, String> map = new HashMap<>(5);
map.put("inquiry", "How Can I solve the problem with Jackson double serialization of strings?");
map.put("phone", "+12345677890");
Queue queue = null;
try {
queue = new Queue("General Inquiry", mapper.writeValueAsString(map));
} catch (JsonProcessingException e) {
e.printStackTrace();
}
String test = mapper.writeValueAsString(map)
System.out.println(test);
Expected Output: "{"requestType": "General Inquiry","body": "{"inquiry":"How Can I solve the problem with Jackson double serialization of strings?","phone":"+12345677890"}"}"
Actual Output:"{"requestType": "General Inquiry","body": "{\"inquiry\":\"How Can I solve the problem with Jackson double serialization of strings?\",\"phone\":\"+12345677890\"}"}"
I am using
Jackson Core v2.8.2
I tried playing with
#JsonIgnore
and
#JsonProperty
tags but that doesn't help because my field is already serialized from the map when writing to the Entity.
Add the #JsonRawValue annotation to the body property. This makes Jackson treat the contents of the property as a literal JSON value, that should not be processed.
Be aware that Jackson doesn't do any validation of the field's contents, which makes it dangerously easy to produce invalid JSON.