Add static methods for extracting time and random components #9
Add static methods to Ulid: - Ulid.getInstant(String); - Ulid.getTime(String); - Ulid.getRandom(String); List of changes: Updated Ulid Updated test cases Updated README.md Test coverage 99.4%
This commit is contained in:
		
							parent
							
								
									b5b262be42
								
							
						
					
					
						commit
						1dffbf1ebb
					
				
							
								
								
									
										24
									
								
								README.md
								
								
								
								
							
							
						
						
									
										24
									
								
								README.md
								
								
								
								
							| 
						 | 
				
			
			@ -35,14 +35,11 @@ Add these lines to your `pom.xml`.
 | 
			
		|||
<dependency>
 | 
			
		||||
  <groupId>com.github.f4b6a3</groupId>
 | 
			
		||||
  <artifactId>ulid-creator</artifactId>
 | 
			
		||||
  <version>3.0.1</version>
 | 
			
		||||
  <version>3.1.0</version>
 | 
			
		||||
</dependency>
 | 
			
		||||
```
 | 
			
		||||
See more options in [maven.org](https://search.maven.org/artifact/com.github.f4b6a3/ulid-creator).
 | 
			
		||||
 | 
			
		||||
Implementation
 | 
			
		||||
------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
### ULID
 | 
			
		||||
 | 
			
		||||
The ULID is a 128 bit long identifier. The first 48 bits represent the count of milliseconds since Unix Epoch, 1970-01-01. The remaining 80 bits are generated by a secure random number generator.
 | 
			
		||||
| 
						 | 
				
			
			@ -168,25 +165,40 @@ Get the creation instant of a ULID:
 | 
			
		|||
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 the time component of a ULID:
 | 
			
		||||
 | 
			
		||||
```java
 | 
			
		||||
long time = ulid.getTime(); // 1171591994633
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```java
 | 
			
		||||
// static method
 | 
			
		||||
long time = Ulid.getTime("0123456789ABCDEFGHJKMNPQRS"); // 1171591994633
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Get the random component of a ULID:
 | 
			
		||||
 | 
			
		||||
```java
 | 
			
		||||
byte[] random = ulid.getRandom(); // 10 bytes (80 bits)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```java
 | 
			
		||||
// static method
 | 
			
		||||
byte[] random = Ulid.getRandom("0123456789ABCDEFGHJKMNPQRS"); // 10 bytes (80 bits)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Use a `UlidFactory` instance with `java.util.Random` to generate ULIDs:
 | 
			
		||||
 | 
			
		||||
```java
 | 
			
		||||
Random random = new Random();
 | 
			
		||||
UlidFactory factory = UlidCreator.getDefaultFactory().withRandomGenerator(random::nextBytes);
 | 
			
		||||
 | 
			
		||||
Ulid ulid = facory.create();
 | 
			
		||||
Ulid ulid = factory.create();
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Use a `UlidFactory` instance with any random generator you like(*) to generate ULIDs:
 | 
			
		||||
| 
						 | 
				
			
			@ -196,7 +208,7 @@ import com.github.niceguy.random.AwesomeRandom; // a hypothetical RNG
 | 
			
		|||
AwesomeRandom awesomeRandom = new AwesomeRandom();
 | 
			
		||||
UlidFactory factory = UlidCreator.getDefaultFactory().withRandomGenerator(awesomeRandom::nextBytes);
 | 
			
		||||
 | 
			
		||||
Ulid ulid = facory.create();
 | 
			
		||||
Ulid ulid = factory.create();
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
(*) since it provides a void method like `nextBytes(byte[])`.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -423,6 +423,18 @@ public final class Ulid implements Serializable, Comparable<Ulid> {
 | 
			
		|||
		return Instant.ofEpochMilli(this.getTime());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns the instant of creation.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * The instant of creation is extracted from the time component.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param string a canonical string
 | 
			
		||||
	 * @return {@link Instant}
 | 
			
		||||
	 */
 | 
			
		||||
	public static Instant getInstant(String string) {
 | 
			
		||||
		return Instant.ofEpochMilli(getTime(string));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns the time component as a number.
 | 
			
		||||
	 * 
 | 
			
		||||
| 
						 | 
				
			
			@ -435,6 +447,35 @@ public final class Ulid implements Serializable, Comparable<Ulid> {
 | 
			
		|||
		return this.msb >>> 16;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns the time component as a number.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * The time component is a number between 0 and 2^48-1. It is equivalent to the
 | 
			
		||||
	 * count of milliseconds since 1970-01-01 (Unix epoch).
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param string a canonical string
 | 
			
		||||
	 * @return a number of milliseconds.
 | 
			
		||||
	 */
 | 
			
		||||
	public static long getTime(String string) {
 | 
			
		||||
 | 
			
		||||
		final char[] chars = toCharArray(string);
 | 
			
		||||
 | 
			
		||||
		long time = 0;
 | 
			
		||||
 | 
			
		||||
		time |= ALPHABET_VALUES[chars[0x00]] << 45;
 | 
			
		||||
		time |= ALPHABET_VALUES[chars[0x01]] << 40;
 | 
			
		||||
		time |= ALPHABET_VALUES[chars[0x02]] << 35;
 | 
			
		||||
		time |= ALPHABET_VALUES[chars[0x03]] << 30;
 | 
			
		||||
		time |= ALPHABET_VALUES[chars[0x04]] << 25;
 | 
			
		||||
		time |= ALPHABET_VALUES[chars[0x05]] << 20;
 | 
			
		||||
		time |= ALPHABET_VALUES[chars[0x06]] << 15;
 | 
			
		||||
		time |= ALPHABET_VALUES[chars[0x07]] << 10;
 | 
			
		||||
		time |= ALPHABET_VALUES[chars[0x08]] << 5;
 | 
			
		||||
		time |= ALPHABET_VALUES[chars[0x09]];
 | 
			
		||||
 | 
			
		||||
		return time;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns the random component as a byte array.
 | 
			
		||||
	 * 
 | 
			
		||||
| 
						 | 
				
			
			@ -443,8 +484,71 @@ public final class Ulid implements Serializable, Comparable<Ulid> {
 | 
			
		|||
	 * @return a byte array
 | 
			
		||||
	 */
 | 
			
		||||
	public byte[] getRandom() {
 | 
			
		||||
 | 
			
		||||
		final byte[] bytes = new byte[RANDOM_BYTES_LENGTH];
 | 
			
		||||
		System.arraycopy(this.toBytes(), TIME_BYTES_LENGTH, bytes, 0, RANDOM_BYTES_LENGTH);
 | 
			
		||||
 | 
			
		||||
		bytes[0x0] = (byte) (msb >>> 8);
 | 
			
		||||
		bytes[0x1] = (byte) (msb);
 | 
			
		||||
 | 
			
		||||
		bytes[0x2] = (byte) (lsb >>> 56);
 | 
			
		||||
		bytes[0x3] = (byte) (lsb >>> 48);
 | 
			
		||||
		bytes[0x4] = (byte) (lsb >>> 40);
 | 
			
		||||
		bytes[0x5] = (byte) (lsb >>> 32);
 | 
			
		||||
		bytes[0x6] = (byte) (lsb >>> 24);
 | 
			
		||||
		bytes[0x7] = (byte) (lsb >>> 16);
 | 
			
		||||
		bytes[0x8] = (byte) (lsb >>> 8);
 | 
			
		||||
		bytes[0x9] = (byte) (lsb);
 | 
			
		||||
 | 
			
		||||
		return bytes;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns the random component as a byte array.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * The random component is an array of 10 bytes (80 bits).
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param string a canonical string
 | 
			
		||||
	 * @return a byte array
 | 
			
		||||
	 */
 | 
			
		||||
	public static byte[] getRandom(String string) {
 | 
			
		||||
 | 
			
		||||
		final char[] chars = toCharArray(string);
 | 
			
		||||
 | 
			
		||||
		long random0 = 0;
 | 
			
		||||
		long random1 = 0;
 | 
			
		||||
 | 
			
		||||
		random0 |= ALPHABET_VALUES[chars[0x0a]] << 35;
 | 
			
		||||
		random0 |= ALPHABET_VALUES[chars[0x0b]] << 30;
 | 
			
		||||
		random0 |= ALPHABET_VALUES[chars[0x0c]] << 25;
 | 
			
		||||
		random0 |= ALPHABET_VALUES[chars[0x0d]] << 20;
 | 
			
		||||
		random0 |= ALPHABET_VALUES[chars[0x0e]] << 15;
 | 
			
		||||
		random0 |= ALPHABET_VALUES[chars[0x0f]] << 10;
 | 
			
		||||
		random0 |= ALPHABET_VALUES[chars[0x10]] << 5;
 | 
			
		||||
		random0 |= ALPHABET_VALUES[chars[0x11]];
 | 
			
		||||
 | 
			
		||||
		random1 |= ALPHABET_VALUES[chars[0x12]] << 35;
 | 
			
		||||
		random1 |= ALPHABET_VALUES[chars[0x13]] << 30;
 | 
			
		||||
		random1 |= ALPHABET_VALUES[chars[0x14]] << 25;
 | 
			
		||||
		random1 |= ALPHABET_VALUES[chars[0x15]] << 20;
 | 
			
		||||
		random1 |= ALPHABET_VALUES[chars[0x16]] << 15;
 | 
			
		||||
		random1 |= ALPHABET_VALUES[chars[0x17]] << 10;
 | 
			
		||||
		random1 |= ALPHABET_VALUES[chars[0x18]] << 5;
 | 
			
		||||
		random1 |= ALPHABET_VALUES[chars[0x19]];
 | 
			
		||||
 | 
			
		||||
		final byte[] bytes = new byte[RANDOM_BYTES_LENGTH];
 | 
			
		||||
 | 
			
		||||
		bytes[0x0] = (byte) (random0 >>> 32);
 | 
			
		||||
		bytes[0x1] = (byte) (random0 >>> 24);
 | 
			
		||||
		bytes[0x2] = (byte) (random0 >>> 16);
 | 
			
		||||
		bytes[0x3] = (byte) (random0 >>> 8);
 | 
			
		||||
		bytes[0x4] = (byte) (random0);
 | 
			
		||||
		
 | 
			
		||||
		bytes[0x5] = (byte) (random1 >>> 32);
 | 
			
		||||
		bytes[0x6] = (byte) (random1 >>> 24);
 | 
			
		||||
		bytes[0x7] = (byte) (random1 >>> 16);
 | 
			
		||||
		bytes[0x8] = (byte) (random1 >>> 8);
 | 
			
		||||
		bytes[0x9] = (byte) (random1);
 | 
			
		||||
 | 
			
		||||
		return bytes;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -281,20 +281,29 @@ public class UlidTest {
 | 
			
		|||
	public void testGetTimeAndGetRandom() {
 | 
			
		||||
 | 
			
		||||
		long time = 0;
 | 
			
		||||
		byte[] bytes = new byte[10];
 | 
			
		||||
		byte[] bytes = new byte[Ulid.RANDOM_BYTES_LENGTH];
 | 
			
		||||
		Random random = new Random();
 | 
			
		||||
 | 
			
		||||
		for (int i = 0; i < 100; i++) {
 | 
			
		||||
 | 
			
		||||
			time = random.nextLong() & TIME_MASK;
 | 
			
		||||
			random.nextBytes(bytes);
 | 
			
		||||
			Ulid ulid = new Ulid(time, bytes);
 | 
			
		||||
 | 
			
		||||
			// Instance methods
 | 
			
		||||
			Ulid ulid = new Ulid(time, bytes);
 | 
			
		||||
			assertEquals(time, ulid.getTime()); // test Ulid.getTime()
 | 
			
		||||
			assertEquals(Instant.ofEpochMilli(time), ulid.getInstant()); // test Ulid.getInstant()
 | 
			
		||||
			for (int j = 0; j < bytes.length; j++) {
 | 
			
		||||
				assertEquals(bytes[j], ulid.getRandom()[j]); // test Ulid.getRandom()
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Static methods
 | 
			
		||||
			String string = new Ulid(time, bytes).toString();
 | 
			
		||||
			assertEquals(time, Ulid.getTime(string)); // test Ulid.getTime()
 | 
			
		||||
			assertEquals(Instant.ofEpochMilli(time), Ulid.getInstant(string)); // test Ulid.getInstant()
 | 
			
		||||
			for (int j = 0; j < bytes.length; j++) {
 | 
			
		||||
				assertEquals(bytes[j], Ulid.getRandom(string)[j]); // test Ulid.getRandom()
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue