Spring Validation Doesn't Work With Generic Types - spring-boot

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

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.

Exclude parameter from RequestBody - Swagger

I have two methods in one controller with the same obejct as arguments:
#PostMapping("/pg-import")
public String importProcessGroup(#RequestBody NiFiArguments niFiArguments) {
log.info("Called method importFlow");
#PostMapping("/pg-change-version")
public String changeVersionProcessGroup(#RequestBody NiFiArguments niFiArguments) {
log.info("Called method importFlow");
Pojo object:
#Data
public class NiFiArguments {
private String bucketIdentifier;
private String flowIdentifier;
private String flowVersion;
private String baseUrl;
private String processGroupId;
}
I would like to exclude processGroupId attribute from importProcessGroup method. Is it possible?
One way to do that would be to Subclass NiFiArguments into a separate class.
#Data
public class NiFiArguments {
private String bucketIdentifier;
private String flowIdentifier;
private String flowVersion;
private String baseUrl;
}
#Data
public class NiFiArgumentsWithProcessGroup extends NiFiArguments {
private String processGroupId;
}
Then use the different objects in your two methods.

How to post an Image and JSON object with single request to back end Spring Boot

I want to send image and JSON data to my back end in Spring Boot.
This is my method:
#PostMapping
public void uploadFile(#ModelAttribute FileUploadDto fileUploadDto) {
My FileUploadDto model:
public class FileUploadDto {
private MultipartFile file;
private CategoryModel category;
My CategoryModel model:
#Entity
#Table(name = "Category")
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class CategoryModel {
#Id
#Column(name = "id")
//#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String category_name;
private String category_description;
private String image_path;
#JsonIgnore
#OneToMany( mappedBy = "category")
private Set<ProductModel> category;
I do not understand where I'm wrong.
My postman request:
Your payload has to be raw and in json form. Something like this would help Spring boot to convert your payload into a object of an example class:
public class Foo{
public String foo;
public String foo1;
//Getters setters
}
And the request handling method:
#PostMapping
public void uploadFile(#RequestBody Foo foo)
It is also recommended to parse the payload into some a temporary class and then convert objects of the temporary class into the Entity class and vice versa. Take a look at: https://struberg.wordpress.com/2012/01/08/jpa-enhancement-done-right/ for more information
Also, if you want to upload file per REST I also recommend you to take a look at the following documentation: https://www.callicoder.com/spring-boot-file-upload-download-rest-api-example/
Best luck.

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

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.

Spring 3 mvc #Valid annotation doesn't work with List<Entity> property

I want to update an entity, which has a one-to-many List collection of other entity. When the handler method gets called, the validation doesn't seem to run on the collection. I've read the documentation, and searched stackoverflow, but did not find anything useful.
Model:
#Entity
public class Employee {
#Id
#GeneratedValue
private int employeeId;
#NotEmpty
private String name;
#Min(value=18)
private int age;
#OneToMany(mappedBy="parent",cascade=CascadeType.ALL)
private List<Child> children;
//getters,setters
}
#Entity
public class Child {
#Id
#GeneratedValue
private int childId;
#Column(nullable=false)
#NotNull
#Size(min=1,message="Child's name must not be empty")
private String childName;
#Max(value=18)
private Integer age;
#ManyToOne
#JoinColumn(name="employeeId")
private Employee parent;
//getters,setters
}
In the controller:
#RequestMapping(value = { "/edit/{id}" }, method = RequestMethod.POST)
private String update(#PathVariable int id, ModelMap model, #Valid Employee employee, BindingResult result) {
if (result.hasErrors()) {
return "employee/edit";
}
employeeDao.merge(employee);
return "redirect:../list";
}
The validation works for the simple properties of the Employee bean, but not for the elements in the children list.
How can this be fixed?
Seems like you should decorate your children list with #Valid annotation, as described here.
It should look something like this:
#OneToMany(mappedBy="parent",cascade=CascadeType.ALL)
#Valid
private List<Child> children;

Resources