Spring Boot List of Object Bean Validation - spring-boot

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;
}

Related

Spring Framework Responses from POST

What is the standard object design for accepting a POST request from a client, saving the record to the database, and then returning a response back to the client? I'm working with the Spring framework.
Should I be sending back the entity and hiding properties that aren't necessary for the response?
#RestController
public class SomeController {
private final SomeService service;
#PostMapping(value = "/post/new", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<SomeEntity> post(#RequestBody final SomeEntity someEntity) {
SomeEntity savedEntity = service.save(someEntity);
return ResponseEntity.ok(savedEntity);
}
}
#Entity
#Table(name = "posts")
public class SomeEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "title")
private String title;
#Column(name = "body")
#JsonIgnore
private String body;
#JsonIgnore
#Column(name = "deleted_ind")
private boolean deleted;
#JsonIgnore
#Column(name = "author")
private String author;
#Column(name = "created_at")
private LocalDateTime createdAt;
}
or would I accept some sort of POST request object that I convert to an entity, then re-assemble the entity into a response?
#JsonIgnoreProperties(ignoreUnknown = true)
public class SomePostRequestResource {
private String title;
private String body;
private String createdAt;
}
#RequiredArgsConstructor
#RestController
public class SomeController {
private final SomeService service;
private final SomeResourceAssembler resourceAssembler;
#PostMapping(value = "/post/new", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<SomePostRequestResource> post(
#RequestBody final SomePostRequestResource someResource
) {
SomeEntity savedEntity = service.convertToEntityAndSave(someResource);
SomePostRequestResource response = resourceAssembler.toResource(savedEntity);
return ResponseEntity.ok(response);
}
}
But then maybe I only want to send back the createdAt, would I hide the other properties in the SomePostRequestResource, or do I need another object to represent the response, which only has the property I want to send back?
I would also appreciate any book or article suggestions related to desigining objects for use with a RESTful API. I have seen articles concerning how to design and name the endpoints, but not so many concerning how to design the objects on the backend.
I would recommend you create a DTO class for the incoming/outgoing data containing the filed that are set/viewable by the client like:
public class SomeEntityIncomingDto {
private String title;
....
}
public class SomeEntityOutgoingDto {
private Long id;
private String title;
....
}
On the other hand, You won't need to map your persistence entities to DTOs and vice versa manually, you can use a library like ModelMapper or MapStruct that handles the conversion automatically.

Spring Requestbody JSON Deserializer not mapping the value

I have a problem where JSON data is not mapping to the Entity and it displays "selectedOption" as null.
Following Spring REST Contoller Method saves the order.
#RequestMapping(value = "/saveOrder")
public Long saveOrder(#RequestBody CustOrder order) {
return shopService.saveCustomerOrder(order);
}
Following is the JSON which is being sent to the method
{
"order":[
{
"selectedOption":{
"id":6,
"productOptionDescription":"Groß, Ø30cm:",
"optionPrice":null,
"optionPriceForSmall":null,
"optionPriceForNormal":6.7,
"optionPriceForFamily":null,
"optionPriceForParty":null,
"isDefault":true
}
}
]
}
Entity CustOrder
#Entity
public class CustOrder {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#OneToMany
#JoinColumn( name="custorder_id")
private Set<OrderItem> order=new HashSet<>();
}
Entity Order Item
#Entity
public class OrderItem {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#OneToOne
private ProductOption selectedOption;
}
I am struggling to understand why selectedOption is null.
Could someone help me with this.
Below is the screenshot from REST Controller Method (Eclipse)

Spring 4.1.7 validate request body

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;
}

Spring Boot validation of RequestBody Dto annotated in Rest API

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.

Spring MVC with Hibernate Validator Mandatory for the database field, but not in the application

Problem with BindingResult hasErrors() in validation.
I have this code:
#RequestMapping(value = "/entity", params = "form", method = RequestMethod.POST)
public String submit(#Valid #ModelAttribute Entity entity, BindingResult result) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
entity.setCreatedBy(auth.getName());
if (result.hasErrors()) {
//Here the error of createdBy is null
return "entity/new";
} else {
entityService.save(entity);
return "redirect:/entity/list";
}
}
the entity class:
#Entity
#Table(name = "TABLE_X")
public class Entity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#NotNull
#Column(name = "primary_key")
private String primaryKey;
#NotNull
#Column(name = "created_by")
private String createdBy;
//getters and setter
}
I need set the value of createdBy in controller but always show "may not be null" in view.
Please help.
Spring MVC 4, Hibernate Validator 5, Database Oracle 11g
You entity object is validated before Spring MVC invokes the submit() method. The result object is created at the same time. This line:
entity.setCreatedBy(auth.getName());
has absolutely no effect on the outcome of result.hasErrors().

Resources