Spring Request Mapping post vs put, same method, same logic, but - spring

I have a 2 method:
first one create product:
#RequestMapping(method = RequestMethod.POST)
public ResponseEntity<?> create(#Validated ProductDTO productDTO){
productService.addProduct(productDTO);
return new ResponseEntity<>("Maxsulot ro'yhatga qo'shildi", HttpStatus.OK);
}
another one update product:
#RequestMapping(method = RequestMethod.PUT)
public ResponseEntity<?> update(#Validated ProductDTO productDTO){
productService.update(productDTO);
return new ResponseEntity<>("Maxsulot ma'lumotlari yangilandi", HttpStatus.OK);
}
Now, I am surprized that, if I sent same data post method works fine(screen1), but put(screen2) method return validation error.
screen1(post)
screen2(put)
What the problem is?
MyDTO class:
public class ProductDTO {
private Long id;
private MultipartFile file;
#NotNull
#Size(min = 2, max = 50)
private String productName;
#NotNull
private Long productPrice;
private String productInfo;
#NotNull
private Long categoryId;
private String unitOfMeasurement;
// getters and setters
}

I can see you have #Validated that should validate your request body according to JSR-303.
Seems like it is not consistent when you POST and PUT. It validates/not validating and return an error because your body does not match the validation rules you placed on ProductDTO.
In all the docs I saw you should do something like #Valid #RequestBody instead of just putting #Validated.
Try to change it to the above and see if it now work more consistently.

Related

JPA calling default constructor even during POST request

I didn't had a default constructor in my entity class in the beginning. Eventually found out that JPA requires a default constructor in entity class so I made one.
After adding the default constructor, even during post requests, JPA keeps calling default constructor which leads to incorrect initialisation of properties. For example, if you see the property called availableSeats, it is initialised to 100, but during post request only default constructor is called which leads to initialisation of availableSeats to 0.
This is extremely weird and I don't understand what am I doing wrong here.
#Entity
public class Flight {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotBlank(message = "Airline Name cannot be blank!")
private String airlineName;
#NotBlank(message = "From-Location cannot be blank!")
private String fromLocation;
#NotBlank(message = "To-Location cannot be blank!")
private String toLocation;
#NotBlank(message = "Airport Gate Number cannot be blank")
private String gateNumber;
// #NotBlank(message = "Boarding time cannot be blank")
private ZonedDateTime dateTimeZone;
private static final int INITIAL_SEAT_CAPACITY = 100;
private int availableSeats;
// constructor should not be able to set id
public Flight(Long id, String airlineName, String fromLocation, String toLocation, String gateNumber, ZonedDateTime dateTimeZone, int availableSeats) {
this.id = id;
this.airlineName = airlineName;
this.fromLocation = fromLocation;
this.toLocation = toLocation;
this.gateNumber = gateNumber;
this.dateTimeZone = dateTimeZone;
// setting up initial number of available seats
this.availableSeats = INITIAL_SEAT_CAPACITY;
}
public Flight(){
}
// getters and setters
}
Also adding FlightController.java code here
#RestController
#RequestMapping("/api/flights")
public class FlightController {
#Autowired
FlightService flightService;
#GetMapping(value = "/")
public ResponseEntity<List<Flight>> getAllFlights(){
return flightService.getAllFlights();
}
#PostMapping(value = "/")
public ResponseEntity<String> createFlight(#Valid #RequestBody Flight flight){
return flightService.createFlight(flight);
}
#GetMapping(value = "/{id}")
public ResponseEntity<Flight> getFlightById(#PathVariable Long id){
return flightService.getFlightById(id);
}
#DeleteMapping(value = "/{id}")
public ResponseEntity<String> deleteFlight(#PathVariable Long id){
return flightService.deleteFlight(id);
}
}
Spring's controller uses default(zero argument) constructor for object creation and then uses it's setter methods for setting the values in the object. You cannot expect for spring to use parameterized constructor.
So if you need to set some default values then do it in zero argument constructor.
As #grigouille pointed out in the comments, JPA only uses default constructor. Hence, availableSeats should have been initialised in the default constructor too.

Why do I get Status 400, Bad Request on my POST URL (using postman)

I am trying to follow a Spring Boot Tutorials on youtube and I get stuck at Post.
I tried searching for fix but I can't find an specific answer why I can't access the post URL?
I tried both #PostMapping and #RequestMapping(Method = POST)
still same results.
Maybe I am accessing my URL wrong?
I am trying to Post at /api/sis/student_reg
need help, thanks!
#RestController
#RequestMapping(path = "/api/sis")
public class StudentController {
#Autowired
private StudentService studentService;
#GetMapping(path = "/student")
public List<Student> displayStudent(){
return studentService.getStudent();
}
#RequestMapping(method = RequestMethod.POST, value = "/reg_student")
public void registerStudent(#RequestBody Student student){
studentService.addStudent(student);
}
}
#Service
public class StudentService {
#Autowired
private StudentRepository studentRepository;
private Student students = new Student();
public List<Student> getStudent(){
List<Student> student = new ArrayList<>();
studentRepository.findAll()
.forEach(student::add);
return student;
}
public void addStudent(Student student){
studentRepository.save(student);
}
#Entity
#Table
public class Student {
UUID uuid = UUID.randomUUID();
#Id
#SequenceGenerator(
name = "student_sequence",
sequenceName = "student_sequence",
allocationSize = 1
)
#GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "student_sequence"
)
private String id;
private String FirstName;
private String LastName;
private String email;
// Method Converting UUID into string
public String genID(){
id = uuid.toString();
return id;
}
//Constructor, getters and setters
Edited again:
I receive error 400 when using the "Post" while 405 "Get" on the post URL.
apologies for the confusion.
It is not about wrong url. If that would have been the case you would get 404 Not Found error and not 400 i.e., Bad Request.
This means your request is not proper. Can you please also update the whole request body which you are using in postman and also attributes of your Student Class.

Spring Validation Doesn't Work With Generic Types

In my code block, I just want to validate a controller method with Spring boot #Valid annotation for a generic Pair object. But the validation doesn't work for me.
My Controller method looks like this:
#RequestMapping(method = RequestMethod.POST, consumes = "application/json")
public void add(#RequestBody #Valid Pair<AddDto, AddUserDto> pair)
{
...
service.add(pair);
}
Pair object looks like:
public class Pair<F, S>
{
private F first;
private S second;
}
AddDto object looks like:
public class AddDto
{
#NotNull
private String name;
#NotEmpty
private List<String> actionList;
...getters, setters
}
AddUserDto object looks like:
public class AddUserDto
{
#NotNull
private String name;
#NotNull
private Long id;
...getters, setters
}
In this case, validation doesn't work for me. Is there any suggestion?
It has nothing to do with generics. The problem is that the Pair class does not define any validation rules. Try changing it to:
public class Pair<F, S>
{
#Valid
#NotNull
private F first;
#Valid
#NotNull
private S second;
}

Spring MVC Based Rest Services Validations for request body

I have Rest Controller in my application which has the code snippet like below:-
#RestController
#RequestMapping("/api/v1/user")
public class UserRestControllerV1 {
#PostMapping("")
public Response registerUser(#RequestBody #Valid final Request<UserDto> request,
final HttpServletRequest httpServletRequest,
BindingResult result){
Response response = new Response(request);
if(result.hasErrors()){
response.setData(new String("Error"));
}else {
response.setData(new String("Test"));
}
return response;
}
The Request Class:-
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Request<T> {
#JsonProperty(value = "co-relation-id")
private String coRelationID;
#NotNull(message = "The request body should be present")
private T data;
/*
..... various other fields
Getters / Setters
*/
}
The UserDto Class :-
public class UserDto {
#NotNull(message = "The username should not be null")
private String username;
#NotNull(message = "The password should not be null")
#JsonIgnore
private String password;
/*
..... various other fields
Getters / Setters
*/
}
Issue : I am having issues with my validations here. The field private T data in the request class gets validated but the fields inside T - in the case UserDto are not getting validated.
So I need to know the approach or code snippet to achieve this.
I have tried configuring the hibernate validator bean in the configuration but it is of no help in the scenario
#Valid constraint will instruct the Bean Validator to delve to the type of its applied property and validate all constraints found there.
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Request<T> {
#JsonProperty(value = "co-relation-id")
private String coRelationID;
//#NotNull(message = "The request body should be present")
#Valid
private T data;
/*
..... various other fields
Getters / Setters
*/
}

How to handle POST restful webservice in Spring MVC which consume and produce data and image both

I am developing webservice which contain some information with image , for example , develop webservice which contain user information with photo. I want this done by POST request. How can I achieve this?
I want to store only image path in database.
What changes should i make in controller to retrive image from mobile and store it in database? I am taking UserInfoTemp object as request body.
To developing webservice I am using Spring MVC 4.0.3.Release.
Here is my code please review it:
#Entity
public class UserInfoTemp
{
#Id
#GeneratedValue
#Column(name="UserId")
private Long id;
#Column(name="FirstName")
private String firstName;
#Column(name="LastName")
private String lastName;
#Column(name="Email")
#JsonProperty(value="email")
private String email;
#Column(name="Phone")
private String phone;
#Column(name="ProfilePicLink")
private String profilePicLink;
#Column(name="ProfilePicThumbnailLink")
private String profilePicThumbnailLink;
//getter setter
}
Controller:-
// for registering user
#RequestMapping(value = "/register", method = RequestMethod.POST)
public ResponseEntity<Object> register(#RequestBody UserInfoTemp userInfoTemp)
{
try
{
userInfoService.save(userInfoTemp);
return new ResponseEntity<Object>(userInfoTemp, HttpStatus.CREATED);
}
catch(Exception e)
{
Message message = new Message();
message.setStatus(false);
message.setMessage("User information can not be null");
return new ResponseEntity<Object>(message, HttpStatus.CREATED);
}
}

Resources