1. Información general
UUID (Universally Unique Identifier), también conocido como GUID (Globally Unique Identifier) representa un valor de 128 bits que es único para todos los propósitos prácticos . La representación estándar del UUID utiliza dígitos hexadecimales (octetos):
123e4567-e89b-12d3-a456-556642440000
Un UUID se compone de dígitos hexadecimales (4 caracteres cada uno) junto con 4 símbolos "-" que hacen que su longitud sea igual a 36 caracteres .
El UUID nulo es una forma especial de UUID en la que todos los bits se ponen a cero.
En este artículo, veremos la clase UUID en Java. Primero, veremos cómo usar la clase en sí. Luego, veremos los diferentes tipos de UUID y cómo podemos generarlos en Java.
2. La clase UUID
La clase UUID tiene un solo constructor:
UUID uuid = new UUID(long mostSignificant64Bits, long leastSignificant64Bits);
Si queremos usar este constructor, necesitamos proporcionar dos valores largos. Sin embargo, nos obliga a construir el patrón de bits para el UUID nosotros mismos.
Por conveniencia, existen tres métodos estáticos para crear un UUID. Estos son:
UUID uuid = UUID.nameUUIDFromBytes(byte[] bytes);
Este método crea un UUID de la versión 3 a partir de la matriz de bytes dada.
UUID uuid = UUID.randomUUID();
El método randomUUID () crea un UUID versión 4. Esta es la forma más conveniente de crear un UUID.
UUID uuid = UUID.fromString(String uuidHexDigitString);
El tercer método estático devuelve un objeto UUID dada la representación de cadena de un UUID dado.
Veamos ahora cómo está estructurado un UUID.
3. Estructura
Tomemos el UUID de ejemplo:
123e4567-e89b-42d3-a456-556642440000 xxxxxxxx-xxxx-Bxxx-Axxx-xxxxxxxxxxxx
3.1. Variante UUID
A representa la variante que determina el diseño del UUID. Todos los demás bits del UUID dependen de la configuración de los bits en el campo de variantes. La variante está determinada por los 3 bits más significativos 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)
El valor de A en el UUID mencionado es 'a'. El equivalente binario de 'a' (= 10xx) muestra la variante como 2.
3.2. Versión de UUID
B representa la versión. La versión en el UUID mencionado (valor de B ) es 4.
Java proporciona métodos para obtener variantes y versiones de UUID:
UUID uuid = UUID.randomUUID(); int variant = uuid.variant(); int version = uuid.version();
Estas son 5 versiones diferentes para los UUID de la variante 2: Basado en tiempo (UUIDv1), Seguridad DCE (UUIDv2), Basado en nombre (UUIDv3 y UUIDv5), Aleatorio (UUIDv4).
Java proporciona una implementación para v3 y v4, pero también proporciona un constructor para generar cualquier tipo de UUID:
UUID uuid = new UUID(long mostSigBits, long leastSigBits);
4. Las versiones de UUID
4.1. Versión 1
UUID versión 1 se basa en la marca de tiempo actual, medida en unidades de 100 nanosegundos desde el 15 de octubre de 1582, concatenada con la dirección MAC del dispositivo donde se crea el UUID.
Si la privacidad es un problema, la versión 1 de UUID se puede generar alternativamente con un número aleatorio de 48 bits en lugar de la dirección MAC.
En este artículo, veremos esta alternativa. Primero, generaremos los 64 bits menos y más significativos como valores largos:
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; }
Luego podemos pasar estos dos valores al constructor del UUID:
public static UUID generateType1UUID() { long most64SigBits = get64MostSignificantBitsForVersion1(); long least64SigBits = get64LeastSignificantBitsForVersion1(); return new UUID(most64SigBits, least64SigBits); }
4.2. Versión 2
La versión 2 se basa en una marca de tiempo y también en la dirección MAC. Sin embargo, RFC 4122 no especifica los detalles exactos de la generación, por lo tanto, no veremos una implementación en este artículo.
4.3. Versión 3 y 5
Los UUID se generan utilizando el hash del espacio de nombres y el nombre. Los identificadores de espacio de nombres son UUID como el sistema de nombres de dominio (DNS), identificadores de objetos (OID), URL, etc.
UUID = hash(NAMESPACE_IDENTIFIER + NAME)
La única diferencia entre UUIDv3 y UUIDv5 es el algoritmo hash: v3 usa MD5 (128 bits) mientras que v5 usa SHA-1 (160 bits).
En pocas palabras, truncamos el hash resultante a 128 bits y luego reemplazamos 4 bits por la versión y 2 bits por la variante.
Generemos UUID tipo 3:
byte[] nameSpaceBytes = bytesFromUUID(namespace); byte[] nameBytes = name.getBytes("UTF-8"); byte[] result = joinBytes(nameSpaceBytes, nameBytes); UUID uuid = UUID.nameUUIDFromBytes(result);
Aquí, es importante tener en cuenta que la cadena hexadecimal del espacio de nombres primero debe convertirse en una matriz de bytes.
Java no proporciona la implementación para el tipo 5. Consulte nuestro repositorio de código fuente para el UUIDv5.
4.4. Versión 4
La implementación de UUID v4 utiliza números aleatorios como fuente. La implementación de Java es SecureRandom , que utiliza un valor impredecible como semilla para generar números aleatorios para reducir la posibilidad de colisiones.
Generemos UUID de la versión 4:
UUID uuid = UUID.randomUUID();
Generemos una clave única usando 'SHA-256' y un UUID aleatorio:
MessageDigest salt = MessageDigest.getInstance("SHA-256"); salt.update(UUID.randomUUID().toString().getBytes("UTF-8")); String digest = bytesToHex(salt.digest());
5. Conclusión
En este artículo vimos cómo se estructura un UUID, qué variantes y versiones hay. Aprendimos para qué versiones Java proporciona una implementación lista para usar y miramos ejemplos de código para generar las otras versiones.
Y, como siempre, el código fuente de implementación está disponible en Github.