ULID Creator ====================================================== This is a Java implementation of [Universally Unique Lexicographically Sortable Identifier](https://github.com/ulid/spec). In summary: * Sorted by generation time; * Can be stored as a UUID/GUID; * Can be stored as a string of 26 chars; * Can be stored as an array of 16 bytes; * String format is encoded to [Crockford's base32](https://www.crockford.com/base32.html); * String format is URL safe, is case insensitive, and has no hyphens. This project contains a [micro benchmark](https://github.com/f4b6a3/ulid-creator/tree/master/benchmark) and a good amount of [unit tests](https://github.com/f4b6a3/ulid-creator/tree/master/src/test/java/com/github/f4b6a3/ulid). The jar file can be downloaded directly from [maven.org](https://repo1.maven.org/maven2/com/github/f4b6a3/ulid-creator/). Read the [Javadocs](https://javadoc.io/doc/com.github.f4b6a3/ulid-creator). Usage ------------------------------------------------------ Create a ULID: ```java Ulid ulid = UlidCreator.getUlid(); ``` Create a Monotonic ULID: ```java Ulid ulid = UlidCreator.getMonotonicUlid(); ``` ### Dependency Add these lines to your `pom.xml`. ```xml com.github.f4b6a3 ulid-creator 5.2.1 ``` See more options in [maven.org](https://search.maven.org/artifact/com.github.f4b6a3/ulid-creator). ### Modularity Module and bundle names are the same as the root package name. - JPMS module name: `com.github.f4b6a3.ulid` - OSGi symbolic name: `com.github.f4b6a3.ulid` ### ULID ULID is a 128-bit identifier. The first 48 bits represent the number of milliseconds since Unix Epoch, 1970-01-01. The remaining 80 bits are generated by a secure random number generator. Its canonical string representation is 26 characters long. ```java // Generate a ULID Ulid ulid = UlidCreator.getUlid(); ``` Structure of a series of ULIDs: ```text 01EX8Y21KBH49ZZCA7KSKH6X1C 01EX8Y21KBJTFK0JV5J20QPQNR 01EX8Y21KBG2CS1V6WQCTVM7K6 01EX8Y21KB8HPZNBP3PTW7HVEY 01EX8Y21KB3HZV38VAPTPAG1TY 01EX8Y21KB9FTEJHPAGAKYG9Z8 01EX8Y21KBQGKGH2SVPQAYEFFC 01EX8Y21KBY17J9WR9KQR8SE7H 01EX8Y21KCVHYSJGVK4HBXDMR9 < millisecond changed 01EX8Y21KC668W3PEDEAGDHMVG 01EX8Y21KC53D2S5ADQ2EST327 01EX8Y21KCPQ3TENMTY1S7HV56 01EX8Y21KC3755QF9STQEV05EB 01EX8Y21KC5ZSHK908GMDK69WE 01EX8Y21KCSGJS8S1FVS06B3SX 01EX8Y21KC6ZBWQ0JBV337R1CN ^ look |---------|--------------| time random ``` ### Monotonic ULID Monotonic ULID is a variant of ULID. The random component is incremented by 1 whenever the current millisecond equals the previous millisecond. Its main advantage is *speed*. ```java // Generate a Monotonic ULID Ulid ulid = UlidCreator.getMonotonicUlid(); ``` Structure of a series of Monotonic ULIDs: ```text 01EX8Y7M8MDVX3M3EQG69EEMJW 01EX8Y7M8MDVX3M3EQG69EEMJX 01EX8Y7M8MDVX3M3EQG69EEMJY 01EX8Y7M8MDVX3M3EQG69EEMJZ 01EX8Y7M8MDVX3M3EQG69EEMK0 01EX8Y7M8MDVX3M3EQG69EEMK1 01EX8Y7M8MDVX3M3EQG69EEMK2 01EX8Y7M8MDVX3M3EQG69EEMK3 01EX8Y7M8N1G30CYF2PJR23J2J < millisecond changed 01EX8Y7M8N1G30CYF2PJR23J2K 01EX8Y7M8N1G30CYF2PJR23J2M 01EX8Y7M8N1G30CYF2PJR23J2N 01EX8Y7M8N1G30CYF2PJR23J2P 01EX8Y7M8N1G30CYF2PJR23J2Q 01EX8Y7M8N1G30CYF2PJR23J2R 01EX8Y7M8N1G30CYF2PJR23J2S ^ look ^ look |---------|--------------| time random ``` ### Hash ULID Hash ULID is a "non-standard" variant of ULID. It always returns the same ULID for a specific pair of arguments. It has the same basic structure as a ULID, except that the random component is replaced with the first 10 bytes of an SHA-256 hash. ```java // Generate a Hash ULID of a string long time = file.getCreatedAt(); String name = file.getFileName(); Ulid ulid = UlidCreator.getHashUlid(time, name); ``` ```java // Generate a Hash ULID of a byte array long time = file.getCreatedAt(); byte[] bytes = file.getFileBinary(); Ulid ulid = UlidCreator.getHashUlid(time, bytes); ``` Structure of Hash ULIDs: ```text 01GZ8AR53SE5XCA1MN1PGCSDJ0 |---------|--------------| time hash ``` ### More Examples Create a quick ULID: ```java Ulid ulid = Ulid.fast(); ``` --- Create a ULID from a canonical string (26 chars): ```java Ulid ulid = Ulid.from("0123456789ABCDEFGHJKMNPQRS"); ``` --- Convert a ULID into a canonical string in lower case: ```java String string = ulid.toLowerCase(); // 0123456789abcdefghjkmnpqrs ``` --- Convert a ULID into a UUID: ```java UUID uuid = ulid.toUuid(); // 0110c853-1d09-52d8-d73e-1194e95b5f19 ``` --- Convert a ULID into a [RFC-4122](https://tools.ietf.org/html/rfc4122) UUID v4: ```java UUID uuid = ulid.toRfc4122().toUuid(); // 0110c853-1d09-42d8-973e-1194e95b5f19 // ^ UUID v4 ``` --- Get the creation instant of a ULID: ```java Instant instant = ulid.getInstant(); // 2007-02-16T02:13:14.633Z ``` ```java // static method Instant instant = Ulid.getInstant("0123456789ABCDEFGHJKMNPQRS"); // 2007-02-16T02:13:14.633Z ``` Get only the time component substring: ```java String ulidTimePart = ulid.toString() .substring(0, Ulid.TIME_CHARS); // 0123456789 ``` Get only the random component substring: ```java String ulidRandPart = ulid.toString() .substring(Ulid.TIME_CHARS, Ulid.RANDOM_CHARS); // ABCDEFGHJKMNPQRS ``` Insert a string between the time and random components efficiently (avoiding concatenation) ([#29](https://github.com/f4b6a3/ulid-creator/pull/29)): ```java String ulidExpanded = new StringBuilder(ulid.toString()) .insert(Ulid.TIME_CHARS, "-INSERTED-") .toString(); // 0123456789-INSERTED-ABCDEFGHJKMNPQRS ``` --- A key generator that makes substitution easy if necessary: ```java package com.example; import com.github.f4b6a3.ulid.UlidCreator; public class KeyGenerator { public static String next() { return UlidCreator.getUlid().toString(); } } ``` ```java // use the generator String key = KeyGenerator.next(); ``` --- A `UlidFactory` with `java.util.Random`: ```java // use a `java.util.Random` instance for fast generation UlidFactory factory = UlidFactory.newInstance(new Random()); ``` ```java // use the factory Ulid ulid = factory.create(); ``` --- A `UlidFactory` with `RandomGenerator` (JDK 17+): ```java // use a random function that returns a long value RandomGenerator random = RandomGenerator.getDefault(); UlidFactory factory = UlidFactory.newInstance(() -> random.nextLong()); ``` ```java // use the factory Ulid ulid = factory.create(); ``` --- Benchmark ------------------------------------------------------ This section shows benchmarks comparing `UlidCreator` to `UUID.randomUUID()`. ``` -------------------------------------------------------------------------------- THROUGHPUT (operations/msec) Mode Cnt Score Error Units -------------------------------------------------------------------------------- UUID_randomUUID thrpt 5 1787,601 ± 489,482 ops/ms ( 1.0) UUID_randomUUID_toString thrpt 5 1598,467 ± 93,067 ops/ms - - - - - - - - - - - - - - - - - - - - - - - - - - - Ulid_fast thrpt 5 100521,737 ±27132,748 ops/ms (56.2) Ulid_fast_toString thrpt 5 50529,743 ± 8970,574 ops/ms - - - - - - - - - - - - - - - - - - - - - - - - - - - UlidCreator_getUlid thrpt 5 2443,810 ± 379,149 ops/ms ( 1.3) UlidCreator_getUlid_toString thrpt 5 2200,047 ± 539,767 ops/ms - - - - - - - - - - - - - - - - - - - - - - - - - - - UlidCreator_getMonotonicUlid thrpt 5 9845,810 ± 1239,148 ops/ms ( 5.5) UlidCreator_getMonotonicUlid_toString thrpt 5 5748,568 ± 549,121 ops/ms - - - - - - - - - - - - - - - - - - - - - - - - - - - UlidCreator_getHashUlid thrpt 5 6651,239 ± 2541,774 ops/ms UlidCreator_getHashUlidString thrpt 5 6043,582 ± 1879,042 ops/ms -------------------------------------------------------------------------------- Total time: 00:03:22 -------------------------------------------------------------------------------- ``` System: CPU i7-8565U, 16G RAM, Ubuntu 22.04, JVM 11, rng-tools installed. To execute the benchmark, run `./benchmark/run.sh`. Other identifier generators ------------------------------------------- Check out the other ID generators from the same family: * [UUID Creator](https://github.com/f4b6a3/uuid-creator): Universally Unique Identifiers * [TSID Creator](https://github.com/f4b6a3/tsid-creator): Time Sortable Identifiers * [KSUID Creator](https://github.com/f4b6a3/ksuid-creator): K-Sortable Globally Unique Identifiers License ------------------------------------------------------ This library is Open Source software released under the [MIT license](https://opensource.org/licenses/MIT).