Guide de l'UUID en Java

1. Vue d'ensemble

UUID (Universally Unique Identifier), également connu sous le nom de GUID (Globally Unique Identifier), représente une valeur de 128 bits qui est unique à toutes fins pratiques . La représentation standard de l'UUID utilise des chiffres hexadécimaux (octets):

123e4567-e89b-12d3-a456-556642440000

Un UUID est composé de chiffres hexadécimaux (4 caractères chacun) et de 4 symboles «-» qui rendent sa longueur égale à 36 caractères .

L'UUID Nil est une forme spéciale d'UUID dans laquelle tous les bits sont mis à zéro.

Dans cet article, nous allons jeter un œil à la classe UUID en Java. Tout d'abord, nous verrons comment utiliser la classe elle-même. Ensuite, nous examinerons les différents types d'UUID et comment nous pouvons les générer en Java.

2. La classe UUID

La classe UUID a un seul constructeur:

UUID uuid = new UUID(long mostSignificant64Bits, long leastSignificant64Bits);

Si nous voulons utiliser ce constructeur, nous devons fournir deux valeurs longues. Cependant, cela nous oblige à construire nous-mêmes le modèle de bits pour l'UUID.

Pour plus de commodité, il existe trois méthodes statiques pour créer un UUID. Ceux-ci sont:

UUID uuid = UUID.nameUUIDFromBytes(byte[] bytes); 

Cette méthode crée un UUID version 3 à partir du tableau d'octets donné.

UUID uuid = UUID.randomUUID(); 

La méthode randomUUID () crée un UUID version 4. C'est le moyen le plus pratique de créer un UUID.

UUID uuid = UUID.fromString(String uuidHexDigitString); 

La troisième méthode statique renvoie un objet UUID en fonction de la représentation sous forme de chaîne d'un UUID donné.

Voyons maintenant comment un UUID est structuré.

3. Structure

Prenons l'exemple UUID:

123e4567-e89b-42d3-a456-556642440000 xxxxxxxx-xxxx-Bxxx-Axxx-xxxxxxxxxxxx

3.1. Variante UUID

A représente la variante qui détermine la disposition de l'UUID. Tous les autres bits de l'UUID dépendent du paramétrage des bits dans le champ variant. La variante est déterminée par 3 bits les plus significatifs de A:

 MSB1 MSB2 MSB3 0 X X reserved (0) 1 0 X current variant (2) 1 1 0 reserved for Microsoft (6) 1 1 1 reserved for future (7)

La valeur de A dans l'UUID mentionné est «a». L'équivalent binaire de 'a' (= 10xx) montre la variante comme 2.

3.2. Version UUID

B représente la version. La version dans l'UUID mentionné (valeur de B ) est 4.

Java fournit des méthodes pour obtenir la variante et la version de l'UUID:

UUID uuid = UUID.randomUUID(); int variant = uuid.variant(); int version = uuid.version();

Il existe 5 versions différentes pour les UUID de la variante 2: Time Based (UUIDv1), DCE Security (UUIDv2), Name Based (UUIDv3 and UUIDv5), Random (UUIDv4).

Java fournit une implémentation pour les v3 et v4, mais fournit également un constructeur pour générer tout type d'UUID:

UUID uuid = new UUID(long mostSigBits, long leastSigBits);

4. Les versions de l'UUID

4.1. Version 1

La version 1 de l'UUID est basée sur l'horodatage actuel, mesuré en unités de 100 nanosecondes à partir du 15 octobre 1582, concaténé avec l'adresse MAC de l'appareil sur lequel l'UUID est créé.

Si la confidentialité est un problème, la version 1 de l'UUID peut également être générée avec un nombre aléatoire de 48 bits au lieu de l'adresse MAC.

Dans cet article, nous allons cette alternative. Tout d'abord, nous allons générer les 64 bits les moins significatifs et les plus significatifs sous forme de valeurs longues:

private static long get64LeastSignificantBitsForVersion1() { Random random = new Random(); long random63BitLong = random.nextLong() & 0x3FFFFFFFFFFFFFFFL; long variant3BitFlag = 0x8000000000000000L; return random63BitLong + variant3BitFlag; } private static long get64MostSignificantBitsForVersion1() { LocalDateTime start = LocalDateTime.of(1582, 10, 15, 0, 0, 0); Duration duration = Duration.between(start, LocalDateTime.now()); long seconds = duration.getSeconds(); long nanos = duration.getNano(); long timeForUuidIn100Nanos = seconds * 10000000 + nanos * 100; long least12SignificatBitOfTime = (timeForUuidIn100Nanos & 0x000000000000FFFFL) >> 4; long version = 1 << 12; return (timeForUuidIn100Nanos & 0xFFFFFFFFFFFF0000L) + version + least12SignificatBitOfTime; }

On peut ensuite passer ces deux valeurs au constructeur de l'UUID:

public static UUID generateType1UUID() { long most64SigBits = get64MostSignificantBitsForVersion1(); long least64SigBits = get64LeastSignificantBitsForVersion1(); return new UUID(most64SigBits, least64SigBits); }

4.2. Version 2

La version 2 est également basée sur un horodatage et l'adresse MAC. Cependant, la RFC 4122 ne spécifie pas les détails de génération exacts, par conséquent, nous n'examinerons pas une implémentation dans cet article.

4.3. Version 3 et 5

Les UUID sont générés à l'aide du hachage de l'espace de noms et du nom. Les identificateurs d'espace de noms sont des UUID tels que le système de noms de domaine (DNS), des identificateurs d'objets (OID), des URL, etc.

UUID = hash(NAMESPACE_IDENTIFIER + NAME)

La seule différence entre UUIDv3 et UUIDv5 est l'algorithme de hachage - la v3 utilise MD5 (128 bits) tandis que la v5 utilise SHA-1 (160 bits).

En termes simples, nous tronquons le hachage résultant à 128 bits, puis remplaçons 4 bits pour la version et 2 bits pour la variante.

Générons un UUID de type 3:

byte[] nameSpaceBytes = bytesFromUUID(namespace); byte[] nameBytes = name.getBytes("UTF-8"); byte[] result = joinBytes(nameSpaceBytes, nameBytes); UUID uuid = UUID.nameUUIDFromBytes(result);

Ici, il est important de noter que la chaîne hexadécimale de l'espace de noms doit d'abord être convertie en un tableau d'octets.

Java ne fournit pas l'implémentation pour le type 5. Consultez notre référentiel de code source pour l'UUIDv5.

4.4. Version 4

L'implémentation UUID v4 utilise des nombres aléatoires comme source. L'implémentation Java est SecureRandom - qui utilise une valeur imprévisible comme germe pour générer des nombres aléatoires afin de réduire les risques de collisions.

Générons l'UUID de la version 4:

UUID uuid = UUID.randomUUID();

Générons une clé unique en utilisant 'SHA-256' et un UUID aléatoire:

MessageDigest salt = MessageDigest.getInstance("SHA-256"); salt.update(UUID.randomUUID().toString().getBytes("UTF-8")); String digest = bytesToHex(salt.digest());

5. Conclusion

Dans cet article, nous avons vu comment un UUID est structuré, quelles variantes et versions il existe. Nous avons appris pour quelles versions Java fournit une implémentation prête à l'emploi et avons examiné des exemples de code pour générer les autres versions.

Et, comme toujours, le code source de l'implémentation est disponible sur Github.