diff --git a/engine/src/main/java/org/hibernate/validator/constraints/UUID.java b/engine/src/main/java/org/hibernate/validator/constraints/UUID.java index bb9992c52..eca7dc363 100644 --- a/engine/src/main/java/org/hibernate/validator/constraints/UUID.java +++ b/engine/src/main/java/org/hibernate/validator/constraints/UUID.java @@ -57,29 +57,77 @@ /** * @return allow empty strings. - * Per default does not allow empty strings + * Per default does not allow empty strings. */ boolean allowEmpty() default false; /** - * @return {@code true} if nil UUIDs {@code 00000000-0000-0000-0000-000000000000} are valid - * Per default nil UUIDs are valid + * @return {@code true} if nil UUIDs {@code 00000000-0000-0000-0000-000000000000} are valid. + * Per default nil UUIDs are valid. */ boolean allowNil() default true; /** - * Must not be lower than version 1 + * Accepts values in the {@code [1; 15]} range, which corresponds to the hexadecimal {@code [1; f]} range. * - * @return the accepted UUID version numbers - * Per default versions 1 to 5 are allowed + * @return the accepted UUID version numbers. + * Per default, versions 1 through 5 are allowed. */ int[] version() default { 1, 2, 3, 4, 5 }; /** - * Must not be lower than variant 0 + * Accepts values in the {@code [0; 2]} range. + *

+ * The variant of the UUID is determined by the binary representation of the 17th hex digit + * ({@code xxxxxxxx-xxxx-xxxx-Vxxx-xxxxxxxxxxxx} where {@code V} is the variant digit). + *

+ * Currently, only variants {@code [0, 1, 2]} are supported by the validator: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Table 1
Variant #Binary RepresentationHex DigitComment
00xxx0 - 7
110xx8 - b
2110xc - d
-1110eUnsupported, an UUID with such variant will be considered invalid.
-1111fUnsupported, an UUID with such variant will be considered invalid.
* * @return the allowed UUID variant numbers - * Per default variants 0 to 2 are allowed + * Per default, all variants 0 to 2 are allowed */ int[] variant() default { 0, 1, 2 }; diff --git a/engine/src/main/java/org/hibernate/validator/internal/constraintvalidators/hv/UUIDValidator.java b/engine/src/main/java/org/hibernate/validator/internal/constraintvalidators/hv/UUIDValidator.java index 98dd1f0bd..b738eefa4 100644 --- a/engine/src/main/java/org/hibernate/validator/internal/constraintvalidators/hv/UUIDValidator.java +++ b/engine/src/main/java/org/hibernate/validator/internal/constraintvalidators/hv/UUIDValidator.java @@ -119,12 +119,11 @@ else if ( valueLength != 36 ) { return allowNil; } else { - if ( Arrays.binarySearch( this.version, version ) == -1 ) { + if ( Arrays.binarySearch( this.version, version ) < 0 ) { return false; } - return Arrays.binarySearch( this.variant, variant ) != -1; + return Arrays.binarySearch( this.variant, variant ) > -1; } - } /** diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/constraintvalidators/hv/UUIDValidatorTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/constraintvalidators/hv/UUIDValidatorTest.java index 324fffdf0..d97cf286f 100644 --- a/engine/src/test/java/org/hibernate/validator/test/internal/constraintvalidators/hv/UUIDValidatorTest.java +++ b/engine/src/test/java/org/hibernate/validator/test/internal/constraintvalidators/hv/UUIDValidatorTest.java @@ -4,6 +4,7 @@ */ package org.hibernate.validator.test.internal.constraintvalidators.hv; +import static org.assertj.core.api.Assertions.assertThat; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; @@ -287,5 +288,121 @@ public void validOnlyIfConfiguredVariantMatches() { } + @Test + public void versionNotInTheAllowedList() { + char[] versions = new char[] { '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + + for ( int i = 0; i < versions.length; i++ ) { + int version = Character.digit( versions[i], 16 ); + descriptorBuilder.setAttribute( "version", new int[] { version } ); + + uuidAnnotation = descriptorBuilder.build().getAnnotation(); + uuidValidator.initialize( uuidAnnotation ); + + for ( int j = 0; j < versions.length; j++ ) { + if ( i == j ) { + continue; + } + String uuid = "24e6abaa-b2a8-%sa8e-0622-92adaaae229f".formatted( versions[j] ); + assertThat( uuidValidator.isValid( uuid, null ) ) + .as( "Expected uuid %s to be invalid because of the version %s not being allowed", uuid, versions[j] ) + .isFalse(); + } + } + } + + @Test + public void variantNotInTheAllowedLis11t() { + descriptorBuilder.setAttribute( "variant", new int[] { 1 } ); + + uuidAnnotation = descriptorBuilder.build().getAnnotation(); + uuidValidator.initialize( uuidAnnotation ); + + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-c622-92adaaae229f", null ) ); + } + + @Test + public void variantNotInTheAllowedList() { + // 0xxx 0 - 7 reserved (NCS backward compatible) + // 10xx 8 - b DCE 1.1, ISO/IEC 11578:1996 + // 110x c - d reserved (Microsoft GUID) + // 1110 e reserved (future use) + // 1111 f unknown / invalid. Must end with "0" + + descriptorBuilder.setAttribute( "variant", new int[] { 0 } ); + + uuidAnnotation = descriptorBuilder.build().getAnnotation(); + uuidValidator.initialize( uuidAnnotation ); + + assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-0622-92adaaae229f", null ) ); + assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-1622-92adaaae229f", null ) ); + assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-2622-92adaaae229f", null ) ); + assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-3622-92adaaae229f", null ) ); + assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-4622-92adaaae229f", null ) ); + assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-5622-92adaaae229f", null ) ); + assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-6622-92adaaae229f", null ) ); + assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-7622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-8622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-9622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-a622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-b622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-c622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-d622-92adaaae229f", null ) ); + // Next two variants are always invalid as they are currently "undefined": + // 1110 e + // 1111 f + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-e622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-f622-92adaaae229f", null ) ); + + descriptorBuilder.setAttribute( "variant", new int[] { 1 } ); + + uuidAnnotation = descriptorBuilder.build().getAnnotation(); + uuidValidator.initialize( uuidAnnotation ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-0622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-1622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-2622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-3622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-4622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-5622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-6622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-7622-92adaaae229f", null ) ); + assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-8622-92adaaae229f", null ) ); + assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-9622-92adaaae229f", null ) ); + assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-a622-92adaaae229f", null ) ); + assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-b622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-c622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-d622-92adaaae229f", null ) ); + // Next two variants are always invalid as they are currently "undefined": + // 1110 e + // 1111 f + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-e622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-f622-92adaaae229f", null ) ); + + descriptorBuilder.setAttribute( "variant", new int[] { 2 } ); + + uuidAnnotation = descriptorBuilder.build().getAnnotation(); + uuidValidator.initialize( uuidAnnotation ); + + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-0622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-1622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-2622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-3622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-4622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-5622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-6622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-7622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-8622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-9622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-a622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-b622-92adaaae229f", null ) ); + assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-c622-92adaaae229f", null ) ); + assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-d622-92adaaae229f", null ) ); + // Next two variants are always invalid as they are currently "undefined": + // 1110 e + // 1111 f + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-e622-92adaaae229f", null ) ); + assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-f622-92adaaae229f", null ) ); + + } }