Validate DTO in Get mathod - java

I want to pass a DTO to Get method:
#GetMapping
public void my_get(MyDto myDto){
}
Above code work's correctly but validations on fields not worked.
#Data
#AllArgsConstructor
#NoArgsConstructor
public class MyDto {
#NotNull
#NotBlank(message = ValidateConstant.NOT_BLANK_MESSAGE)
String id;
String uri;
String type;
String version;
}
I'm also add #Valid annotation but also Get method return 200 in response.

add #Valid annotation
public void my_get(#Valid MyDto myDto){
if that does not help, add #Validated at the class level.

Related

Use #RequestBody to map JSON to a class with #Builder

I am using #RequestBody to map JSON body of a POST request to my java class. My POST request was working fine initially, but when I add the #Builder annotation to my java class it started fail. I was wandering how I can use #RequestBody to map JSON to a class with #Builder annotation
My Controller Class
#RequestMapping(value = { "/cards/add" }, method = RequestMethod.POST)
public void addCard(final HttpServletResponse response, #RequestBody Card request) {
...
}
My Model Class
#Data
#Builder
public class Card {
private String Id;
...
}
Try adding these:
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class Card {
private String Id;
...
}

#Valid annotation is not working and giving NotReadablePropertyException

I have request class for a patch API in the below format
#Schema
#Data
#EqualsAndHashCode(callSuper = true)
#AllArgsConstructor
#NoArgsConstructor
#Builder
public class PricingUsageTemplatePatchInput extends BaseRequest {
#Schema(description = "From node of the Template")
private JsonNullable<#Valid VertexNode> from;
#Schema(description = "To node of the Template")
private JsonNullable<#Valid VertexNode> to;
#NotNull
#Schema(description = "Current version of the template for which update is being made.")
private Long version;
}
VertexNode is as below
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class VertexNode {
#NotNull
#Valid
private Selectors selectors;
#NotNull
#Valid
private Cardinality cardinality;
}
And in the controller layer is as below
#PatchMapping("/{key}")
#Operation(description = "API to update the template")
public PricingUsageTemplateResponse update(#PathVariable #IsUUID final String key,
#Valid #RequestBody #NotNull #Parameter(description = "PricingUsageTemplatePatchInput", required = true)
PricingUsageTemplatePatchInput pricingUsagePatchInput) {
var request = PricingUsageTemplateUpdateRequest.builder()
.key(key)
.pricingUsageTemplatePatchInput(pricingUsageTemplatePatchInput)
.build();
return (PricingUsageTemplateResponse) actionRegistry.get(request).invoke(request);
}
When I am sending selector as null from the postman for the above api , the valid annotation is not able to send valid not null validation error instead I am getting 5xx error with below reason
org.springframework.beans.NotReadablePropertyException: Invalid property 'to.selectors' of bean class [domain.pricing_usage.dto.request.PricingUsageTemplatePatchInput]: Bean property 'to.selectors' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
Can anyone help why #Valid is not working as expected

Why #RequestBody works without setters?

I am writing a controller with the annotation #RequestBody in order to map to a Java object. The method that uses the annotation is:
#PostMapping("/users")
public ResponseEntity<Object> createUserForProject(#Valid #RequestBody User user) {
log.info("Creating a user " + user.getEmail());
}
This is the User class:
#Getter
#AllArgsConstructor
#Slf4j
#EqualsAndHashCode
#ToString
public class User {
#NotEmpty
#Email
private String email;
#NotEmpty
private String firstName;
#NotEmpty
private String lastName;
#JsonIgnore
private Optional<LocalDate> lastLogonDate = Optional.empty();
#JsonIgnore
private Optional<LocalDate> lastModificationDate = Optional.empty();
#JsonIgnore
private Optional<LocalDate> creationDate = Optional.empty();
#JsonIgnore
private Optional<LocalDate> mfaWarningDate = Optional.empty();
#JsonIgnore
private Optional<LocalDate> auditStartNotificationDate = Optional.empty();
#JsonIgnore
private boolean enabled = true;
public User() {
log.info("HI");
}
(More code without explicit setters)
So when I make a POST call with the body
{
"email":"test#test.com",
"firstName":"testName",
"lastName":"testLastName"
}
Outputs HI and the log with the Creating a user test#test.com message, so the object is created. My point here is... why does this really work? The HttpMessageConverter is calling the no-args constructor and there are no setters to call after create the object with the constructor. How do the object attributes get their values without any setter? What am I missing here?
Spring boot uses Jackson for Object <-> JSON conversion, and Jackson does not need setters, it sets fields via reflection.
Here is a relevant question about Jackson and why it doesn't need setters
How does jackson set private properties without setters?

Spring CrudRepository failing to return JSON from valid object while using Lombok #Data Annotation

I'm attempting to get a basic spring application up and running from a tutorial with mysql but I'm running into issues with the GetMapping and PostMapping annotations, here is what I have so far:
I've manually added a user into my table with id=0, name="test" via mysql workbench and verified that the data is in fact there.
I was forced to do it via mysql workbench because attempting to post with curl results in no change
Attempting to call localhost/api/user/1 when there is no user with that ID gives me a 404, which is what is expected while calling it with localhost/api/user/0 gives me an http ok code 200, I'm just not actually receiving a populated JSON object.
Debugging the application on the getUser (using url localhost/api/user/0) shows a user in memory with id=0, name="test" however once the return ResponseBody.ok()... is completed the response I get via browser AND curl is still {}, an empty JSON object
User.Java
#Data
#Builder
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
private String name;
}
UserRepository.java
#Repository
public interface UserRepository extends CrudRepository<User, Long> {}
UserController.java
#RestController
#RequestMapping("/api/user")
public class UserController {
#Autowired
private UserRepository userRepository;
#GetMapping
public List<User> getAllUsers(){
return (List<User>) userRepository.findAll();
}
#GetMapping("/{id}")
public ResponseEntity<User> getUser(#PathVariable(value="id") long id){
Optional<User> user = userRepository.findById(id);
if(user.isPresent()) {
return ResponseEntity.ok().body(user.get());
}else {
return ResponseEntity.notFound().build();
}
}
#PostMapping
public User saveUser(#Validated #RequestBody User user) {
return userRepository.save(user);
}
}
So to summarize I'm receiving an empty JSON object from my GetMapping AND PostMapping annotated calls, even while I have valid data in the table (or have submitted valid post data) when I should be receiving back a json object with {id:0, name:"test"}, does anyone know what might be happening?
Edit:
It appears as though lombok is not actually injecting getters and setters when I run my application, changing my user.java to
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getId() {
return this.id;
}
}
and recalling localhost/api/user/0 returns the expected json object, Why isnt lombok injecting these functions into my code properly with the #Data annotation? (eclipse)
So this was happening because lombok was not injecting getters/setters and the ResponseEntity.ok.body(user) could not retrieve the values within the User class.
Apparently according to this stackoverflow answer when using eclipse lombok requires a plugin to properly inject the methods.
So this problem can be fixed by either manually defining the appropriate getters/setters needed or by installing the plugin for eclipse.

javax.validation not working when noargsconstructor is used

I am trying to validate a request object, whose class is as follows:
#Value
#NoArgsConstructor(force = true, access = AccessLevel.PRIVATE)
#AllArgsConstructor
public class SomeCreateRequest {
#NotNull(message = "Name can not be null")
#NotBlank(message = "Name can not be empty")
String name;
}
Without NoArgsConstructor, validation works but POST operation fails with HttpMessageNotReadableException; with NoArgsConstructor, POST operation succeeds but validation doesn't work.
What am I doing wrong?
P.S. using Java 8, Spring 2.3.4.RELEASE, javax.validation 2.0.1.Final and my controller looks like below:
#RequiredArgsConstructor
#RestController
#RequestMapping("/api")
public class MyController {
private final MyService myService;
#PostMapping()
public MyResponse submit(#Valid #RequestBody SomeCreateRequest request){
return myService.create(request);
}
}

Categories