You can convert the UUID into a String which is really a sequence of 16-bit char
8 elements long as follows.
static String encodeUuid(final UUID id) {
final long hi = id.getMostSignificantBits();
final long lo = id.getLeastSignificantBits();
return new String(new char[] {
(char) ((hi >>> 48) & 0xffff), (char) ((hi >>> 32) & 0xffff),
(char) ((hi >>> 16) & 0xffff), (char) ((hi ) & 0xffff),
(char) ((lo >>> 48) & 0xffff), (char) ((lo >>> 32) & 0xffff),
(char) ((lo >>> 16) & 0xffff), (char) ((lo ) & 0xffff)
});
}
static UUID decodeUuid(final String enc) {
final char[] cs = enc.toCharArray();
return new UUID(
(long) cs[0] << 48 | (long) cs[1] << 32 | (long) cs[2] << 16 | (long) cs[3],
(long) cs[4] << 48 | (long) cs[5] << 32 | (long) cs[6] << 16 | (long) cs[7]
);
}
This code indeed seems like it should work (try it yourself here), and can be encoded/decoded using both UTF-8 and UTF-16 without issue the majority of the time:
static boolean validate(final UUID id, final Charset cs) {
final ByteBuffer buf = cs.encode(encodeUuid(id));
final UUID _id = decodeUuid(cs.decode(buf).toString());
return id.equals(_id);
}
public static void main(final String[] argv) {
final UUID id = UUID.randomUUID();
assert validate(id, StandardCharsets.UTF_8) : "failed using utf-8";
assert validate(id, StandardCharsets.UTF_16) : "failed using utf-16";
}
C:\dev\scrap>javac UuidTest.java
C:\dev\scrap>java -ea UuidTest
However there is indeed the problem that some UTF-16 code points are reserved as surrogates. In the case this happens, the encoding will not work and you will be unable to reconstruct the original UUID. Refer to Mechanical snail's response above for more information on that.
The only data you can consistently actually remove from an encoded UUID generated via UUID.randomUUID are those 2 used for variant
(always 2
) and the 4 bits used for version
(always 4
).
There exist different variants of these global identifiers. The methods of this class are for manipulating the Leach-Salz variant, although the constructors allow the creation of any variant of UUID (described below).
The layout of a variant 2 (Leach-Salz) UUID is as follows: The most significant long consists of the following unsigned fields:
0xFFFFFFFF00000000 time_low
0x00000000FFFF0000 time_mid
0x000000000000F000 version
0x0000000000000FFF time_hi
The least significant long consists of the following unsigned fields:
0xC000000000000000 variant
0x3FFF000000000000 clock_seq
0x0000FFFFFFFFFFFF node
The variant field contains a value which identifies the layout of the UUID
. The bit layout described above is valid only for a UUID
with a variant value of 2, which indicates the Leach-Salz variant.
The version field holds a value that describes the type of this UUID
. There are four different basic types of UUIDs: time-based, DCE security, name-based, and randomly generated UUIDs. These types have a version value of 1, 2, 3 and 4, respectively.