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