Introduction
Greetings my fellow earth dwellers. Previously, I blogged about the acquisition of dependent picklists in Apex (as the title implies). Although the algorithm works, I managed to later identify what seemed to be 3 bottlenecks in the code. So I’m going to do what I think is “the right thing to do” and share my solutions to them 🙂 . I will include the final code snippet at the bottom so that you may feel free to copy and paste.
In total, these optimizations provided me with approximately 76% reduction in CPU Time.
Bottleneck 1
The first one I identified is the continuous serialization and deserialization of the dependent picklist entry in the for loop.
1 2 3 4 5 6 7 8 9 |
//check the dependent values for(Integer pDependentIndex=0; pDependentIndex<dep_ple.size(); pDependentIndex++){ //get the pointer to the dependent index Schema.PicklistEntry dep_entry = dep_ple[pDependentIndex]; //get the valid for String pEntryStructure = JSON.serialize(dep_entry); TStringUtils.TPicklistEntry objDepPLE = (TStringUtils.TPicklistEntry)JSON.deserialize(pEntryStructure, TStringUtils.TPicklistEntry.class); //... } |
I figured it’s better to add all the entries to a list first, then serialize and deserialize it once to get the attributes instead of incurring the overhead of multiple calls.
1 2 3 4 5 6 7 8 9 10 11 12 |
//load all dep entries List<Schema.PicklistEntry> objEntries = new List<Schema.PicklistEntry>(); List<TStringUtils.TPicklistEntry> objDS_Entries = new List<TStringUtils.TPicklistEntry>(); //add all entries for(Integer pDependentIndex=0; pDependentIndex<dep_ple.size(); pDependentIndex++){ //get the pointer to the dependent index Schema.PicklistEntry dep_entry = dep_ple[pDependentIndex]; objEntries.add(dep_entry); } //serialize once objDS_Entries = (List<TStringUtils.TPicklistEntry>)JSON.deserialize(JSON.serialize(objEntries), List<TStringUtils.TPicklistEntry>.class); |
Bottleneck 2
The next one is the sub loop which tests each dependent picklist entry against each controlling value.
1 2 3 4 5 |
for(Integer pControllingIndex=0; pControllingIndex<ctrl_ple.size(); pControllingIndex++){ if (objBitSet.testBit(objDepPLE.validFor,pControllingIndex)){ //... } } |
This caused the overhead of calling the “testBit” function for every Controlling Index. I analyzed the testBit function and realized there’s only a small portion which depends on the controlling index, the rest is constant for the validBit. With this information, I added a subsequent function called “testBits” which takes the list of Controlling Indexes to test against. With this information, I’m now able to isolate the portion unique to the controlling index. This allows me to remove an extra 2 for loops per that were incurring unnecessary CPU cycles and place them outside the context of the same said index.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
/* Effect: Method takes a validFor string and tests it against a set of controlling indexes Postcondition: Returns a list of all controlling indexes for which the validFor string test True */ public List<Integer> testBits(String pValidFor,List<Integer> nList){ List<Integer> results = new List<Integer>(); //the list of bytes (not derived from n) List<Integer> pBytes = new List<Integer>(); //multiply by 6 since base 64 uses 6 bits (not derived form n) Integer bytesBeingUsed = (pValidFor.length() * 6)/8; //will be used to hold the full decimal value (not derived from n) Integer pFullValue = 0; //must be more than 1 byte if (bytesBeingUsed <= 1) return results; //get the base64bytes for(Integer i=0;i<pValidFor.length();i++){ //get currenct character value pBytes.Add((Base64CharCodes.get((pValidFor.Substring(i, i+1))))); } //calculate the full decimal value for (Integer i = 0; i < pBytes.size(); i++) { Integer pShiftAmount = (pBytes.size()-(i+1))*6;//used to shift by a factor 6 bits to get the value pFullValue = pFullValue + (pBytes[i] << (pShiftAmount)); } //now we don't want to always be declaring memory, so let's set the initial //variables Integer bit; Integer targetOctet; Integer shiftBits; Integer tBitVal; Integer n; Integer nListSize = nList.size(); for(Integer i=0; i<nListSize; i++){ n = nList[i]; //calculate the target bit for comparison bit = 7 - (Math.mod(n,8)); //calculate the octet that has in the target bit targetOctet = (bytesBeingUsed - 1) - (n >> bytesBeingUsed); //the number of bits to shift by until we find the bit to compare for true or false shiftBits = (targetOctet * 8) + bit; //& is to set the same set of bits for testing //shift to the bit which will dictate true or false //Math.Pow(2, shiftBits) == 2 << (shiftBits+1) tBitVal = ((Integer)(2 << (shiftBits-1)) & pFullValue) >> shiftBits; if (tBitVal==1) results.add(n); } return results; } } |
Bottleneck 3
The last one is the call to Math.Pow in the testBit function. I realized, that when getting the testBit value, part of that function is dependent on the value 2 being raised to a power of the shiftBits. The overhead from this function was unnecessary, and so I optimized Math.Pow(2,shiftBits) to 2 << (shiftBits -1) which is already included in the above snippet.
Other fine tuning
I also added the option to call the method GetDependentOptions explicitly with the object type (GetDependentOptionsImpl) or with the object name (GetDependentOptions). I realized that at moments it’s unnecessary to ask the system to find the object type by name if the caller function already has the object type available. In order to make the changes backward compatible, I kept the original method parameters and just forwarded it to the submethod that uses this optimal route. At the end of the day, either method can be used by the caller.
The Full Code Change
Step 1: Add the new testBits function. No need to remove the older one, it is however deprecated and no longer used.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
/* Effect: Method takes a validFor string and tests it against a set of controlling indexes Postcondition: Returns a list of all controlling indexes for which the validFor string test True */ public List<Integer> testBits(String pValidFor,List<Integer> nList){ List<Integer> results = new List<Integer>(); //the list of bytes (not derived from n) List<Integer> pBytes = new List<Integer>(); //multiply by 6 since base 64 uses 6 bits (not derived form n) Integer bytesBeingUsed = (pValidFor.length() * 6)/8; //will be used to hold the full decimal value (not derived from n) Integer pFullValue = 0; //must be more than 1 byte if (bytesBeingUsed <= 1) return results; //get the base64bytes for(Integer i=0;i<pValidFor.length();i++){ //get currenct character value pBytes.Add((Base64CharCodes.get((pValidFor.Substring(i, i+1))))); } //calculate the full decimal value for (Integer i = 0; i < pBytes.size(); i++) { Integer pShiftAmount = (pBytes.size()-(i+1))*6;//used to shift by a factor 6 bits to get the value pFullValue = pFullValue + (pBytes[i] << (pShiftAmount)); } //now we don't want to always be declaring memory, so let's set the initial //variables Integer bit; Integer targetOctet; Integer shiftBits; Integer tBitVal; Integer n; Integer nListSize = nList.size(); for(Integer i=0; i<nListSize; i++){ n = nList[i]; //calculate the target bit for comparison bit = 7 - (Math.mod(n,8)); //calculate the octet that has in the target bit targetOctet = (bytesBeingUsed - 1) - (n >> bytesBeingUsed); //the number of bits to shift by until we find the bit to compare for true or false shiftBits = (targetOctet * 8) + bit; //& is to set the same set of bits for testing //shift to the bit which will dictate true or false //Math.Pow(2, shiftBits) == 2 << (shiftBits+1) tBitVal = ((Integer)(2 << (shiftBits-1)) & pFullValue) >> shiftBits; if (tBitVal==1) results.add(n); } return results; } |
Step 2: Add the new GetDependentOptions and GetDependentOptionsImpl functions
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
public static Map<String,List<String>> GetDependentOptions(String pObjName, String pControllingFieldName, String pDependentFieldName){ Map<String,List<String>> objResults = new Map<String,List<String>>(); //get the string to sobject global map Map<String,Schema.SObjectType> objGlobalMap = Schema.getGlobalDescribe(); if (!Schema.getGlobalDescribe().containsKey(pObjName)) return objResults; //get the type being dealt with Schema.SObjectType pType = Schema.getGlobalDescribe().get(pObjName); return GetDependentOptionsImpl(pType,pControllingFieldName,pDependentFieldName); } public static Map<String,List<String>> GetDependentOptionsImpl(Schema.SObjectType pType, String pControllingFieldName, String pDependentFieldName){ Map<String,List<String>> objResults = new Map<String,List<String>>(); if (pType==null) return objResults; TStringUtils.Bitset BitSetInstance = new TStringUtils.Bitset(); Map<String, Schema.SObjectField> objFieldMap = pType.getDescribe().fields.getMap(); //verify field names if (!objFieldMap.containsKey(pControllingFieldName) || !objFieldMap.containsKey(pDependentFieldName)) return objResults; //get the control values List<Schema.PicklistEntry> ctrl_ple = objFieldMap.get(pControllingFieldName).getDescribe().getPicklistValues(); //get the dependent values List<Schema.PicklistEntry> dep_ple = objFieldMap.get(pDependentFieldName).getDescribe().getPicklistValues(); objFieldMap = null; List<Integer> lstControllingIndexes = new List<Integer>(); //iterate through the values and get the ones valid for the controlling field name //set up the results for(Integer pControllingIndex=0; pControllingIndex<ctrl_ple.size(); pControllingIndex++){ //get the pointer to the entry Schema.PicklistEntry ctrl_entry = ctrl_ple[pControllingIndex]; //get the label String pControllingLabel = ctrl_entry.getLabel(); //create the entry with the label objResults.put(pControllingLabel,new List<String>()); //keep track of the controlling indexes lstControllingIndexes.add(pControllingIndex); } //cater for null and empty objResults.put('',new List<String>()); objResults.put(null,new List<String>()); //load all dep entries List<Schema.PicklistEntry> objEntries = new List<Schema.PicklistEntry>(); List<TStringUtils.TPicklistEntry> objDS_Entries = new List<TStringUtils.TPicklistEntry>(); //add all entries for(Integer pDependentIndex=0; pDependentIndex<dep_ple.size(); pDependentIndex++){ //get the pointer to the dependent index Schema.PicklistEntry dep_entry = dep_ple[pDependentIndex]; objEntries.add(dep_entry); } //serialize once objDS_Entries = (List<TStringUtils.TPicklistEntry>)JSON.deserialize(JSON.serialize(objEntries), List<TStringUtils.TPicklistEntry>.class); List<Integer> validIndexes; for (TStringUtils.TPicklistEntry objDepPLE : objDS_Entries){ //if valid for is empty, skip if (objDepPLE.validFor==null || objDepPLE.validFor==''){ continue; } //get the test for the controlling indexes validIndexes = BitSetInstance.testBits(objDepPLE.validFor,lstControllingIndexes); for (Integer validIndex : validIndexes){ //get the label String pControllingLabel = ctrl_ple[validIndex].getLabel(); objResults.get(pControllingLabel).add(objDepPLE.label); } } objEntries = null; objDS_Entries = null; return objResults; } |
38 Comments on “Salesforce: Acquiring Dependent Picklists In Apex Contd.”
Pingback: Salesforce: Acquiring Dependent Picklists in Apex | Tales of an earthling
Hi, I want to subscribe for this blog to take latest updates, therefore where can i do it please help out.
close – at least it runs in apex vs a VF/js hack BUT – the values are not correct in the several instances i tried – close but not correct – i suspect something in the base64 bit math but i lack the skills to troubleshoot it 🙂
Hey Erik, I think there are a few existing solutions out there for the VF/js hack. This one is exclusively for apex because it’s based on different bit shifting that’s done on the server end and not the client end (JS)
Love this code but for some reason it is not returning all my dependent values, only a handful. Any ideas why this is happening? It works find for another field but just this one.
I like the idea of making it in apex, good job!
However, I found some cases where code doesn’t work. For example, if the validFor is”///////////////A” code breaks in the TestBit method line
pFullValue = pFullValue + (pBytes[i] << (pShiftAmount));
because pBytes[i] is null.
Unfortunatelly, I am not really good at those encodings and shiftings so I could't figure out where the problem is. Will continue however to learn and try in order to figure out how to make it work.
Ok, I figured that out. The problem was because Base64CharCodes was initialized without’/’ character which is a valid base64 character. Adding this character to Base64CharCodes solves this issue.
However, there is one more. Something is wrong with last for loop in testBits() method. I noticed that for some controlling fields I don’t have any dependent values but I should. After debugging I found that for those controlling fields tBitVal is “-1” and thus code don’t fall int results.add(n). I suppose that “-1” should not be expected value here, it should be 0 or 1
How do you add ‘/’ to the Base64CharCodes?
Did you figure out what the other issue was? I’m getting incorrect results for some of mine. Majority of them are working, but some are returning values that aren’t set?
Added
Base64CharCodes.put(‘+’,62);
Base64CharCodes.put(‘/’,63);
to the initialization. (But didn’t solve my issue of it returning incorrect results… So close and yet so far.)
Woah! I’m really loving the template/theme of this site. It’s simple, yet effective. A lot of times it’s challenging to get that “perfect balance” between user friendliness and visual appeal. I must say you’ve done a amazing job with this. Additionally, the blog loads super quick for me on Safari. Excellent Blog!
Thanks for this tutorial. Would be great if there is some example of how to use this code in practice.
How can I pass controlling and dependent fields names?
Thank you
THANK YOU! This is amazing and saved me so much frustration!
I believe the issue with this not always returning the correct value is because when SFDC converts base64 to string, it doesn’t handle non-ascii well (converts to UTF-8) and those characters out of normal range will always return char value of 65535. So this doesn’t allow you to use the converted string to find set bits.
I created code to convert base64 into an integer list, then used that integer list (instead of strings) to create the listing of “set bits” in the “validFor”. This new code appears to work for me — hopefully it will work for you and anyone else coming to this page. (Note, the class I put this code in is called “Globals” — you will need to adjust the references to “Globals.TPicklistEntry” appropriately.
// Converts a base64 string into a list of integers representing the encoded bytes
public static List B64ToBytes (String sIn) {
Map base64 = new Map{65=>0,66=>1,67=>2,68=>3,69=>4,70=>5,71=>6,72=>7,73=>8,74=>9,75=>10,76=>11,77=>12,78=>13,79=>14,80=>15,81=>16,82=>17,83=>18,84=>19,85=>20,86=>21,87=>22,88=>23,89=>24,90=>25,97=>26,98=>27,99=>28,100=>29,101=>30,102=>31,103=>32,104=>33,105=>34,106=>35,107=>36,108=>37,109=>38,110=>39,111=>40,112=>41,113=>42,114=>43,115=>44,116=>45,117=>46,118=>47,119=>48,120=>49,121=>50,122=>51,48=>52,49=>53,50=>54,51=>55,52=>56,53=>57,54=>58,55=>59,56=>60,57=>61,43=>62,47=>63};
List lstOut = new List();
if ( sIn == null || sIn == ” ) return lstOut;
sIn += ‘=’.repeat( 4 – Math.mod( sIn.length(), 4) );
for ( Integer idx=0; idx < sIn.length(); idx += 4 ) {
if ( base64.get(sIn.charAt(idx+1)) != null ) lstOut.add( (base64.get(sIn.charAt(idx)) <>> 4) );
if ( base64.get(sIn.charAt(idx+2)) != null ) lstOut.add( ((base64.get(sIn.charAt(idx+1)) & 15)<>> 2) );
if ( base64.get(sIn.charAt(idx+3)) != null ) lstOut.add( ((base64.get(sIn.charAt(idx+2)) & 3)<<6) | base64.get(sIn.charAt(idx+3)) );
}
//System.Debug('B64ToBytes: [' + sIn + '] = ' + lstOut);
return lstOut;
}//B64ToBytes
public static List BlobToBytes (Blob input) {
return B64ToBytes( EncodingUtil.base64Encode(input) );
}//BlobToBytes
// Converts a base64 string into a list of integers indicating at which position the bits are on
public static List cnvBits (String b64Str) {
List lstOut = new List();
if ( b64Str == null || b64Str == ” ) return lstOut;
List lstBytes = B64ToBytes(b64Str);
Integer i, b, v;
for ( i = 0; i < lstBytes.size(); i++ ) {
v = lstBytes[i];
//System.debug ( 'i['+i+'] v['+v+']' );
for ( b = 1; b <= 8; b++ ) {
//System.debug ( 'i['+i+'] b['+b+'] v['+v+'] = ['+(v & 128)+']' );
if ( ( v & 128 ) == 128 ) lstOut.add( (i*8) + b );
v <<= 1;
}
}
//System.Debug('cnvBits: [' + b64Str + '] = ' + lstOut);
return lstOut;
}//cnvBits
public class TPicklistEntry{
public string active {get;set;}
public string defaultValue {get;set;}
public string label {get;set;}
public string value {get;set;}
public string validFor {get;set;}
public TPicklistEntry(){
}
}//TPicklistEntry
public static Map<String,List> GetDependentOptions(String pObjName, String pControllingFieldName, String pDependentFieldName) {
Map<String,List> mapResults = new Map<String,List>();
//verify/get object schema
Schema.SObjectType pType = Schema.getGlobalDescribe().get(pObjName);
if ( pType == null ) return mapResults;
Map objFieldMap = pType.getDescribe().fields.getMap();
//verify field names
if (!objFieldMap.containsKey(pControllingFieldName) || !objFieldMap.containsKey(pDependentFieldName)) return mapResults;
//get the control & dependent values
List ctrl_ple = objFieldMap.get(pControllingFieldName).getDescribe().getPicklistValues();
List dep_ple = objFieldMap.get(pDependentFieldName).getDescribe().getPicklistValues();
//clear heap
objFieldMap = null;
//initialize results mapping
for(Integer pControllingIndex=0; pControllingIndex<ctrl_ple.size(); pControllingIndex++){
mapResults.put( ctrl_ple[pControllingIndex].getLabel(), new List());
}
//cater for null and empty
mapResults.put(”, new List());
mapResults.put(null, new List());
//serialize dep entries
List objDS_Entries = new List();
objDS_Entries = (List)JSON.deserialize(JSON.serialize(dep_ple), List.class);
List validIndexes;
for (Globals.TPicklistEntry objDepPLE : objDS_Entries){
validIndexes = cnvBits(objDepPLE.validFor);
//System.Debug(‘cnvBits: [‘ + objDepPLE.label + ‘] = ‘ + validIndexes);
for (Integer validIndex : validIndexes){
mapResults.get( ctrl_ple[validIndex-1].getLabel() ).add( objDepPLE.label );
}
}
//clear heap
objDS_Entries = null;
return mapResults;
}//GetDependentOptions
Good find Paul N. I couldn’t comment much because I don’t use Salesforce anymore in my current job and as a result, it’s a tad bit harder for me to not just find the time to stay up to speed with it, but to test any changes I would make to the code. But I’m glad you figured it out and that should help other readers as well!
Hi Paul
I am trying to implement your logic bu t the content you put on this webpage was missing or misinteruppted the logic behind the encoding.
would you mind please pass down the code if you have it in git? Thanks
Aarthi,
Did you see my dropbox version (linked at: https://www.dropbox.com/s/4gi7m38sr4blqqo/GetDependentOptions.txt)? The original version doesn’t work correctly for all situations.
Hi Paul,
could you please correct the following code lines?
if ( base64.get(sIn.charAt(idx+1)) != null ) lstOut.add( (base64.get(sIn.charAt(idx)) > 4) );
if ( base64.get(sIn.charAt(idx+2)) != null ) lstOut.add( ((base64.get(sIn.charAt(idx+1)) & 15)> 2) );
Even though I used your code in the comment, still it doesn’t pickup correct values from the dependent list. 🙁
I’m really sorry, not sure why the code is coming out wrong in the posting above… there should be three greater-than symbols in a row at the end of those lines:
if ( base64.get(sIn.charAt(idx+1)) != null ) lstOut.add( (base64.get(sIn.charAt(idx)) <>> 4) );
if ( base64.get(sIn.charAt(idx+2)) != null ) lstOut.add( ((base64.get(sIn.charAt(idx+1)) & 15)<>> 2) );
Hopefully that works…
Here’s a link to a “pastie” of the code to ensure it’s right:
http://pastie.org/private/ykjr9ircfh08d8iygfliyg
hi Paul N….
Really appreciate your work .. Thanks for the updated code
Yeah, it changed them again… use the link to grab the code. Let me know if it works
Hi Paul,
Now this is fantastic. I’ve got over 150 controlling picklist values and over 5000 dependent values.. This works like a charm. I found another javascript solution on the net and still its not reliable as this and fails to get the correct values. Thank you for this.
That is great to hear, I glad it worked! 🙂
Hi Yo,
Can you please share the working code for Dependent pick-list, working code link(http://pastie.org/private/ykjr9ircfh08d8iygfliyg) shared showing an error. Please help!!
Thanks
Himanshu
Many thanks Paul N!
I had some issues with the previous code when obtaining the dependencies between States and Countries. This seems work fine for me for this picklists 🙂
Thanks Paul!
It works perfectly with the last taken approach.
Great work!
Hi Paul,
Can you please share the working code for Dependent pick-list, working code link(http://pastie.org/private/ykjr9ircfh08d8iygfliyg) shared showing an error. Please help!!
Thanks
Himanshu
Himanshu,
Please try this download instead:
https://www.dropbox.com/s/4gi7m38sr4blqqo/GetDependentOptions.txt
Glad this continues to be helpful! 🙂
Paul
Hi Paul,
Appreciated for your help!!
Its working perfectly for me. Keep posting valuable stuffs.
Thanks
Himanshu Kalra
Man!
Code does not work with Global Picklist = (( I spent some good time to find out this = ((
No questions to Neel.
Just to let others know.
Really strange. Works fine with 4 dependent picklists but not 5th – a lot of extra values…
Hi, thanks for this, nicely done!
I have some suggestions:
1. It looks like you are copying dep_ple to objEntries. Is there any reason why you are not serialising straight from dep_ple? objDS_Entries = (List)JSON.deserialize(JSON.serialize(dep_ple), List.class);
2. Is there any difference between if(objDepPLE.validFor==null || objDepPLE.validFor==”){ continue; } // do code AND if(objDepPLE.validFor!=null && objDepPLE.validFor!=”){ //do code } ?
3. The List nList in testBits will always be 0, 1…. ctrl_ple.size(). I would maybe change the nList to an Integer ctrlListSize, change for(Integer i=0; i<nListSize; i++) to for(Integer i=0; i<ctrlListSize; i++) and inside the for loop replace n with i; also , in GetDependentOptionsImpl, I would change:
for(Integer pControllingIndex=0; pControllingIndex<ctrl_ple.size(); pControllingIndex++){
//get the pointer to the entry
Schema.PicklistEntry ctrl_entry = ctrl_ple[pControllingIndex];
//get the label
String pControllingLabel = ctrl_entry.getLabel();
//create the entry with the label
objResults.put(pControllingLabel,new List());
//keep track of the controlling indexes
lstControllingIndexes.add(pControllingIndex);
}
to
for( Schema.PicklistEntry ctrl_entry : ctrl_ple){
//get the label
String pControllingLabel = ctrl_entry.getLabel();
//create the entry with the label
objResults.put(pControllingLabel,new List());
}
AND
validIndexes = BitSetInstance.testBits(objDepPLE.validFor,lstControllingIndexes);
to
validIndexes = BitSetInstance.testBits(objDepPLE.validFor,ctrl_ple.size());
Sabina,
Did you see my version (linked to above at: https://www.dropbox.com/s/4gi7m38sr4blqqo/GetDependentOptions.txt)? The original version doesn’t work correctly for all situations. I also addressed some on the concerns you had.
1) I did leave this unchanged in my code… dep_ple is type “List”, while objDS_Entries is of type “List” (which is a wrapper class. The serialize/deserialize converts the object from a PicklistEntry to our customize “TPicklistEntry” type which allows us to get the “ValidFor” portion which cannot be accessed using standard PicklistEntry.
I use “objDS_Entries” just to make the code a bit more readable. I clear it at the end to remove the memory usage. If you wanted to eliminate “objDS_Entries” and just put the serialize/deserialize in the “for” loop, this shouldn’t cause any issues.
2) I don’t think there would be much difference in how you suggest other than readability / personal preference. Obviously, the “continue” would prevent any other code being done after the “if”, but if there isn’t anything else to do, then it shouldn’t make a difference.
3) I completely changed the way the bitset is determined — as the original had issues with non-standard characters when converted using the Base64 conversion functions (which are intended for character conversion).
Hi Paul,
Thanks, I will give it a try 🙂 To reply to your remarks:
1) I was talking about objEntries, not objDS_Entries, which is indeed a different type of List. The code is first copying dep_ple into objEntries and THEN serialising to objDS_Entries. I was just wondering why not skip objEntries completely.
But I see that in your code (objDS_Entries = (List)JSON.deserialize(JSON.serialize(dep_ple), List.class);) you did just that 🙂
2) There is no difference, but I always care about readability 😉
I have a controlling pick list with 240 values and a dependent pick list with length of validfor string as 30. Is this normal as target octet in the algorithm will always be bytesbeingused -1. If yes, is there a better way to handle the scenario?
this idea is very great, but there is a bug in my code.
I think there are some issues in the ‘Bitset’ class. Because in my debug log, I fount that it returns null in the ‘testBits’ method.
I find an open source from github(https://gist.github.com/boxfoot/4166342/forks)
🙂
Hi guys,
I copied this code and i am getting error in developer console like:
1.Invalid type: Globals.TPicklistEntry
2.Variable does not exist: objDepPLE
Please anyone tell what is the list:globals.Tpicklistentry ?
ukwg1c