Generating unique IDs

When identifiers are used solely within a database, their generation should be left to the database itself. (See Statement.getGeneratedKeys.)

Unique identifiers which are "published" in some way may need special treatment, since the identifier may need to be difficult to guess or forge. A typical example is the value of a cookie used as a session identifier - simply using a series of consecutive integers is generally unacceptable, since one user could easily impersonate another by altering the value of the cookie to some nearby integer.

Style 1 - UUID

Starting with Java 5, the UUID class provides a simple means for generating unique ids. The identifiers generated by UUID are actually universally unique identifiers.

Example

import java.util.UUID;

public class GenerateUUID {
  
  public static final void main(String... args){
    //generate random UUIDs
    UUID idOne = UUID.randomUUID();
    UUID idTwo = UUID.randomUUID();
    log("UUID One: " + idOne);
    log("UUID Two: " + idTwo);
  }
  
  private static void log(Object object){
    System.out.println( String.valueOf(object) );
  }
} 

Example run:

>java -cp . GenerateUUID
UUID One: 067e6162-3b6f-4ae2-a171-2470b63dff00 
UUID Two: 54947df8-0e9e-4471-a2f9-9af509fb5889

If Java 5 is not available, then there are other more laborious ways to generate unique ids (see below).

Style 2 - SecureRandom and MessageDigest

The following method uses SecureRandom and MessageDigest:

The MessageDigest class is suitable for generating a "one-way hash" of  arbitrary data. (Note that hash values never uniquely identify their source data, since different source data can produce the same hash value. The value of hashCode, for example, does not uniquely identify its associated object.) A MessageDigest takes any input, and produces a String which: MessageDigest is often used as a checksum, for verifying that data has not been altered since its creation.

Example

import java.security.SecureRandom;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public final class GenerateId {

  public static void main (String... arguments) {
    try {
      //Initialize SecureRandom
      //This is a lengthy operation, to be done only upon
      //initialization of the application
      SecureRandom prng = SecureRandom.getInstance("SHA1PRNG");

      //generate a random number
      String randomNum = Integer.valueOf(prng.nextInt()).toString();

      //get its digest
      MessageDigest sha = MessageDigest.getInstance("SHA-1");
      byte[] result =  sha.digest(randomNum.getBytes());

      System.out.println("Random number: " + randomNum);
      System.out.println("Message digest: " + hexEncode(result));
    }
    catch (NoSuchAlgorithmException ex) {
      System.err.println(ex);
    }
  }

  /**
  * The byte[] returned by MessageDigest does not have a nice
  * textual representation, so some form of encoding is usually performed.
  *
  * This implementation follows the example of David Flanagan's book
  * "Java In A Nutshell", and converts a byte array into a String
  * of hex characters.
  *
  * Another popular alternative is to use a "Base64" encoding.
  */
  static private String hexEncode(byte[] input){
    StringBuilder result = new StringBuilder();
    char[] digits = {'0', '1', '2', '3', '4','5','6','7','8','9','a','b','c','d','e','f'};
    for (int idx = 0; idx < input.length; ++idx) {
      byte b = input[idx];
      result.append(digits[ (b&0xf0) >> 4 ]);
      result.append(digits[ b&0x0f]);
    }
    return result.toString();
  }
} 

Example run:

>java -cp . GenerateId
Random number: -1103747470
Message digest: c8fff94ba996411079d7114e698b53bac8f7b037

Style 3 - UID

Finally, here is another method, using a java.rmi.server.UID. The Serializable identifiers generated by this class are unique on the host on which they are generated, provided that In order to construct a UID that is globally unique, simply pair a UID with an InetAddress.

Example

import java.rmi.server.UID;

public class UniqueId {

  /**
  * Build and display some UID objects.
  */
  public static void main (String... arguments) {
    for (int idx=0; idx<10; ++idx){
      UID userId = new UID();
      System.out.println("User Id: " + userId);
    }
  }
} 

Example run:

User Id: 3179c3:ec6e28a7ef:-8000
User Id: 3179c3:ec6e28a7ef:-7fff
User Id: 3179c3:ec6e28a7ef:-7ffe
User Id: 3179c3:ec6e28a7ef:-7ffd
User Id: 3179c3:ec6e28a7ef:-7ffc
User Id: 3179c3:ec6e28a7ef:-7ffb
User Id: 3179c3:ec6e28a7ef:-7ffa
User Id: 3179c3:ec6e28a7ef:-7ff9
User Id: 3179c3:ec6e28a7ef:-7ff8
User Id: 3179c3:ec6e28a7ef:-7ff7

Clearly, these are not secure identifiers - knowing one, it's easy to guess another.