10

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?

mbs
  • 421
  • 2
  • 8
  • 28
  • You need to build your own validator. Check [this page](http://www.javabeat.net/2011/04/the-bean-validation-api-in-spring-roo-framework/all/1/) for an example that validates the ISBN number – Augusto Feb 14 '13 at 14:36

4 Answers4

16

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

Yudhistira Arya
  • 3,491
  • 6
  • 25
  • 42
David Rabinowitz
  • 29,904
  • 14
  • 93
  • 125
  • The pattern can be easily extended... The point is that you do not write additional annotations and validators, when you can use regular expressions – David Rabinowitz Feb 14 '13 at 14:50
  • 2
    But if a create an additional annotation I can use it several times and I have to extend it only in one place. Thanks for the regex I need it anyway for the validation. – mbs Feb 14 '13 at 15:17
  • The regexp string literal needs to escape – Lonre Wang May 31 '13 at 04:17
8

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
  }
}
sbk
  • 3,856
  • 1
  • 19
  • 19
  • Could you please explain why initialize method is empty? – Peters_ Aug 13 '20 at 13:08
  • You need that method to satisfy the contract of the ConstraintValidator interface, but if you don't need to actually initialize anything you can leave it empty. – sbk Aug 25 '20 at 23:50
0

Essentially you want to use JSR-303 annotations with a custom validator. See a full working example here.

abalogh
  • 8,239
  • 2
  • 34
  • 49
0

I know I'm digging up an old answer but I wanted to add a few things here. that I think could help because I was personally unsatisfied by all these answers for a couple reasons.

1). Doing a @Pattern above every IP like that is kinda ugly and it'd be cool just to have a quick class to include.

2). IPv4 is trivial. IPv6 is not.

If you're looking to do IPv6, read this: Regular expression that matches valid IPv6 addresses

3). If you want a simple IPv4 validator in one nice class, check out this code I hacked together and tested over on my own website. Works nicely.

import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Pattern;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Pattern(regexp = ValidIPv4.IPV4_REGEX)
@Constraint(validatedBy = {})
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidIPv4 {
    // JSR 303 Pattern Validator for IPv4
    String IPV4_REGEX = "^(([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])$";

    String message() default "must match " + IPV4_REGEX;

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

and of course a really nice unit test you can use:

import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
import org.springframework.validation.annotation.Validated;
import org.testng.annotations.Test;

import java.util.Set;

import static org.testng.AssertJUnit.assertEquals;

public class ValidIPv4Test {

    @Validated
    private class MyClass {
        @ValidIPv4
        private String ipv4;

        public String getIpv4() {
            return ipv4;
        }

        public void setIpv4(String ipv4) {
            this.ipv4 = ipv4;
        }
    }

    @Test
    public void testValidFormat() {
        // Create a ValidatorFactory and Validator
        ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
        Validator validator = validatorFactory.getValidator();

        // Create an object with the field to validate
        MyClass myClass = new MyClass();
        myClass.setIpv4("127.0.0.1");

        // Perform validation
        Set<ConstraintViolation<MyClass>> violations = validator.validate(myClass);

        // Assert that there are no validation violations
        assertEquals(0, violations.size());
    }

    @Test
    public void testInvalidFormat() {
        // Create a ValidatorFactory and Validator
        ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
        Validator validator = validatorFactory.getValidator();

        // Create an object with the field to validate
        MyClass myClass = new MyClass();
        myClass.setIpv4("827.0.0.1");

        // Perform validation
        Set<ConstraintViolation<MyClass>> violations = validator.validate(myClass);

        // Assert that there is one validation violation
        assertEquals(1, violations.size());

        // Assert that the violation is related to the field
        ConstraintViolation<MyClass> violation = violations.iterator().next();
        assertEquals("must match \"" + ValidIPv4.IPV4_REGEX + "\"", violation.getMessage());
        assertEquals("ipv4", violation.getPropertyPath().toString());
    }
}
alvonellos
  • 1,009
  • 1
  • 9
  • 27