Spring MVC Custom validation showing error code HV000074. - java

I am trying to implement a custom password match validation in spring boot. But I am getting an error as follows:-
PasswordMatch contains Constraint annotation, but does not contain a message parameter
I am following this link https://www.baeldung.com/registration-with-spring-mvc-and-spring-security for custom validation. The problem is I am getting error as this.
javax.validation.ConstraintDefinitionException: HV000074: com.bikram.booking.validation.PasswordMatch contains Constraint annotation, but does not contain a message parameter.
at org.hibernate.validator.internal.metadata.core.ConstraintHelper.assertMessageParameterExists(ConstraintHelper.java:915)
I have searched solutions on web but couldn't find the decent soultion.
My Modal is
package com.bikram.booking.dto;
import com.bikram.booking.validation.PasswordMatch;
import com.bikram.booking.validation.ValidEmail;
import javax.validation.constraints.*;
#PasswordMatch
public class UserDto {
#NotNull
#Size(min = 6, message = "Password should be more than 6 characters")
#NotEmpty(message = "Please provide a password")
private String password;
#NotNull
#Size(min = 6, message = "Password should be more than 6 characters")
private String confirmPassword;
}
My Interface is
package com.bikram.booking.validation;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
#Target({ TYPE, ANNOTATION_TYPE})
#Retention(RUNTIME)
#Constraint(validatedBy = PasswordMatchValidator.class)
#Documented
public #interface PasswordMatch {
String messages() default "Sorry, passwords does not match";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
And Implementation is
package com.bikram.booking.validation;
import com.bikram.booking.dto.UserDto;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class PasswordMatchValidator implements ConstraintValidator<PasswordMatch, Object> {
#Override
public void initialize(PasswordMatch constraintAnnotation) {
}
#Override
public boolean isValid(Object obj, ConstraintValidatorContext constraintValidatorContext) {
UserDto userDto = (UserDto) obj;
return true;
}
}
Any hints will be higly appreciable.

Rename messages() to message() in PasswordMatch :
public #interface PasswordMatch {
String message() default "Sorry, passwords does not match";
....
}

Related

Spring Boot JPA Custom validation null point error for password confirmation

I made a registration form and I want to validate all filed of the form I validated expect one field to match the fields of PASSWORD matching so make custom validtion but is not working i attaced code in
#Entity
public class Userlist {
......
#Size(min = 8, message = "Please enter atleast 8 digit password")
private String userpassword;
#PasswordMatch(message="Your Password is not match with created password")
private String confirmpassword;
}
package com.picture.picturesalbum.anotation;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import java.lang.annotation.*;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
#Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Constraint(validatedBy = PasswordMatchValidator.class)
public #interface PasswordMatch {
public String message() default "Your Password is not match with created password ";
public Class<?>[] groups() default {};
public Class<? extends Payload>[] payload() default {};
}
package com.picture.picturesalbum.anotation;
import com.picture.picturesalbum.model.Userlist;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class PasswordMatchValidator implements ConstraintValidator<PasswordMatch, String> {
Userlist userlist = new Userlist();
public boolean isValid(String value, ConstraintValidatorContext context) {
// Userlist userlist = new Userlist();
if (value.contentEquals(userlist.getUserpassword())) {
return true;
} else {
return false;
}
}
}
Error is
at java.base/java.lang.Thread.run(Thread.java:1589)
Caused by: java.lang.NullPointerException: Cannot invoke "java.lang.CharSequence.length()" because "cs" is null
If you want to validate two fields of a class, you have to use a custom validator with a class level constraint and then compare both values in the validator class.
Check this answer for more information.
Another solution is to define a method that must validate to true and put the #AssertTrue annotation on the top of it:
#AssertTrue
private boolean isEqual() {
return userpassword.equals(confirmPassword);
}

Annotation for DataSize validation

Is there any standard validator annotation I can use for a DataSize field?
Something like javax #Min and #Max, or Hibernate's #DurationMin and #DurationMax.
For class DataSize, there's no standard validator, so you should implement your own. But it's quite easy :)
Annotation interface:
import org.springframework.util.unit.DataUnit;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
#Documented
#Constraint(validatedBy = DataSizeMaxValidator.class)
#Target({ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
public #interface DataSizeMax {
String message() default "must be less than or equal to {value} {unit}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
long value();
DataUnit unit();
}
Validator:
import org.springframework.stereotype.Component;
import org.springframework.util.unit.DataSize;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
#Component
public class DataSizeMaxValidator implements ConstraintValidator<DataSizeMax, DataSize> {
private DataSize dataSizeMax;
#Override
public void initialize(DataSizeMax dataSizeMax) {
this.dataSizeMax = DataSize.of(dataSizeMax.value(), dataSizeMax.unit());
}
#Override
public boolean isValid(DataSize value, ConstraintValidatorContext context) {
return dataSizeMax.compareTo(value) >= 0;
}
}
That's it. Then use this annotation as here:
import pizza.nikiforov.validators.DataSizeMax;
import org.springframework.util.unit.DataSize;
import org.springframework.util.unit.DataUnit;
public class Data {
#DataSizeMax(value = 15L, unit = DataUnit.MEGABYTES)
private DataSize dataSize;
// other fields
// constructors, getters and setters
}

Validating entity as a parameter via custom constraint

Using Spring Boot, I've created an example application.
package hello;
import org.springframework.web.bind.annotation.RestController;
import constraint.CheckHelloId;
import dto.HelloDto;
import javax.validation.Valid;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#RestController
public class HelloController {
#RequestMapping(value = "/", method = RequestMethod.POST)
public String index(#RequestBody #Valid final HelloDto hello) {
hello.setId(null);
validateFromMethodHeader(hello);
return "Greetings from Spring Boot!";
}
private void validateFromMethodHeader(#CheckHelloId final HelloDto helloDto) {
System.out.println("Validating DTO...");
}
}
I'm trying to add a custom constraint to the DTO HelloDto in the private method that checks if the id field is null or not.
The interface:
package constraint;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
#Target({ FIELD, ANNOTATION_TYPE, TYPE, METHOD, PARAMETER })
#Retention(RUNTIME)
#Constraint(validatedBy = CheckHelloIdValidator.class)
#Documented
public #interface CheckHelloId {
String message() default "";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
The validator:
package constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.constraintvalidation.SupportedValidationTarget;
import javax.validation.constraintvalidation.ValidationTarget;
import org.apache.commons.lang3.StringUtils;
import dto.HelloDto;
#SupportedValidationTarget(ValidationTarget.PARAMETERS)
public class CheckHelloIdValidator implements ConstraintValidator<CheckHelloId, HelloDto> {
private static final String ID_VALIDATION_ERROR = "Null or blank ID.";
#Override
public void initialize(CheckHelloId arg0) {
}
#Override
public boolean isValid(HelloDto helloDto, ConstraintValidatorContext context) {
if (StringUtils.isBlank(helloDto.getId())){
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(ID_VALIDATION_ERROR).addConstraintViolation();
return false;
}
return true;
}
}
The DTO:
package dto;
import java.io.Serializable;
public class HelloDto implements Serializable {
private static final long serialVersionUID = 8792903048191496378L;
private String id;
private String message;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
As seen in the private method at the controller, I'm trying to apply the validation of the DTO at a parameter level (I know I can just do it at the index via entity validation, but I want to test this concrete case, that's why I set the id field as null at the controller).
When I run the application and perform the call, the constraint does not apply in the private method, even when the id field is null. Could anybody shed some light on this? Thank you in advance.
To validate consuming json on rest controller beside annotated method parameters #RequestBody #Valid final HelloDto hello you have to annotate filed of your json data class with special constraints. For you case it enough to use hibernate validation constraints #NotNull or #NotEmpty:
package dto;
import java.io.Serializable;
public class HelloDto implements Serializable {
private static final long serialVersionUID = 8792903048191496378L;
#NotEmpty
private String id;

How to validate 2 field with OR condition?

I want to validate two fields of a Request Class in manner that Either one field is valid OR another field is valid.
Eg:
Request Bean
public class CarRequest {
#NotEmpty
private String customerName;
#NotEmpty
private String customerId;
Controller Method
public #ResponseBody CarResponse addCar(
#ModelAttribute #Valid CarRequest request, BindingResult results)
throws RuntimeException, ValidationException {
if (results.hasErrors()) {
LOG.error("error occured while adding the car");
throw new ValidationException(
"Error Occoured while validiating car request");
}
}
Here I want to check that either customerName should be NotEmpty OR customerId should be NotEmpty. then my validation should pass. How can I implement it . Please suggest!!
You need to create custom validator to validate multiple fields.
create a custom annotation:
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
#Documented
#Constraint(validatedBy = CarRequestValidator.class)
#Target({ ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface RequestAnnotation {
String message() default "{RequestAnnotation}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
create a custom validator:
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class CarRequestValidator implements
ConstraintValidator<RequestAnnotation, CarRequest> {
#Override
public void initialize(RequestAnnotation constraintAnnotation) {
}
#Override
public boolean isValid(CarRequest value, ConstraintValidatorContext context) {
// validation logic goes here
return false;
}
}
Now, annotate your model with custom annotation:
#RequestAnnotation
public class CarRequest {
private String customerName;
private String customerId;
}

Spring IP address validation

I'm looking for a possiblity to validate IP addresses in my Spring roo project.
My entity looks like this
package com.ip.test.domain;
import javax.persistence.ManyToOne;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord;
import org.springframework.roo.addon.tostring.RooToString;
#RooJavaBean
#RooToString
#RooJpaActiveRecord
public class IP {
#NotNull
#Size(min = 7, max = 15)
private String ip;
#ManyToOne
private Hoster Hoster;
}
With this setup it validates only if the string contains 7 to 15 characters, but not really if it's an IP address.
Something like
#validIpAddress
private String ip;
would be nice.
Any idea if that's possible?
You can use the JSR 303 Pattern validator, with an IP address regex:
#NotNull
#Pattern(regexp = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$")
private String ip;
edit: escape backslash
Definitely possible. You will need to code a custom annotation and implementation class. Not too much effort. See here for background: http://docs.jboss.org/hibernate/validator/5.0/reference/en-US/html_single/#validator-customconstraints
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
#Documented
#Constraint(validatedBy = IpAddressValidator.class)
public #interface IpAddress
{
String message() default "{ipAddress.invalid}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
and
public class IpAddressValidator implements ConstraintValidator<IpAddress, Object>
{
#Override
public void initialize(IpAddress constraintAnnotation)
{
}
#Override
public boolean isValid(Object value, ConstraintValidatorContext cvContext)
{
// logic here
}
}
Essentially you want to use JSR-303 annotations with a custom validator. See a full working example here.

Categories