I know this issue has been around there in other post, but after applying the fiux suggested was not working.
I am using spring 4.1.7 version, i want to validate the RequestBody from post rest call. For doing this i tried following set of codes, but it was not working as i expected.
My Request body pojo classes.
ParentPojo.class
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Builder
#ToString
#Validated
public class ParentPojo<T> implements Serializable{
#NotNull
private String cNumber;
#NotNull
private String statusCode;
#NotNull T child;
}
ChildPojo.class
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
#Builder
#ToString
#Validated
public class ChildPojo{
#NotNull
private String name;
#NotNull
private String address;
#NotNull
private String pin;
}
Controller:
Adding only methods
#Autowired
#Qualifier("validator")
private Validator validator;
#InitBinder
private void initBinder(WebDataBinder binder) {
binder.setValidator(validator);
}
#RequestMapping(produces = { "application/json", "application/xml" }, consumes ={MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}, method = { RequestMethod.POST })
#ResponseStatus(HttpStatus.CREATED)
public Messageresponse<ChildPojo> create(#NotNull(groups = {ParentPojo.class, ChildPojo.class})
#Valid #Validated({ParentPojo.class, ChildPojo.class}) #RequestBody final ParentPojo<ChildPojo> ParentPojo, BindingResult bindingResult) {
System.out.println("new version 8="+bindingResult.hasErrors());
validator.validate(ParentPojo, bindingResult);
if(bindingResult.hasErrors()) {
System.out.println("Non formated form stuff.");
}
return service.create(ParentPojo);
}
#RequestMapping(value = "/{create}", produces = { "application/json", "application/xml" }, consumes ={MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}, method = { RequestMethod.POST })
#ResponseStatus(HttpStatus.CREATED)
public Messageresponse<ChildPojo> create1(#NotNull #Valid #RequestBody final ParentPojo<ChildPojo> ParentPojo, BindingResult bindingResult) {
System.out.println("new version 8="+bindingResult.hasErrors());
validator.validate(ParentPojo, bindingResult);
if(bindingResult.hasErrors()) {
System.out.println("Non formated form stuff.");
}
return service.create(ParentPojo);
}
application context xml:
<mvc:annotation-driven validator="validator">
</mvc:annotation-driven>
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
jar file tried:
hibernate-validator-4.3.0.Final
hibernate-validator-4.1.0.Final
hibernate-validator-4.0.2.GA
validation-api-1.1.0.Final
spring-context-4.1.7.RELEASE
But nothing was working with all the above combination for the request below:
in below request "pin" is missed and the controller method #Valid #RequestBody expected to handle this request as Bad Request. instead it is accepting the request body and processing further.
{
"cNumber" : "ff",
"statusCode" : "ddd",
"child" : {
"name" : "ll",
"address" : "ll"
}
Look at this question Here
You need to decorate the child pojo as #Valid
public class ParentPojo<T> implements Serializable{
#NotNull
private String cNumber;
#NotNull
private String statusCode;
#Valid
#NotNull
T child;
}
Related
I've done the following Thymeleaf form which takes some fields and a .pdf CV file
Form: link
There is the controller:
#Controller
#RequestMapping("/interview")
public class InterviewController {
#PostMapping(path = "/create", consumes = { MediaType.MULTIPART_FORM_DATA_VALUE })
public #ResponseBody ResponseEntity<Object> createInterview(#RequestBody #ModelAttribute CreateInterviewTO createInterviewTO) {
ErrorRTO errorRTO = checkErrorsInsertInterview.validate(createInterviewTO);
//...Other
}
}
And at the end, DTO class:
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class CreateInterviewTO {
private String site;
private String candidateName;
private String candidateSurname;
private Date candidateBirth;
private String mail;
private String eduQualification;
private String candidateType;
private String interviewType;
private String enterpriseId;
private MultipartFile curriculum;
}
When I send the request, I receive the following error:
w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported]
UPDATE: when I sent request, curriculum DTO attribute is null.
Anyone has a solution?
I have a simple Spring Boot controller with a simple Object, which is annotated with Lombok, when I tried to post data to the controller the object to not serializing.
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
#EqualsAndHashCode(callSuper = true)
#ToString(callSuper = true)
public class Employee extends BaseDomain {
private String firstName;
private String middleName;
private String lastName;
private String email;
private String mobileNo;
#PostMapping
public Employee saveEmployee(Employee employee) {
log.debug("Employee save {}", employee);
return employeeService.saveOrUpdateEmployee(employee);
}
}
#PostMapping
public Employee saveEmployee(#Requestbody Employee employee) {
log.debug("Employee save {}", employee);
return employeeService.saveOrUpdateEmployee(employee);
}
#Requestbody is missing
I have a Bean,
#Data
#NoArgsConstructor
public final class PersonRequest {
#NotNull
#JsonProperty("nameList")
private List<Person> nameList;
}
and Person POJO,
#Data
public class Sensor {
#NotNull
#JsonProperty("id")
private int id;
#NotNull
#JsonProperty("name")
#Min(1)
private String name;
}
I am sending JSON request and added #Valid in my controller. I am sending request as below,
{
"nameList": [
{
"id": 1,
"name": "John"
},
{
"id": 2,
"name": "Alex"
}
]
}
When i send request without id and name not validating. I tried using #Valid private List<Person> nameList; also but no luck. I use Spring boot 2.3.2.
UPDATED:
when i add one more attribute, this also say bad request when i pass date in request.
#NotNull
#JsonProperty("startTime")
#DateTimeFormat(pattern = "yyyy-MM-dd'T'hh:mm:ss", iso =
DateTimeFormat.ISO.DATE_TIME)
#Valid
private LocalDateTime startTime;
The #Valid annotation in your controller triggers the validation of the PersonRequest object, passed as request body. To validate also the Person objects contained in PersonRequest, you need to annotate that field with #Valid too.
#Data
#NoArgsConstructor
public final class PersonRequest {
#NotNull
#JsonProperty("nameList")
#Valid
private List<Person> nameList;
}
I am working on Spring REST API and have following controller:
#RestController
#RequestMapping(
value = "/api/Test",
produces = "application/json"
)
public class MyController {
#RequestMapping(method = RequestMethod.POST)
public Response serviceRequest(#Valid #RequestBody ServiceRequest myServiceRequest) {
....
}
}
ServiceRequest has following structure:
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
public class ServiceRequest {
#NotBlank
private LocalDate fromDate;
#NotBlank
private LocalDate toDate;
}
My task is to introduce validation based on combination of fromDate and toDate field's values: if time period between them is longer that 1 week then validation should fail.
What is the best way to archive this please?
You may create a custom constraint validator that will validate the required conditions before processing the request.
DatesDifference.java
#Constraint(validatedBy = DatesDifferenceValidator.class)
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface DatesDifference {
String message() default "Dates difference is more than a week";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
DatesDifferenceValidator.java
#Component
public class DatesDifferenceValidator implements ConstraintValidator<DatesDifference, ServiceRequest> {
#Override
public boolean isValid(ServiceRequest serviceRequest, ConstraintValidatorContext context) {
System.out.println("validation...");
if (!(serviceRequest instanceof ServiceRequest)) {
throw new IllegalArgumentException("#DatesDifference only applies to ServiceRequest");
}
LocalDate from = serviceRequest.getFromDate();
LocalDate to = serviceRequest.getToDate();
long daysBetween = ChronoUnit.DAYS.between(from, to);
System.out.println("daysBetween "+daysBetween);
return daysBetween <= 7;
}
}
ServiceRequest.java
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#DatesDifference
public class ServiceRequest {
#NotBlank
private LocalDate fromDate;
#NotBlank
private LocalDate toDate;
}
In my controller I have annotated the request parameter with the #Valid annotation and the field of my DTO with the #NotNull annotation, but the validation doesn't seem to work.
Are there any configurations to do in order to proceed with the validation? Following there are the Controller and the DTO class details.
#RepositoryRestController
#RequestMapping(value = "/download_pdf")
public class PurchaseController {
#Autowired
private IPurchaseService iPurchaseService;
#Loggable
#RequestMapping(value = "view_order", method = RequestMethod.POST)
public ResponseEntity getPDF(#RequestBody #Valid CustomerOfferDto offer,
HttpServletResponse response) {
return iPurchaseService.purchase(offer, response);
}
}
public class CustomerOfferDto {
#NotNull
private String agentCode;
// getter and setter...
}
Following are the steps I did to make it work.
Add dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Constraints in DTO class:
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#ValidTaskDTO
public class TaskDTO {
#FutureOrPresent
#NotNull(message = "DueDate must not be null")
private ZonedDateTime dueDate;
#NotBlank(message = "Title cannot be null or blank")
private String title;
private String description;
#NotNull
private RecurrenceType recurrenceType;
#Future
#NotNull(message = "RepeatUntil date must not be null")
private ZonedDateTime repeatUntil;
}
RestController method with #Valid annotation on requestBody argument:
#RestController
#RequestMapping("/tasks")
#Validated
public class TaskController {
#PostMapping
public TaskDTO createTask(#Valid #RequestBody TaskDTO taskDTO) {
.....
}
}
On making a POST request with requestbody containing null value for dueDate, I got the expected error message as shown below.
{
"timestamp": "2021-01-20T11:38:53.043232",
"status": 400,
"error": "Bad Request",
"message": "DueDate must not be null"
}
I hope this helps. For details on class level constraints, hav a look at this video.
In my projects, this usually happens when I change my code from lets say Entity to DTO and forget to add #ModelAttribute to my DTO parameter.
If this also happened to you, try adding #ModelAttribute("offer") to your DTO parameter.