PostgreSQL:
create extension if not exists "uuid-ossp"; select uuid_generate_v3(uuid_nil(), 'this is a test'); uuid_generate_v3 -------------------------------------- e1e27115-9f5b-366d-90e8-e07b1b36b99c (1 row)
Java:
java> java.util.UUID.nameUUIDFromBytes("this is a test".getBytes()); java.util.UUID res9 = 54b0c58c-7ce9-32a8-b551-351102ee0938
How do I generate the same UUID’s in Java as PostgreSQL does?
Advertisement
Answer
The algorithm for generating a version 3 UUID is described here https://www.rfc-editor.org/rfc/rfc4122#section-4.3
But the key steps are:
- Allocate a UUID to use as a “name space ID” for all UUIDs generated from names in that name space.
- Choose either MD5 or SHA-1 as the hash algorithm
- Convert the name to a canonical sequence of octets
- Compute the hash of the name space ID concatenated with the name.
- Change certain bytes of the to predefined values (see link above)
- Convert the resulting UUID to local byte order.
The postgres function signature is uuid_generate_v3(namespace uuid, name text)
so it takes the namespace UUID and name
as arguments.
The Java method nameUUIDFromBytes(byte[] name)
takes only the name
and hashes it with MD5 to create the UUID. To get the same output as with PostgreSQL you have to concatenate the the namespace bytes and the name
bytes together yourself.
For namespace you have used uuid_nil()
(all zeroes) which is new UUID(0L, 0L)
in Java.
Putting it all together this would look something like this:
byte[] bytes = Arrays.concatenate(toByteArray(new UUID(0L, 0L)), "this is a test".getBytes(StandardCharsets.UTF_8)); System.out.println(UUID.nameUUIDFromBytes(bytes)); // prints out e1e27115-9f5b-366d-90e8-e07b1b36b99c
And you can convert the namespace UUID to byte array like so:
private static byte[] toByteArray(UUID uuid) { ByteBuffer bb = ByteBuffer.wrap(new byte[16]); bb.putLong(uuid.getMostSignificantBits()); bb.putLong(uuid.getLeastSignificantBits()); return bb.array(); }