I'm developing an application using spring-boot. I want to validate the user bean using JSR annotation. The problem is that I have some fields that depend on the value of others. For example when status="user_pr" I have to make the address, county, and phoneNumber as mandatory.
this my bean:
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonInclude(JsonInclude.Include.NON_NULL)
public class User {
#NotNull(message = "required")
private String status;
#JsonProperty("first_name")
#NotNull(message = "required")
private String firstName;
#NotNull(message = "required")
private String name;
#NotNull(message = "required")
#Pattern(message = "Email not valid", regexp = "^([\\w\\.\\-_]+)?\\w+#[\\w-_]+(\\.\\w+){1,}$")
private String mailAddress;
private String country;
private String phoneNumber;
#JsonProperty("address")
private Address billingAddress;
}
Would you have any ideas ?
Best regards
I had the same problem a couple of weeks ago, I created my own validation annotation with a custom validation logic. You can find the showcase project in my repository: ConditionalValidator.
If you have any questions, just ask.
Related
I'm using Spring Boot.
I'm writing a Java class and I would like to make a validation using the annotations.
Something like this:
#Getter #Setter
#Validated
public class User {
#NotBlank(message = "Username cannot be empty")
private String username;
#NotBlank(message = "Email address cannot be empty")
#Email(message = "Please provide valid email address")
private String email;
#NotBlank(message = "First Name cannot be empty")
private String firstName;
#NotBlank(message = "Last Name cannot be empty")
private String lastName;
}
I would like to rise an exception if I try to create a new object with wrong parameters.
Same result if I will try to use a setter with wrong parameter.
Is it' possible? Is my code wrong?
You can invoke validator by yourself
#Component
class SomeComponent{
private Validator validator;
SomeComponent(Validator validator){
this.validator = validator;
}
void validateInput(Input input) {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Set<ConstraintViolation<Input>> violations = validator.validate(input);
if (!violations.isEmpty()) {
throw new ConstraintViolationException(violations);
}
}
}
You can trigger in Post Constructor method and in setters
You can use Hibernate Validator for Annotation validations
https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#validator-gettingstarted-createmodel
I am Java web developer, usually develop Spring MVC.
I have been using #RequestMapping or #RequestParam for mapping to hashMap at Controller.
It is a terrible way. I should always cast type when using value.
But nowadays I try to use #ModelAttribute to write clean code at Controller.
However, there are some problem.
case 1) make DTO for each EndPoint.
We can make DTO for each EndPoint, but DTO will have many duplicated property.
#Getter
#Setter
#ToString
class GetUserInfoDTO {
private String id;
private String name;
}
#Getter
#Setter
#ToString
class PostUserInfoDTO {
private String name;
private Integer age;
private String address;
private String gender;
private String email;
private Date joinDate;
}
in controller,
#GetMapping("/user")
public ResultDTO getUserInfo (#ModelAttribute GetUserInfoDTO){
...
return ResultDTO;
}
#PostMapping("/user")
public ResultDTO postUserInfo (#ModelAttribute PostUserInfoDTO){
...
return ResultDTO;
}
In this case, we can apply independent validation strategy for each End-Point.
for example..
#Getter
#Setter
#ToString
class GetUserInfoDTO {
#NotNull
private String id;
private String name;
}
#Getter
#Setter
#ToString
class PostUserInfoDTO {
#NotNull
private String name;
#NotNull
private Integer age;
#NotEmpty
private String address;
private String gender;
private String email;
private Date joinDate;
}
like this.
But so many model classes made, and so many duplicated property exists.
case 2. make common DTO for each Controller.
We can make DTO for each Controller, and reuse them.
#Getter
#Setter
#ToString
class UserInfoDTO {
private String id;
private String name;
private Integer age;
private String address;
private String gender;
private String email;
private Date joinDate;
}
#GetMapping("/user")
public ResultDTO getUserInfo (#ModelAttribute UserInfoDTO){
//I want only id, name
...
return ResultDTO;
}
#PostMapping("/user")
public ResultDTO postUserInfo (#ModelAttribute UserInfoDTO){
...
return ResultDTO;
}
But In this case, we can only pass specific properties.
If someone send other parameter than id and name, we can't notice. ( 400 error not occur )
Code assistance can't recommend us specific properties that use at single end-point.
I don't like these cases.
In first case, I should make so many models and It's management will be so hard.
Second case, unnecessary properties exists and it hard to validate for each end-point.
Which way is the best?
Or Can you recommend another way for mapping request parameter to model object?
I am creating a spring boot API which basically asks the user to create an account.
The account details are showed on a form.
I want to fetch the details from the form and save that to the database(MYSQL).
The model class is as follows:
#Table(name = "user")
public class User {
#Id
#Column(name = "ID")
private int ID;
#Column(name = "Fname")
private String fName;
#Column(name = "Lname")
private String lName;
#Column(name = "dob")
private String dob;
#Column(name = "email")
private String email;
#Column(name = "pWord")
private String pWord;
}
The controller class is as follows:
public class MController {
#Autowired
private UserRepository userRepository;
#PostMapping("/successSignUp")
public String dataToDB(#ModelAttribute("User") User formData, Model model) {
userRepository.save(new User(formData.getFname(), formData.getLname(), formData.getDob(), formData.getEmail(), formData.getPassword()));
model.addAttribute("user", new User());
return "welcomeUser";
}
When i am executing this code, i am getting the following error:
java.sql.SQLSyntaxErrorException: Unknown column 'p_word' in 'field list'
What am I doing wrong here?
Thanks in advance.
Spring framework changes the camel case to snake case internally.
This is part of Spring Boot Naming Strategies:
We can override these values, but by default, these will:
Change camel case to snake case
Replace dots with underscores
Lower-case table names
Can you try to update column name as pword instead of pWord ?
#Column(name = "pword")
private String pWord;
it will be considered as p_word if you use 'pWord'. please update column name as 'pword' and try.
example:
#Entity
public class Account {
#Id
private Long id;
private String defaultEmail;
}
And then turn on some SQL debugging in our properties file:
hibernate.show_sql: true
At startup, we'll see the following create statement in our logs:
Hibernate: create table account (id bigint not null, default_email varchar(255))
The easiest solution to fix this is to put the column names in lowercase or uppercase.
#Column(name = "pword")
private String pWord;
or
#Column(name = "PWORD")
private String pWord;
This will avoid that spring convert the name into snakecase.
Name of the columns in MySql are not case sensitive, so it will work.
Here is my example:
Java:
#JsonProperty("id")
private String id;
#JsonProperty(value = "name", required = true)
private String deviceName;
I made the name as a required field. In request how to make it as required field. I should send the name value from request.
But when I enter this:
{ "id": "abc123",}
It should send error response back.
Please help me.
Jacksons JsonProperty Annotation is not used for Validation. see: Jackson #JsonProperty(required=true) doesn't throw an exception. But you can use Bean Validation, e.g.:
class Device {
#JsonProperty("id")
private String id;
#NotEmpty
#JsonProperty(value = "name")
private String deviceName;
}
I have 2 bean as follows. Student bean validation is fine. But the inner bean Address validation has no effect at all. Although there is no validation for Address.pincode, but comes validation message as studentAddress.pincode Value must be an integer.
Why is it happening? Well I'm new in Spring, pleas explain in details. Thanks in advance!
public class Student {
#Size(min=2, max=30)
private String studentName;
#Size(min=3, max=30)
private String studentHobby;
#NotNull
private int studentMobile;
#Past
private Date studentDOB;
private ArrayList<String> studentSkills;
private Address studentAddress;
}
public class Address {
#Size(min=4, max=50)
private String country;
#Size(min=4, max=50)
private String city;
private String street;
private int pincode;
}
If you are using using Hibernate Validator 4.0.0+, you can do a "cascade validation" like so :
#Valid
private Address studentAddress;