32

I can't find a @UUID (or similar) annotation for validating input parameters in a java web app.

I've looked so far in

  1. javax.validation.constraints
  2. org.hibernate.validator.constraints
Ian
  • 30,182
  • 19
  • 69
  • 107
Emanuel George Hategan
  • 1,123
  • 1
  • 13
  • 22
  • 9
    If you want to make validation on **@RestController** endpoint then I think easier is to just expect the **java.util.UUID** type. If there will be not possible to map the value from HTTP request to valid UUID then spring just refuse the request :) – Ziemowit Stolarczyk Nov 09 '17 at 12:46
  • At least now, `org.hibernate.validator.constraints.UUID` is in place and we're using it. – Dmitriy Popov Aug 14 '23 at 15:16

4 Answers4

45

yes, build it by yourself

@Target(ElementType.FIELD)
@Constraint(validatedBy={})
@Retention(RUNTIME)
@Pattern(regexp="^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$")
public @interface UUID {
    String message() default "{invalid.uuid}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
Christoph Leiter
  • 9,147
  • 4
  • 29
  • 37
Jaiwo99
  • 9,687
  • 3
  • 36
  • 53
  • 14
    Thank you @Jaiwo99 I was hoping validating uuids is common enough so that it is already included in libraries and I don't need to reinvent the wheel... – Emanuel George Hategan Jun 07 '16 at 13:25
  • 5
    In case of constraint violation this returns the error message of the @Pattern annotation, not the custom `message()`. To return the custom error message set from outside, you can add `javax.validation.ReportAsSingleViolation` metaannotation. – helospark Aug 14 '18 at 06:49
  • @Jaiwo99 your interface not work for me. it not throw me custom message. neither default message. – ankit Aug 24 '18 at 07:50
  • 1
    This regex will invalidate all upper case or if a single upper case char is present in the UUID. – dazito Nov 08 '18 at 09:05
  • @dazito Hi, you are right, but this is not the ultimate solution for all possible UUID validation, feel free to change it so that it suits your requirement. – Jaiwo99 Nov 08 '18 at 13:32
  • 1
    Sure, I was just pointing out in case someone does a copy paste and then is wondering why it is failing (in case it fails) :) – dazito Nov 08 '18 at 17:30
  • 2
    @dazito This can easily be fixed by passing the `Pattern.Flag.CASE_INSENSITIVE` flag to `@Pattern` – Niel de Wet Apr 08 '19 at 19:32
  • 1
    @Jaiwo99 You cannot apply the '@Pattern' annotation to something (java.util.UUID) that is not a CharSequence.https://stackoverflow.com/questions/53868539/validate-uuid-restful-service – Mojtaba Jan 27 '21 at 10:00
  • @ankit the proper answer for UUID validation can be found in https://stackoverflow.com/questions/53868539/validate-uuid-restful-service/ – Mojtaba Jan 27 '21 at 12:12
20

[Updated]

The solution from @Jaiwo99 will not display the specified message, it will instead display the error message from @Pattern. To fix this issue, just add @ReportAsSingleViolation annotation to @Jaiwo's solution. (@LudovicRonsin pointed this out in a comment to this answer, and @helospark in a comment to @Jaiwo99's answer.)

@Target(ElementType.FIELD)
@Constraint(validatedBy={})
@Retention(RUNTIME)
@Pattern(regexp="^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$")
@ReportAsSingleViolation
public @interface UUID {
    String message() default "{invalid.uuid}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

[Old Answer]

The solution from Jaiwo99 works, but I was unable to set a custom message from the outside (it is overriden by the message from @Pattern). If you need that, I propose that you simply use something like this:

@Pattern(regexp = SomeUtilClass.UUID_PATTERN, message = "TokenFormatError")
private String token;

You can put the pattern in some static final field to avoid duplication:

public static SomeUtilClass {
    public static final String UUID_PATTERN = "^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$";
}
mrzli
  • 16,799
  • 4
  • 38
  • 45
  • 1
    There are at least 3 ways of defining your own message in a composed constraint (like in @Jaiwo99 answer) * Set the `@Pattern` message field with a static default message. * Use `@javax.validation.OverridesAttribute` to override `@Pattern` default message and give the ability to contextualise with constraint usage. * `@javax.validation.ReportAsSingleViolation` to return only the message set by your annotation. In this particular case, I would use `@ReportAsSingleViolation` See https://beanvalidation.org/1.1/spec/#constraintsdefinitionimplementation-constraintcomposition – Ludovic Ronsin May 17 '21 at 10:57
7

At the time of the question there wasn't one but in the meantime it has been added starting with org.hibernate.validator:hibernate-validator:8.0.0.Final

https://docs.jboss.org/hibernate/stable/validator/api/org/hibernate/validator/constraints/UUID.html

Emanuel George Hategan
  • 1,123
  • 1
  • 13
  • 22
Jim Bethancourt
  • 1,061
  • 11
  • 16
3

Same as @Jaiwo99's answer , but as @mrzli pointed out, the pattern's message overrides any custom messages. Using message in the @Pattern will fix that if you want custom messages.

@Target(ElementType.FIELD)
@Constraint(validatedBy={})
@Retention(RUNTIME)
@Pattern(regexp="^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", message = "Not a valid UUID")
public @interface UUID {
    String message() default "{invalid.uuid}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
Ajo Paul
  • 544
  • 4
  • 6