The near-equivalent class in Java is java.util.UUID
. However, as you've noticed, the two do not give the same byte arrays. But if you execute the following and look at the array given by Java versus the array given by .NET:
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.UUID;
public class Main {
// expected from your question
private static final int[] EXPECTED_BYTES = {
185, 242, 54, 152, 140, 186, 166, 66, 184, 132, 46, 158, 237, 159, 185, 90
};
public static void main(String[] args) {
UUID uuid = UUID.fromString("9836f2b9-ba8c-42a6-b884-2e9eed9fb95a");
byte[] array = toByteArray(uuid);
System.out.println("EXPECTED: " + Arrays.toString(EXPECTED_BYTES));
System.out.println("ACTUAL : " + Arrays.toString(toUnsignedInts(array)));
}
private static byte[] toByteArray(UUID uuid) {
return ByteBuffer.allocate(16)
.putLong(uuid.getMostSignificantBits())
.putLong(uuid.getLeastSignificantBits())
.array();
}
// for visual purposes only
private static int[] toUnsignedInts(byte[] array) {
int[] result = new int[array.length];
for (int i = 0; i < array.length; i++) {
result[i] = Byte.toUnsignedInt(array[i]);
}
return result;
}
}
And the output:
EXPECTED: [185, 242, 54, 152, 140, 186, 166, 66, 184, 132, 46, 158, 237, 159, 185, 90]
ACTUAL : [152, 54, 242, 185, 186, 140, 66, 166, 184, 132, 46, 158, 237, 159, 185, 90]
You'll see the arrays are almost equal, it's just the order of some bytes don't match. The last eight bytes (i.e. the least significant bits) all match, but the first four bytes are reversed, the next two bytes are reversed, and so are the next two bytes. To see it visually:
EXPECTED: [185, 242, 54, 152, 140, 186, 166, 66, 184, 132, 46, 158, 237, 159, 185, 90]
ACTUAL : [152, 54, 242, 185, 186, 140, 66, 166, 184, 132, 46, 158, 237, 159, 185, 90]
|---------------| |------| |-----|
I don't know enough to explain why this difference exists, but this comment on an answer to a question you linked to says:
See also [Universally unique identifier - Wikipedia] "Many systems encode the UUID entirely in a big-endian format." "Other systems, notably Microsoft's marshalling of UUIDs in their COM/OLE libraries, use a mixed-endian format, whereby the first three components of the UUID are little-endian, and the last two are big-endian." – Denis Dec 20 '19 at 13:06
The answer that comment is on gives a solution to your problem, which you've included in your question. That solution simply swaps bytes around to get the desired effect. Here's another solution that doesn't involve creating a copy array:
private static byte[] toByteArray(UUID uuid) {
long mostSigBits = uuid.getMostSignificantBits();
return ByteBuffer.allocate(16)
.order(ByteOrder.LITTLE_ENDIAN)
.putInt((int) (mostSigBits >> 32))
.putShort((short) (((int) mostSigBits) >> 16))
.putShort((short) mostSigBits)
.order(ByteOrder.BIG_ENDIAN)
.putLong(uuid.getLeastSignificantBits())
.array();
}
Note: I'm not very comfortable with bit-shifting, so there may be a more succinct way of accomplishing the above that I couldn't think of.
Which gives the following output:
EXPECTED: [185, 242, 54, 152, 140, 186, 166, 66, 184, 132, 46, 158, 237, 159, 185, 90]
ACTUAL : [185, 242, 54, 152, 140, 186, 166, 66, 184, 132, 46, 158, 237, 159, 185, 90]
Warning: Unfortunately, I'm not sure you can rely on either workaround giving the correct bytes 100% of the time.