Derek Zhang
Derek Zhang

Reputation: 141

Use @Pattern to validate UUID or UUID.toString()

As we know, @Pattern annotation can only be used for implementation of CharSequence, such as String. Thus the following validation on UUID won't work.

@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}$")
private UUID                id;

Is there a way to use @Pattern annotation directly on UUID or based on UUID.toString()?

THE ACTUAL SCENARIO:

public class IndexController {
    ...
    public ResponseEntity<Void> postIndexes(@ApiParam(value = INDEXES_DESC, required = true) @Valid @RequestBody @Size(min = 1, max = 2000) List<Index> indexes) {
        ...
    }
    ...
}

@JsonInclude(JsonInclude.Include.NON_NULL)
public class Index implements Serializable {
    @ApiModelProperty(value = ID_DESC, example = SINGLE_ID)
    @NotNull
    private UUID                id;
    ...
}

When the user inputs a request body with JSON format like below

[
  {
    ...
    "id": "40336c2b-591a-4472-a270-A46339",
    ...
  }
]

It does not look like a normal UUID. The last part should contain 12 digits and there should not be any Uppercase letter. However, such input will be successfully converted into a valid Index with UUID "40336c2b-591a-4472-a270-000000a46339". We want this kind of input to fail by adding validation annotation.

Upvotes: 1

Views: 4852

Answers (1)

Basil Bourque
Basil Bourque

Reputation: 340070

UUID != String

You must understand that a UUID is not text. A java.util.UUID object is not a String object. A UUID is a 128-bit value where some of the bits have special meaning per the standard spec.

Humans do not do well with reading/writing 128 bits, such as one hundred and twenty eight 0 & 1 digits.

1010 1111 0111 0000 0000 0101 1001 1100

1111 0110 0000 0100 0100 1100 1011 1101

1001 1101 0010 0111 0010 1100 1111 1111

0111 1110 0010 1000 0000 1011 0001 0011

So when presenting a UUID for human consumption we translate the 128-bit value to a hexadecimal string of 32 characters. Canonically those hex characters are grouped with four hyphens, for a total of 36 characters.

Example per UuidGenerator.net:

af70059c-f604-4cbd-9d27-2cff7e280b13

Such a hex string is not a UUID, it represents a UUID value, a handy way to read or write 128 bits.

If you have a UUID object at hand in Java, you need not do any validation. Indeed, you have no string against which to do any validation. So regex is irrelevant. You have only 128-bits, stored internally as a pair of 64-bit integer numbers in most implementations.

To validate an incoming string in canonical format, there is no need for your pattern to validate, just parse using the UUID class and trap for exception.

By the way the UUID standard spec requires any hex representation to be generated in all lowercase. This rule is violated by many implementations including those by Apple and by Microsoft. The spec also requires parsing of inputs to tolerate uppercase.

Upvotes: 3

Related Questions