Skip to content

Commit d4b8210

Browse files
committed
HV-2067 Adjust UUID's version/variant validation
1 parent bb039fd commit d4b8210

File tree

3 files changed

+177
-11
lines changed

3 files changed

+177
-11
lines changed

engine/src/main/java/org/hibernate/validator/constraints/UUID.java

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,29 +60,77 @@
6060

6161
/**
6262
* @return allow empty strings.
63-
* Per default does not allow empty strings
63+
* Per default does not allow empty strings.
6464
*/
6565
boolean allowEmpty() default false;
6666

6767
/**
68-
* @return {@code true} if nil UUIDs {@code 00000000-0000-0000-0000-000000000000} are valid
69-
* Per default nil UUIDs are valid
68+
* @return {@code true} if nil UUIDs {@code 00000000-0000-0000-0000-000000000000} are valid.
69+
* Per default nil UUIDs are valid.
7070
*/
7171
boolean allowNil() default true;
7272

7373
/**
74-
* Must not be lower than version 1
74+
* Accepts values in the {@code [1; 15]} range, which corresponds to the hexadecimal {@code [1; f]} range.
7575
*
76-
* @return the accepted UUID version numbers
77-
* Per default versions 1 to 5 are allowed
76+
* @return the accepted UUID version numbers.
77+
* Per default, versions 1 through 5 are allowed.
7878
*/
7979
int[] version() default { 1, 2, 3, 4, 5 };
8080

8181
/**
82-
* Must not be lower than variant 0
82+
* Accepts values in the {@code [0; 2]} range.
83+
* <p>
84+
* The variant of the UUID is determined by the binary representation of the 17th hex digit
85+
* ({@code xxxxxxxx-xxxx-xxxx-Vxxx-xxxxxxxxxxxx} where {@code V} is the variant digit).
86+
* <p>
87+
* Currently, only variants {@code [0, 1, 2]} are supported by the validator:
88+
* <table>
89+
* <caption>Table 1</caption>
90+
* <thead>
91+
* <tr>
92+
* <th>Variant #</th>
93+
* <th>Binary Representation</th>
94+
* <th>Hex Digit</th>
95+
* <th>Comment</th>
96+
* </tr>
97+
* </thead>
98+
* <tbody>
99+
* <tr>
100+
* <td>0</td>
101+
* <td>0xxx</td>
102+
* <td>0 - 7</td>
103+
* <td></td>
104+
* </tr>
105+
* <tr>
106+
* <td>1</td>
107+
* <td>10xx</td>
108+
* <td>8 - b</td>
109+
* <td></td>
110+
* </tr>
111+
* <tr>
112+
* <td>2</td>
113+
* <td>110x</td>
114+
* <td>c - d</td>
115+
* <td></td>
116+
* </tr>
117+
* <tr>
118+
* <td>-</td>
119+
* <td>1110</td>
120+
* <td>e</td>
121+
* <td>Unsupported, an UUID with such variant will be considered invalid.</td>
122+
* </tr>
123+
* <tr>
124+
* <td>-</td>
125+
* <td>1111</td>
126+
* <td>f</td>
127+
* <td>Unsupported, an UUID with such variant will be considered invalid.</td>
128+
* </tr>
129+
* </tbody>
130+
* </table>
83131
*
84132
* @return the allowed UUID variant numbers
85-
* Per default variants 0 to 2 are allowed
133+
* Per default, all variants 0 to 2 are allowed
86134
*/
87135
int[] variant() default { 0, 1, 2};
88136

engine/src/main/java/org/hibernate/validator/internal/constraintvalidators/hv/UUIDValidator.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,11 @@ else if ( valueLength != 36 ) {
121121
return allowNil;
122122
}
123123
else {
124-
if ( Arrays.binarySearch( this.version, version ) == -1 ) {
124+
if ( Arrays.binarySearch( this.version, version ) < 0 ) {
125125
return false;
126126
}
127-
return Arrays.binarySearch( this.variant, variant ) != -1;
127+
return Arrays.binarySearch( this.variant, variant ) > -1;
128128
}
129-
130129
}
131130

132131
/**

engine/src/test/java/org/hibernate/validator/test/internal/constraintvalidators/hv/UUIDValidatorTest.java

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@
1414
import org.testng.annotations.BeforeMethod;
1515
import org.testng.annotations.Test;
1616

17+
import static org.assertj.core.api.Assertions.assertThat;
1718
import static org.testng.Assert.assertFalse;
1819
import static org.testng.Assert.assertTrue;
1920
import static org.testng.Assert.fail;
2021

22+
import java.util.Locale;
23+
2124
/**
2225
* Tests the {@link UUID} constraint.
2326
*
@@ -289,5 +292,121 @@ public void validOnlyIfConfiguredVariantMatches() {
289292

290293
}
291294

295+
@Test
296+
public void versionNotInTheAllowedList() {
297+
char[] versions = new char[] { '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
298+
299+
for ( int i = 0; i < versions.length; i++ ) {
300+
int version = Character.digit( versions[i], 16 );
301+
descriptorBuilder.setAttribute( "version", new int[] { version } );
302+
303+
uuidAnnotation = descriptorBuilder.build().getAnnotation();
304+
uuidValidator.initialize( uuidAnnotation );
305+
306+
for ( int j = 0; j < versions.length; j++ ) {
307+
if ( i == j ) {
308+
continue;
309+
}
310+
String uuid = String.format( Locale.ROOT, "24e6abaa-b2a8-%sa8e-0622-92adaaae229f", versions[j] );
311+
assertThat( uuidValidator.isValid( uuid, null ) )
312+
.as( "Expected uuid %s to be invalid because of the version %s not being allowed", uuid, versions[j] )
313+
.isFalse();
314+
}
315+
}
316+
}
317+
318+
@Test
319+
public void variantNotInTheAllowedLis11t() {
320+
descriptorBuilder.setAttribute( "variant", new int[] { 1 } );
321+
322+
uuidAnnotation = descriptorBuilder.build().getAnnotation();
323+
uuidValidator.initialize( uuidAnnotation );
324+
325+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-c622-92adaaae229f", null ) );
326+
}
327+
328+
@Test
329+
public void variantNotInTheAllowedList() {
330+
// 0xxx 0 - 7 reserved (NCS backward compatible)
331+
// 10xx 8 - b DCE 1.1, ISO/IEC 11578:1996
332+
// 110x c - d reserved (Microsoft GUID)
333+
// 1110 e reserved (future use)
334+
// 1111 f unknown / invalid. Must end with "0"
335+
336+
descriptorBuilder.setAttribute( "variant", new int[] { 0 } );
337+
338+
uuidAnnotation = descriptorBuilder.build().getAnnotation();
339+
uuidValidator.initialize( uuidAnnotation );
340+
341+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-0622-92adaaae229f", null ) );
342+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-1622-92adaaae229f", null ) );
343+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-2622-92adaaae229f", null ) );
344+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-3622-92adaaae229f", null ) );
345+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-4622-92adaaae229f", null ) );
346+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-5622-92adaaae229f", null ) );
347+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-6622-92adaaae229f", null ) );
348+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-7622-92adaaae229f", null ) );
349+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-8622-92adaaae229f", null ) );
350+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-9622-92adaaae229f", null ) );
351+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-a622-92adaaae229f", null ) );
352+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-b622-92adaaae229f", null ) );
353+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-c622-92adaaae229f", null ) );
354+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-d622-92adaaae229f", null ) );
355+
// Next two variants are always invalid as they are currently "undefined":
356+
// 1110 e
357+
// 1111 f
358+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-e622-92adaaae229f", null ) );
359+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-f622-92adaaae229f", null ) );
360+
361+
descriptorBuilder.setAttribute( "variant", new int[] { 1 } );
362+
363+
uuidAnnotation = descriptorBuilder.build().getAnnotation();
364+
uuidValidator.initialize( uuidAnnotation );
365+
366+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-0622-92adaaae229f", null ) );
367+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-1622-92adaaae229f", null ) );
368+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-2622-92adaaae229f", null ) );
369+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-3622-92adaaae229f", null ) );
370+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-4622-92adaaae229f", null ) );
371+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-5622-92adaaae229f", null ) );
372+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-6622-92adaaae229f", null ) );
373+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-7622-92adaaae229f", null ) );
374+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-8622-92adaaae229f", null ) );
375+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-9622-92adaaae229f", null ) );
376+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-a622-92adaaae229f", null ) );
377+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-b622-92adaaae229f", null ) );
378+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-c622-92adaaae229f", null ) );
379+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-d622-92adaaae229f", null ) );
380+
// Next two variants are always invalid as they are currently "undefined":
381+
// 1110 e
382+
// 1111 f
383+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-e622-92adaaae229f", null ) );
384+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-f622-92adaaae229f", null ) );
385+
386+
descriptorBuilder.setAttribute( "variant", new int[] { 2 } );
292387

388+
uuidAnnotation = descriptorBuilder.build().getAnnotation();
389+
uuidValidator.initialize( uuidAnnotation );
390+
391+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-0622-92adaaae229f", null ) );
392+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-1622-92adaaae229f", null ) );
393+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-2622-92adaaae229f", null ) );
394+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-3622-92adaaae229f", null ) );
395+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-4622-92adaaae229f", null ) );
396+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-5622-92adaaae229f", null ) );
397+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-6622-92adaaae229f", null ) );
398+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-7622-92adaaae229f", null ) );
399+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-8622-92adaaae229f", null ) );
400+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-9622-92adaaae229f", null ) );
401+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-a622-92adaaae229f", null ) );
402+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-b622-92adaaae229f", null ) );
403+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-c622-92adaaae229f", null ) );
404+
assertTrue( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-d622-92adaaae229f", null ) );
405+
// Next two variants are always invalid as they are currently "undefined":
406+
// 1110 e
407+
// 1111 f
408+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-e622-92adaaae229f", null ) );
409+
assertFalse( uuidValidator.isValid( "24e6abaa-b2a8-4a8e-f622-92adaaae229f", null ) );
410+
411+
}
293412
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy