Created
November 8, 2020 20:41
-
-
Save richardstephens/d974260678cee5ee2906e71f7f9a8ab4 to your computer and use it in GitHub Desktop.
Base64 UUID with space for some flags
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package dev.richst.libs.richuuid; | |
import java.io.*; | |
import java.util.Base64; | |
import java.util.UUID; | |
public class RichUuid { | |
static byte[] uuidToByteArray(UUID uuid) { | |
try { | |
ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |
DataOutputStream dos = new DataOutputStream(bos); | |
dos.writeLong(uuid.getMostSignificantBits()); | |
dos.writeLong(uuid.getLeastSignificantBits()); | |
dos.write(2); | |
dos.flush(); | |
return bos.toByteArray(); | |
} catch (IOException ex) { | |
// this should never be thrown, and there is no sensible way to handle it | |
throw new IllegalStateException( | |
"IO exception occurred working on memory backed streams", ex); | |
} | |
} | |
static UUID byteArrayToUuid(byte[] uuidBytes) { | |
try { | |
ByteArrayInputStream bis = new ByteArrayInputStream(uuidBytes); | |
DataInputStream dis = new DataInputStream(bis); | |
long msb = dis.readLong(); | |
long lsb = dis.readLong(); | |
return new UUID(msb, lsb); | |
} catch (IOException ex) { | |
// this should never be thrown, and there is no sensible way to handle it | |
throw new IllegalStateException( | |
"IO exception occurred working on memory backed streams", ex); | |
} | |
} | |
public static String fromUUID(UUID uuid) { | |
byte[] uuidBytes = uuidToByteArray(uuid); | |
byte[] uuidBytesWithChecksum = new byte[18]; | |
int checksum = 0; | |
for (int ii = 0; ii < 16; ii++) { | |
uuidBytesWithChecksum[ii] = uuidBytes[ii]; | |
checksum += uuidBytes[ii] & 0xFF; | |
} | |
uuidBytesWithChecksum[16] = 0; | |
uuidBytesWithChecksum[17] = (byte) (checksum % 256); | |
return Base64.getUrlEncoder().encodeToString(uuidBytesWithChecksum); | |
} | |
public static String generate() { | |
return fromUUID(UUID.randomUUID()); | |
} | |
private static boolean validateChecksum(byte[] uuidBytesWithChecksum) { | |
int checksum = 0; | |
for (int ii = 0; ii < 17; ii++) { | |
checksum += uuidBytesWithChecksum[ii] & 0xFF; | |
} | |
return ((byte) checksum) == uuidBytesWithChecksum[17]; | |
} | |
private static void assertChecksumValid(byte[] uuidBytes) { | |
if (!validateChecksum(uuidBytes)) { | |
throw new InvalidRichUuidException("checksum invalid"); | |
} | |
} | |
public static UUID toUUID(String richUuid) { | |
byte[] uuidBytesWithChecksum; | |
try { | |
uuidBytesWithChecksum = Base64.getUrlDecoder().decode(richUuid); | |
} catch (IllegalArgumentException ex) { | |
throw new InvalidRichUuidException("Could not base64 decode richUuid", ex); | |
} | |
if (uuidBytesWithChecksum.length != 18) { | |
throw new InvalidRichUuidException("UUID length invalid"); | |
} | |
assertChecksumValid(uuidBytesWithChecksum); | |
return byteArrayToUuid(uuidBytesWithChecksum); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment