39

I am converting UUID to byte using this code

public byte[] getIdAsByte(UUID uuid)
{
    ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
    bb.putLong(uuid.getMostSignificantBits());
    bb.putLong(uuid.getLeastSignificantBits());
    return bb.array();
}

However, if I try to recreate the UUID using this function,

public UUID frombyte(byte[] b)
{
    return UUID.nameUUIDFromBytes(b);
}

It is not the same UUID. Converting a randomUUID back and forth returns two different it.

UUID u = UUID.randomUUID();
System.out.println(u.toString());
System.out.println(frombyte(getIdAsByte(u)).toString());

prints:

1ae004cf-0f48-469f-8a94-01339afaec41
8b5d1a71-a4a0-3b46-bec3-13ab9ab12e8e
yatul
  • 1,103
  • 12
  • 27
Anon21
  • 2,961
  • 6
  • 37
  • 46
  • Related, possible duplicate: [What namespace does the JDK use to generate a UUID with nameUUIDFromBytes?](http://stackoverflow.com/questions/9504519/what-namespace-does-the-jdk-use-to-generate-a-uuid-with-nameuuidfrombytes) – Daniel Pryden Jul 27 '13 at 02:28

2 Answers2

84
public class UuidUtils {
  public static UUID asUuid(byte[] bytes) {
    ByteBuffer bb = ByteBuffer.wrap(bytes);
    long firstLong = bb.getLong();
    long secondLong = bb.getLong();
    return new UUID(firstLong, secondLong);
  }

  public static byte[] asBytes(UUID uuid) {
    ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
    bb.putLong(uuid.getMostSignificantBits());
    bb.putLong(uuid.getLeastSignificantBits());
    return bb.array();
  }
}

@Test
public void verifyUUIDBytesCanBeReconstructedBackToOriginalUUID() {
  UUID u = UUID.randomUUID();
  byte[] uBytes = UuidUtils.asBytes(u);
  UUID u2 = UuidUtils.asUuid(uBytes);
  Assert.assertEquals(u, u2);
}

@Test
public void verifyNameUUIDFromBytesMethodDoesNotRecreateOriginalUUID() {
  UUID u = UUID.randomUUID();
  byte[] uBytes = UuidUtils.asBytes(u);
  UUID u2 = UUID.nameUUIDFromBytes(uBytes);
  Assert.assertNotEquals(u, u2);
}
Brice Roncace
  • 10,110
  • 9
  • 60
  • 69
  • 2
    This implies everybody agrees on little-endian representation. – Pedro Lamarão Jun 03 '15 at 21:55
  • why would you have firstLong == secondLong with twice the same computation? This parameter is supposed to be the least/most significative bits in the byte representation. Any opinion? – belka Oct 03 '17 at 14:06
  • Is this little endian? The ByteBuffer itself is going to start with a BIG_ENDIAN order. – user988346 Jun 21 '18 at 16:54
  • Yes. This was tested using x86 (little-endian) based processors. – Brice Roncace Jun 22 '18 at 15:09
  • 3
    @Brice I don't believe "using x86 (little-endian) based processors" is relevant. The [`ByteBuffer`](https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/nio/ByteBuffer.html) class has an independent endianness and "_The initial order of a byte buffer is always BIG_ENDIAN_". – Slaw Feb 27 '20 at 00:19
20

that's because nameUUIDFromBytes constructs a specific kind of UUID (as the javadoc states).

if you want to convert a byte[] back to a UUID, you should use the UUID constructor. Wrap a ByteBuffer around the byte[], read the 2 longs and pass them to the UUID constructor.

jtahlborn
  • 52,909
  • 5
  • 76
  • 118
  • 5
    An example code for this would be: `ByteBuffer bb = ByteBuffer.wrap(inputByteArray); long firstLong = bb.getLong(); long secondLong = bb.getLong(); return new UUID(firstLong, secondLong);` – djvdorp Nov 06 '13 at 11:54
  • What if access to the UUID contructor is restricted like in minecraft? I have that problem because Im trying to condense a UUID and some data down to bytes in one big file to create a Shop characteristic of a Plugin for a bukkit server. the file is of binary in array : [0] UUID [1] money [2] points. This would just repeat going down the list in the file. – AMDG Aug 17 '14 at 02:22
  • 3
    @LinkTheProgrammer - if you have a different problem, then you should probably open a new question. – jtahlborn Aug 18 '14 at 01:27