I have a legacy identifier with a reference implementation is JS. I need to generate IDs in Java.
I rarely have to think about bitwise operations, so this problem started out frustrating, but I developed an appreciation for the elegance of binary, hex and bitwise operations as I warmed up, and was reluctant to trade them in for the relatively self-documenting Java syntax at the end.
We use an array of 8-bit, unsigned ints:
var ints = new Uint8Array(8)
Presumably, this is because unsigned ints are byte-like (0-255).
We populate this array with random values:
We get the last (random) 4 bits of the first byte using the AND operator against 1111 (0xF in hex):
var rand = 0xF & ints
We prepend 0111 by adding 011100000 (0x70 in hex):
ints = 0x70 + rand
I think this may be due to max long in Java, ie
Long.MAX_VALUE == 0x7FFF_FFFF_FFFF_FFFFL.
We convert this to an array of chars and then base64 encode:
I think the base64 encoding is to retain the integrity of the “bytes”.
> atob("ekMJT1sVNBc=").split('').map(c=>c.charCodeAt(0)) < [122, 67, 9, 79, 91, 21, 52, 23]
Java makes this easier with native 64 bit long, byte primitives and convenience classes. Java REPL makes it easy to hack around.
import java.nio.ByteBuffer import java.util.Base64 String encoded = "ekMJT1sVNBc=" byte bytes = Base64.getDecoder().decode(encoded) long id = ByteBuffer.wrap(bytes).getLong()
Generate a random long within a range 0x7…:
import java.util.Random long id = new Random().longs(0x7000_0000_0000_0000L, Long.MAX_VALUE).limit(1).findFirst().getAsLong()
Convert to bytes:
byte bytes = ByteBuffer.allocate(Long.BYTES).putLong(id).array()