I am working currently on a project and I need to send a POST request to spring. I looked or several hours already for a solution and didn't find one to work. The request worked when I developed that part. The problem is that after creating some new functionalities(2 new endpoint in another controller) the POST requests for creating or updating the entities stopped working without changing code in the specific area.
The Controller:
#RestController
#CrossOrigin
#RequestMapping
public class SensorController {
#PostMapping(value = "/createSensor", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<UUID> insertSensor(#RequestBody SensorDto sensorDto){
UUID sensorId = sensorService.createSesor(sensorDto);
return new ResponseEntity<>(sensorId,HttpStatus.CREATED);
}
}
The part with consumes and produces wasn't there originally, I tried it because saw on other posts but doesn't helped the situation.
The SensorDto:
public class SensorDto extends RepresentationModel<SensorDto> {
private UUID id;
private String description;
private Integer maxValue;
private Device device;
The call from POSTMAN:
image
The headers: headers
Can someone help me to get it to work again?
EDIT: The code asked from the other controller
#PostMapping("/addSensorToDevice")
public ResponseEntity<UUID> addSensor(#RequestBody DeviceSensorLinkDto deviceSensorLinkDto){
System.out.println("OOO: " + deviceSensorLinkDto.toString());
if(deviceService.addSensor(deviceSensorLinkDto)){
return new ResponseEntity<>(deviceSensorLinkDto.getDeviceId(), HttpStatus.OK);
}else {
return new ResponseEntity<>(deviceSensorLinkDto.getDeviceId(), HttpStatus.EXPECTATION_FAILED);
}
}
#PostMapping("/addClientToDevice")
public ResponseEntity<UUID> addClient(#RequestBody DeviceClientLinkDto deviceClientLinkDto){
System.out.println("OOO: " + deviceClientLinkDto.toString());
if(deviceService.addClient(deviceClientLinkDto)){
return new ResponseEntity<>(deviceClientLinkDto.getDeviceId(), HttpStatus.OK);
}else {
return new ResponseEntity<>(deviceClientLinkDto.getDeviceId(), HttpStatus.EXPECTATION_FAILED);
}
}
And this one works and also the requests for deleting a Sensor entity.
It seems that you have multiple #JsonBackReference and #JsonManagedReference in your application and as a consequence, you must provide a name for all pairs as follows:
#JsonBackReference(value = "something")
#JsonManagedReference(value = "something")
#JsonBackReference(value = "something-else")
#JsonManagedReference(value = "something-else")
You can find some information about this in the reference documentation:
Logical have for the reference property pair; used to link managed and
back references. Default name can be used if there is just single
reference pair (for example, node class that just has parent/child
linkage, consisting of one managed reference and matching back
reference).
Related
For some reason java can't map DTO with requestBody and all values are default ones, as for request it works, with payload for ex. "{"productId":1,"commitment":6,"returnMonths":"2"}"
DTO
#Data
public class Request {
private int productId;
private int commitment;
private String returnMonths;
// contructers
}
Controller :
#PostMapping(value = "/calculate", consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public String calculatePrice(#RequestBody Request request) {
productService.calculatePrice(request);
return "Success";
}
front request:
submit: async function() {
let request = {
productId: this.productSelected,
commitment: this.optionSelected,
returnMonths: this.input
};
let data = await getCalculation(request);
console.log(data);
}
DTO maps as:
productId : 0
commitment : 0
returnMonths : null
Tried an exact copy of your code and it worked when tested with Postman. This makes me think it's either something to do with the FE or maybe some issue in the service. I'd check if the Frontend really sends the data.
Try to annotation Request class with #AllArgsConstructor like:
#AllArgsConstructor
#Data
public class Request {
private int productId;
private int commitment;
private String returnMonths;
}
If your request body contains properties that is date such as LocalDateTime, make sure to format it in your DTO using #JsonFormat(pattern="") respecting the input value.
I have some problem with getting response from external resources with RestTemplate.
What I want to get is data from PokemonApi: https://pokeapi.co/api/v2/type/
I thought about creating 2 Classes that will contain that data(Not using Object and headers)
My 2 classes are like:
#JsonIgnoreProperties(ignoreUnknown = true)
public class MainResponse {
#JsonProperty("typeList")
private List<PokemonType> pokemonTypes;
}
#JsonIgnoreProperties(ignoreUnknown = true)
public class PokemonType {
#JsonProperty("name")
private String pokemonType;
}
What problem I got is that I can't extract any data from my RestTemplate class:
public MainResponse response() {
Optional<MainResponse> search = Optional.ofNullable(
restTemplate.getForObject("https://pokeapi.co/api/v2/type", MainResponse.class)
);
return search.orElseGet(MainResponse::new);
}
I'm not sure why its not working right. I can't get any response and everything is ending in errors when I try get response. Please someone look at that and give me some pointers.
It will be surely eyeopener for all RestTemplates in the future for me :) Thanks alot.
I should migrate some code from jax-rs to spring mvc. We had a controller, which response with an object and set at the same time links in a list :
HateoasResponse.ok(content)
.selfLink(FieldPath.path("categories"), "some_controller_id", "id")
.build()
Did any one know, if there is something similar in spring mvc ?
I have checked spring-hateoas. If I use it , I should modify my models to something supported by this package (CollectionModel, EnitityModel..)
You have to make the response object extend ResourceSupport and then generate the links as follows.
org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo(methodOn(YourSpringMvcController.class)
.methodWhichHasMappingTo(param1,param2,paramN))
.withRel("relationOfThisLinkToTheRequestedResource").expand();
This link can then be added to the response object using the resource add method.
for example, let's say you have a controller like the following:
#RestController
public class OrderController {
#GetMapping(value = "/orders/{orderId}", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<Order> getOrder(#Valid #PathVariable Integer orderId) {
return getOrder(orderId);
}
#DeleteMapping(value = "/orders/{orderId}", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<Order> deleteOrder(#Valid #PathVariable Integer orderId) {
return orderRepo.deleteOrder(orderId);
}
}
then for a request to GET orders, you would build the response like the following:
Order which is a response entity will extend ResourceSupport
public Order getOrder(int orderId){
Order order = repo.findByOrderId(orderId);
Link deleteLink = ControllerLinkBuilder.linkTo(methodOn(OrderController.class)
.deleteOrder(orderId))
.withRel("delete").expand();
order.add(deleteLink);
Link selfLink = ControllerLinkBuilder.linkTo(methodOn(OrderController.class)
.getOrder(orderId))
.withSelfRel();
order.add(selfLink);
return order;
}
Hope this helps.
I am trying to write an integration test for my spring application, I have an api which insert some default data, I run call this api after my test gets initialized
#PostConstruct
public void inti() {
ResponseEntity<String> response = restTemplate.getForEntity("/api/default", String.class);
assertEquals("Default values are not inserted successfully", "lala", response.getBody());
}
This passed and I can see in the database default values.
In my test I try to fetch some data but the returned data is 0 although I tested the api manually and its working
#Test
public void shouldReturnDeliveryNotes() {
ResponseEntity<PagedResources<DeliveryNote>> allDeliveryNotes = restTemplate.exchange("/api/deliverynotes/all?start=0&length=1000",HttpMethod.GET,null, new ParameterizedTypeReference<PagedResources<DeliveryNote>>() {});
assertNotEquals("Should have default delivery notes", 0, allDeliveryNotes.getBody().getContent().size());
}
I put some log in the api to see the returned data size and I see the returned data when the test is run is correct which means my test is hitting the right api and the api fetch the data.
#GetMapping("/all")
public ResponseEntity<Page<DeliveryNoteDTO>> getAllDeliveryNote(#RequestParam(value = "start", required = false) int start, #RequestParam(value ="length", required = false) int length) {
Pageable pageable = new OffsetBasedPageRequest(start, (length ==0? Integer.MAX_VALUE: length));
List<DeliveryNote> page = this.deliveryNoteService.getAllDeliverNotes();
List<DeliveryNoteDTO> dtoList =page.stream().map(post -> convertToDto(post)).collect(Collectors.toList());
Page<DeliveryNoteDTO> pageDto = new PageImpl<>(dtoList, pageable, dtoList.size());
System.out.println("size = "+pageDto.getNumberOfElements());
return new ResponseEntity<Page<DeliveryNoteDTO>>(pageDto,HttpStatus.OK);
}
Any help is appreciated
The problem is I am returning Page while in my restTemplate I am expecting PagedResources, it would make sense to just return page but I need a concrete class , I would use PageImpl but the problem is that PageImple does not have a default constructor which RestTemplate use to map the response, so What I did I created a new class and extended the PageImpl just as mentioned in the accepted answer of this question
Spring RestTemplate with paginated API
I have the following controller method:
#RequestMapping(value = "/v1/users/{userId}/settings", method = RequestMethod.POST, produces = { "application/json" }, consumes = { "application/json" })
#ResponseStatus(value = HttpStatus.CREATED)
#ResponseBody
public UserSetting createUserSetting(#PathVariable("userId") String userId,
#RequestBody Setting setting){
return userSettingService.createSetting(userId, userSetting);
}
When invoking the url /v1/users/12345/settings POST
with the payload
{"Setting":{"name":"CoolSetting", "id":"SETTING-ID"}}
the method behaves as expected.
What I would also like to accept is:
{"name":"CoolSetting", "id": "SETTING-ID"}
how do I accept the second payload version without the root tag.
The object in question looks like this
public class Setting{
#JsonProperty
private String id;
#JsonProperty
private String name;
//getters and setters removed
}
how can I tell spring to marshel using either json method?
You can use DeserializationConfig.Feature.UNWRAP_ROOT_VALUE property to achieve this result. For serialization use SerializationConfig.Feature.WRAP_ROOT_VALUE.
Detailed explanation and usage available in this blog: Jackson with and without root node