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 {
Related
This question already has an answer here:
How to deserialize a JSON array with no name, using RestAssured?
(1 answer)
Closed 5 months ago.
I have created couple of POJO classes for serializing/deserializing. When I create a request to receive all categories I am expecting to receive an array of category objects. But I am getting the following error:-
Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type POJO.Categories from Array value (token JsonToken.START_ARRAY)
1. This is my test class and I try to map the response to my POJO class(model) but it gives me an error.
#Test(alwaysRun = true, priority = 1)
public void getUserDetail() {
String url = "http://localhost:8081/users";
RequestSpecification httpRequest = RestAssured.given()
.header("Content-Type", "application/json")
.contentType(ContentType.JSON);
Response response = httpRequest.get(url);
ResponseBody responseBody = response.getBody();
UsersResponseDetails b = responseBody.as(UsersResponseDetails.class);
softAssert.assertEquals(b.getId(), 1,"invalid");
softAssert.assertAll();
}
2. Error
java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `model.UsersResponseDetails` from Array value (token `JsonToken.START_ARRAY`)
at [Source: (String)"[{"id":1,"name":"litteleHelpByKR-1","dob":"2020-05-23T","addressDetails":{"houseNumber":"H-55","aadharNumber":32345,"addressLine1":"Mg Road-1","addressLine2":"12th Cross-1","landmark":"Near Airport Road","pin":1,"officeAddress":{"buildingNumber":3,"addressLine1":"XYZ-1","addressLine2":"Airport Road","landMark":"Near U turn signal","cardId":"EMP-001","pin":75943764}}}]"; line: 1, column: 1]
3. Used Jackson dependent but its not work
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.4</version>
</dependency>
4. API GET response
[
{
"id":1,
"name":"litteleHelpByKR-1",
"dob":"2020-05-23T",
"addressDetails":{
"houseNumber":"H-55",
"aadharNumber":32345,
"addressLine1":"Mg Road-1",
"addressLine2":"12th Cross-1",
"landmark":"Near Airport Road",
"pin":1,
"officeAddress":{
"buildingNumber":3,
"addressLine1":"XYZ-1",
"addressLine2":"Airport Road",
"landMark":"Near U turn signal",
"cardId":"EMP-001",
"pin":75943764
}
}
}
]
5. This model I created to map the response
#Getter
#Setter
public class UsersResponseDetails {
private int id;
private String name;
private String dob;
private AddressDetails addressDetails;
#Getter
#Setter
public static class AddressDetails {
private String houseNumber;
private int aadharNumber;
private String addressLine1;
private String addressLine2;
private String landmark;
private int pin;
private OfficeAddress officeAddress;
#Getter
#Setter
public static class OfficeAddress {
private int buildingNumber;
private String addressLine1;
private String addressLine2;
private String landMark;
private String cardId;
private int pin;
}
}
}
My suggesstion are:
If you want to work with array, then
UsersResponseDetails[] b = responseBody.as(UsersResponseDetails[].class);
softAssert.assertEquals(b[0].getId(), 1,"invalid");
If you prefer List, then
List<UsersResponseDetails> b= responseBody.as(new TypeRef<List<UsersResponseDetails>>() {});
softAssert.assertEquals(b.get(0).getId(), 1,"invalid");
I have multiple objects in my array using . If I then send this to my Spring Boot backend with axios and output the FormData beforehand, I get the following image. That fits. In the backend, however, I need this list of objects as an entity. In this case, of type List. Do I do that?
Frontend code:
let data = new FormData();
...
data.append("zugeordnet", JSON.stringify(personNamen));
await axios.post("/neuerEintrag", data,...)
React:
Backend:
#PostMapping("/neuerEintrag")
public String neuerEintrag(HttpServletRequest req,#RequestParam("zugeordnet") List<?> zugeordnet,..) {
List<User> userListe = (List<User>) zugeordnet;
for(User inListe : userListe) //ERROR here
{
System.out.println("USER :" + inListe);
}
...
}
java.lang.ClassCastException: class java.lang.String cannot be cast to class com.home.calendar.User.User
UPDATE
For completeness, here is the user entity and the complete method for a new entry.
#PostMapping("/neuerEintrag")
public String neuerEintrag(HttpServletRequest req, #RequestParam("beschreibung") String beschreibung,
#RequestParam("datum") Date datum, #RequestBody List<User> zugeordnet,
#RequestBody List<Freunde> kontaktAuswahl, #RequestParam("neuAlt") String neuAlt,
#RequestParam("kalenderId") int kalenderId) { }
The User Entity:
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
#JsonIgnoreProperties("user")
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "user")
private List<Kalender> kalenderEinträge;
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(String name, List<Kalender> kalenderEinträge) {
super();
this.name = name;
this.kalenderEinträge = kalenderEinträge;
}
public List<Kalender> getKalenderEinträge() {
return kalenderEinträge;
}
[getter/setter]
Spring can't parse an unknown object.
To get it work, I suggest a new class for the "request".
#Data // lombok - this generates getter/setters/equals/hashcode for you
public class NeuerEintragRequest {
private List<User> zugeordnet;
private String beschreibung;
private int kalendarId;
// and your others fields
}
The controller can now use very type-safe objects.
#PostMapping("/neuerEintrag")
public String neuerEintrag(#RequestBody NeuerEintragRequest request) {
for(User user : request.getUserlist()) {
// a logging framework is a lot better. Try to use log4j or slf4j.
log.info("USER: {}", user);
}
...
}
Typescript
Let axios handle the typing and serializing. See this tutorial: https://masteringjs.io/tutorials/axios/post-json
To post all the needed data, you can create a new object.
// no formdata - just send the object
const data = { zugeordnet: personNamen, kalendarId: 123, beschreibung: 'abc' };
await axios.post("/neuerEintrag", data);
You can also create a interface in typescript, but this is going to much for a stackoverflow-answer. Try to learn more about spring and typescript.
Based on question & comments ,
your front end call data.append("zugeordnet", JSON.stringify(personNamen)); is converting your object to List<String> instead of List<User>.
So you can transform this List<String> to List<User> in your postMapping:
#PostMapping("/neuerEintrag")
public String neuerEintrag(HttpServletRequest req,#RequestParam("zugeordnet") List<?> zugeordnet,..) {
ObjectMapper mapper=new ObjectMapper();
for(String str:zugeordnet){
System.out.println(mapper.readValue(str, User.class));
}
...
}
I need to receive a request from a webhook from a third party API.
Post content is an urlenconded in following format:
event=invoice.created&data%5Bid%5D=value1&data%5Bstatus%5D=pending&data%5Baccount_id%5D=value2
The problem is serialize this params data[id] with these square brackets. I'm getting an error in spring boot:
Invalid property 'data[account_id]' of bean class [br.com.bettha.domain.dto.IuguWebhookDto]: Property referenced in indexed property path 'data[account_id]' is neither an array nor a List nor a Map; returned value was [IuguDataDto(id=null, account_id=null, status=null, subscription_id=null)]
My controller:
#PostMapping(value = "/subscription-invoice", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
#ApiOperation(
value="Create a subscription invoice from Iugu's webhook",
response= Invoice.class,
notes="This Operation creates a subscription invoice from Iugu's webhook")
#PreAuthorize("#oauth2.hasScope('read')")
public ResponseEntity<Invoice> createSubscriptionInvoice(IuguWebhookDto iuguWebhookDto) {
try {
Invoice invoice = paymentService.createSubscriptionInvoiceFromIugusWebhook(iuguWebhookDto);
return new ResponseEntity<>(invoice, HttpStatus.CREATED);
} catch (EntityNotFoundException e) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage(), e);
} catch (Exception e) {
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage(), e);
}
}
IuguWebhookDto.java:
#Getter
#Setter
#NoArgsConstructor
#ToString
public class IuguWebhookDto implements Serializable {
private static final long serialVersionUID = -5557936429069206933L;
private String event;
private IuguDataDto data;
IuguDataDto.java:
#Getter
#Setter
#NoArgsConstructor
#ToString
public class IuguDataDto implements Serializable {
private static final long serialVersionUID = -5557936429069206933L;
private String id;
private String account_id;
private String status;
private String subscription_id;
How can I receive these request params as an object in Spring Boot?
I have the same problem using Iugu Webhooks API. To solve, i just stringify the raw data sent by Iugu, remove the unwanted characters, and then parse again the object to get the variables that i want.
var dataReceived = JSON.stringify(req.body).replace('data[id]','id').replace('data[status]','status').replace('data[account_id]','account_id');
var finalData = JSON.parse(dataReceived);
return res.status(200).send(finalData.id);
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));
I have two domain models mapped using Hibernate #OneToMany. I am trying to create a JSON object in the frontend and send it to the spring mvc controller to set the model data on its own.
Following are my model classes:
ConceptModelDetails.java
#Entity
#Table(name="conceptModelDetails")
#SequenceGenerator(name="CONCEPT_SEQ",sequenceName="concept_sequence", initialValue=1, allocationSize=1)
public class ConceptModelDetails implements java.io.Serializable{
private static final long serialVersionUID = 1L;
#Id #GeneratedValue(strategy = GenerationType.SEQUENCE, generator="CONCEPT_SEQ")
private int instructionsId;
private String operationType;
private String conceptModelID;
private String requestor;
private String status;
private Timestamp requestDateTime;
private Timestamp lastExecutedDateTime;
private Timestamp completedDateTime;
#OneToMany(fetch = FetchType.EAGER, cascade=CascadeType.ALL, mappedBy="conceptModelDetails")
#JsonManagedReference // nested exception is org.springframework.http.converter.HttpMessageNotWritableException:
//Could not write JSON: Infinite recursion
//The fix is to get Jackson to be able to handle bi-directional references
private List<Instructions> instructions = new ArrayList<Instructions>();
public ConceptModelDetails() {
// TODO Auto-generated constructor stub
}
//setter & getter methods
}
and Instructions.java:
#Entity
#Table(name="instructions")
#SequenceGenerator(name="INSTRUCTIONS_SEQ", sequenceName="instructions_sequence",initialValue=1, allocationSize=1)
public class Instructions implements java.io.Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator="INSTRUCTIONS_SEQ")
private int Sno;
private String instruction;
#ManyToOne
#JoinColumn(name="instructionsId")
#JsonBackReference
private ConceptModelDetails conceptModelDetails;
//setter & getter methods
}
This is my send method at frontend to create and send the JSON object:
$scope.send = function() {
console.log("test");
var dataObj = {
"operationType" : $scope.operationType,
"conceptModelID" : $scope.conceptID,
"requestor" : $scope.requestor,
"status" : "new",
"requestDateTime" : null,
"lastExecutedDateTime" : null,
"completedDateTime" : null,
"instructions" : null
};
console.log(dataObj);
dataObj.instructions = [];
console.log($scope.operations_publish);
var ins = getSelected();
for ( var i in ins) {
var temp = {
instruction : null,
conceptModelDetails : null
}
temp.instruction = ins[i];
dataObj.instructions.push(temp);
}
var response = $http.post(
'PostService', dataObj);
response.success(function(data, status, headers, config) {
$scope.responseData = data;
});
response.error(function(data, status, headers, config) {
alert("Exception details: " + JSON.stringify({
data : data
}));
});
}
Following is my controller:
#RequestMapping(value = "/PostService", method = RequestMethod.POST)
public #ResponseBody String Test(#RequestBody ConceptModelDetails conceptModelDetails){
ApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
ConceptModelDAO obj = (ConceptModelDAO) context.getBean("objDAO");
System.out.println("concept id: "+conceptModelDetails.getConceptModelID()+" "+ conceptModelDetails.getInstructionsId());
System.out.println("instructions id: "+conceptModelDetails.getInstructions());
// ConceptModelDAOImpl objDAO = new ConceptModelDAOImpl();
obj.add(conceptModelDetails);
Instructions instructions = new Instructions();
System.out.println("dimba: " + instructions.getInstruction());
ArrayList<Instructions> operations = (ArrayList<Instructions>) conceptModelDetails.getInstructions();
for (int i = 0; i< operations.size(); i++ ) {
instructions.setInstruction(operations.get(i).getInstruction());
instructions.setConceptModelDetails(conceptModelDetails);
obj.addInstructions(instructions);
}
return null;
}
I am getting the eror: 400 (Bad Request) because of List<Instructions> instructions. Please suggest how do I deal with this.
I have found the problem in this code. As explained by Bozho here,
ArrayList<Instructions> operations = (ArrayList<Instructions>) conceptModelDetails.getInstructions();
should be
List<Instructions> operations = conceptModelDetails.getInstructions();
in the spring controller.