Spring IP address validation - java

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.

Related

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
}

Custom Validation annotations not working properly using java 8 #Repeatable

Recently I added #Repeatable to my custom annotations. Once i added repeating annotaion to fields it was working fine , but fields with single annotoation is not working.
Example:
Following works:
#NotNull
#CustomValidator(type = Type.SIZE, max = 80)
#CustomValidator(type = Type.FIELD)
private String firstName;
But following does not works(Since it contains only one #CustomValidator):
#NotNull
#CustomValidator(type = Type.EMAIL)
private String email;
CustomValidator.java
import java.lang.annotation.Repeatable;
import javax.validation.Constraint;
import javax.validation.Payload;
#Constraint(validatedBy = CustomValidatorImpl.class)
#Repeatable(RepeatableCustomValidator.class)
public #interface CustomValidator {
String message() default "";
int min() default 1;
int max() default Integer.MAX_VALUE;
String format() default "dd.MM.yyyy";
String[] values() default {};
Type type();
boolean optional() default false;
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
RepeatableCustomValidator.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Target({ ElementType.FIELD })
#Retention(RetentionPolicy.RUNTIME)
public #interface RepeatableCustomValidator {
CustomValidator[] value();
}
CustomValidatorImpl.java
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class CustomValidatorImpl implements ConstraintValidator<CustomValidator, String> {
...............
#Override
public void initialize(CustomValidator constraintAnnotation) {
..........
}
}
Dependencies:
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
JAVA_VERSION="1.8.0_121"
Is there any thing that i am missing ?
As #Holger also pointed out,
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
Adding these two to your CustomValidator class fixes the problem.
By the way, Normal validations should also not take place if we do not mention these two policies.
Are you sure it was working without these? As I tried, and it was not working.

Spring MVC Custom validation showing error code HV000074.

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

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

Hibernate Validator : Using if - else kind of logic in annotation

I am using Hibernate validator like #NotEmpty to see if a specific property in a class is empty or not. The class is as as shown:
#Entity
#Table(name="emergency_messages")
public class EmergencyMessages implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id", nullable=false)
private Integer id;
#NotEmpty(message="Home message cannot be empty")
#Column(name="home_page_message")
private String homePageMessage;
#Range(min=0, max=1, message="Please select one of the display announcement value")
#Column(name="messages_enabled")
private Integer messagesEnabled;
}
So far so good. Whenever the property "homePageMessage" is empty I can see that the correct error message in the form in the browser.
Now the situation has changed. The new requirement is that the property "homePageMessage" can be empty only if the other property "messagesEnabled" is set to 1. If it is set to 0 then there should be no empty check done for "homePageMessage". In simple words the validation of "homePageMessage" should now be dependent on the "messagesEnabled" value.
My question: Is this possible to do with annotations? If not, then I will have to dismantle my hibernate validator mechanism and create my own validation class.
I think you need to write custom annotation to achieve this. Also you can use other hibernate validation constraint with custom annotation, no need to remove anything.
Check this link for details.
Following is the code that I came up with (after suggestions from Ajinkya and Alex):
Customized 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;
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Constraint(validatedBy=HomePageEmptyMessageValidator.class)
public #interface HomePageEmptyMessage {
String message() default "";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Customized Validator:
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class HomePageEmptyMessageValidator implements ConstraintValidator<HomePageEmptyMessage, EmergencyMessages> {
#Override
public void initialize(HomePageEmptyMessage homePageEmptyMessage) {
}
#Override
public boolean isValid(EmergencyMessages emergencyMessages, ConstraintValidatorContext context) {
if (emergencyMessages == null) {
return false;
}
Integer messageEnabled = emergencyMessages.getMessagesEnabled();
if (messageEnabled != null) {
if (messageEnabled == 1) {
String homePageMessage = emergencyMessages.getHomePageMessage();
if (Util.isNullOrEmpty(homePageMessage)) {
return false;
} else {
return true;
}
} else {
return true;
}
}
return false;
}
}
Usage of customized annotation in the code:
#Entity
#Table(name="emergency_messages")
#HomePageEmptyMessage(message="Home page annoucement cannot be empty if the Display Announcement is set to Yes")
public class EmergencyMessages implements Serializable {
private static final long serialVersionUID = -7870767517772161300L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id", nullable=false)
private Integer id;
#Column(name="home_page_message")
private String homePageMessage;
#Range(min=0, max=1, message="Please select one of the display announcement value")
#Column(name="messages_enabled")
private Integer messagesEnabled;
}
I hope it helps someone.
What you need is a ConstraintValidator implementation for your entity, using the #Constraint annotation on it.
This is where you will put conditions on fields that depends on other ones. Constraints using annotations on field are supposed to be used for check that can be made on the field itself, and not depending on another ones (like max size, nullable, etc...).

Categories