Find your content:

Search form

You are here

How to generate a GUID/UUID?

 
Share

What is the best way to generate a GUID/UUID from Apex code (such as a trigger)? Preferably in the following format:

nnnnnnnn-nnnn-nnnn-nnnnnnnnnnnnnnnnn

Example:

13219ec0-3a81-44c5-a300-de14b7d0235f


Attribution to: Paul Sasik

Possible Suggestion/Solution #1

After working with the code in techtrekker's link (in OP comments) and other resources I cobbled together a standalone, working class for generating GUIDs in Apex code:

Sample usage:

   if (acct.AccountUuid__c == null)
        acct.AccountUuid__c = GuidUtil.NewGuid();

Apex class:

global class GuidUtil {

    private static String kHexChars = '0123456789abcdef';

    global static String NewGuid() {

        String returnValue = '';
        Integer nextByte = 0;

        for (Integer i=0; i<16; i++) {

            if (i==4 || i==6 || i==8 || i==10) 
                returnValue += '-';

            nextByte = (Math.round(Math.random() * 255)-128) & 255;

            if (i==6) {
                nextByte = nextByte & 15;
                nextByte = nextByte | (4 << 4);
            }

            if (i==8) {
                nextByte = nextByte & 63;
                nextByte = nextByte | 128;
            }

            returnValue += getCharAtIndex(kHexChars, nextByte >> 4);
            returnValue += getCharAtIndex(kHexChars, nextByte & 15);
        }

        return returnValue;
    }

    global static String getCharAtIndex(String str, Integer index) {

        if (str == null) return null;

        if (str.length() <= 0) return str;    

        if (index == str.length()) return null;    

        return str.substring(index, index+1);
    }
}

Attribution to: Paul Sasik

Possible Suggestion/Solution #2

The answers given already either don't use a cryptographically secure random number or don't conform to UUID v4 standards. Here is a class and test that does both.

/*
How to generate a version 4 GUID (random)

1. Generate 128 random bits
2. Set the version: Take the 7th byte perform an AND operation with 0x0f followed by an OR operation of 0x40.
3. Set the variant: Take the 9th byte perform an AND operation with 0x3f followed by an OR operation of 0x80.
4. Convert the data to hex and add dashes
*/

public class GuidUtil { 
    static List<String> hexMap = new List<String> {
        '0', '1', '2', '3', '4', '5', '6', '7', 
        '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
    };

    public static String NewGuid() {        
        String randomStringAsHex = EncodingUtil.ConvertTohex(Crypto.GenerateAESKey(128));

        String versionHexBits = randomStringAsHex.SubString(14,16); // 7th bit 
        String variantHexBits = randomStringAsHex.SubString(18,20); // 9th bit

        Integer versionIntBits = convertHexToInt(versionHexBits);
        Integer variantIntBits = convertHexToInt(variantHexBits);

        Integer versionShiftedIntBits = versionIntBits & 15 | 64;  // (i & 0x0f) | 0x40
        Integer variantShiftedIntBits = variantIntBits & 63 | 128; // (i & 0x3f) | 0x80

        String versionShiftedHexBits = convertIntToHex(versionShiftedIntBits); // Always begins with 4
        String variantShiftedHexBits = convertIntToHex(variantShiftedIntBits); // Always begins with one of 8,9,a,b

        String guid = randomStringAsHex.SubString(0,8) + '-' + randomStringAsHex.SubString(8,12) + '-' + versionShiftedHexBits + randomStringAsHex.SubString(14,16) + '-' + variantShiftedHexBits + randomStringAsHex.SubString(18,20) + '-' + randomStringAsHex.substring(20);        

        return guid;
    }

    static Integer convertHexToInt(String hex) {        
        Integer d0 = hexMap.IndexOf(hex.Substring(1,2));
        Integer d1 = hexMap.IndexOf(hex.Substring(0,1));

        Integer intval = d0 + (d1*16);
        return intval;
    }

    static String convertIntToHex(Integer intval) {
        // https://stackoverflow.com/a/13465128
        String hs0 = hexMap.Get(intval & 15); // i & 0x0f
        String hs1 = hexMap.Get(((intval >> 4) & 15)); //(i >> 4) & 0x0f        
        return hs1+hs0;
    }
}

And here is a test for it

@isTest
public class GuidUtilSpec {
    private static testmethod void GuidIsV4() {
      Pattern p = Pattern.compile('[\\w]{8}-[\\w]{4}-4[\\w]{3}-[89ab][\\w]{3}-[\\w]{12}');
      for(Integer x = 0; x < 100; x++) {
        Matcher m = p.matcher(GuidUtil.NewGuid());
        System.assert(m.matches() == true);
      }
    }
}

Attribution to: NotDan

Possible Suggestion/Solution #3

The answer provided by Paul Sasik above works, but is not a secure way of generating a UUID because of it's use of Math.Random(), which is not a cryptographically secure pseudo-random number generator.

One of two things should be done, either use Crypto.getRandomInteger() to generate the random integer or use the code below as a drop in replacement for the whole UUID generation routine:

Blob b = Crypto.GenerateAESKey(128);
String h = EncodingUtil.ConvertTohex(b);
String guid = h.SubString(0,8)+ '-' + h.SubString(8,12) + '-' + h.SubString(12,16) + '-' + h.SubString(16,20) + '-' + h.substring(20);

Sources:


Attribution to: rev

Possible Suggestion/Solution #4

The answer provided by Paul Sasik works and generates valid UUIDs, in the other hand the method provided by rev looks nicer, but it doesn't generate valid UUIDs because it does not agree with UUID conventions (see https://en.wikipedia.org/wiki/Universally_unique_identifier)

You can try to test the results of the following anonymous code at http://guid.us/Test/GUID

Blob b = Crypto.GenerateAESKey(128);
String h = EncodingUtil.ConvertTohex(b);
String guid = h.SubString(0,8)+ '-' + h.SubString(8,12) + '-' + h.SubString(12,16) + '-' + h.SubString(16,20) + '-' + h.substring(20);
system.debug(guid);

System.debug(GuidUtil.NewGuid());
System.debug(GuidUtil.NewGuid());
System.debug(GuidUtil.NewGuid());
System.debug(GuidUtil.NewGuid());
System.debug(GuidUtil.NewGuid());

or using the follow JS regexp

<script>
var uuids = ['35706b3e-9f52-7d53-7ed3-d7f100b02a1c', //Generated by Crypo
'49b7d84b-478c-4eec-b53d-b6237666f30c', //Generated as Paul says
'c8f9caa0-b90b-438d-91bd-77fdea7a304b', //Generated as Paul says
'a44bedcb-5481-4780-aac9-3f106c2b8074', //Generated as Paul says
'83a15da9-c6c2-4c1f-8682-a51a79e6ae57', //Generated as Paul says
'fbc72910-32ce-4b60-a498-f4b3f450942f']; //Generated as Paul says
var re = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
for(var i=0; i<uuids.length; i++) {
  console.log(uuids[i] + '-'+re.test(uuids[i]));
}
</script>

For now I will use Paul's method, using Crypto.getRandomInteger() instead of Math.random(), but I think it is not entirely safe because there is a remote possibility of collisions


Attribution to: Jorge Ortega Traverso

Possible Suggestion/Solution #5

This worked for me (where i is integer from a for loop):

(id)('0'+string.valueOf(27100000001122L+i))

You can probably find a valid SFDC prefix does not start with 0.


Attribution to: dzh
This content is remixed from stackoverflow or stackexchange. Please visit https://salesforce.stackexchange.com/questions/4073

My Block Status

My Block Content