• ca_peterson
  • NEWBIE
  • 55 Points
  • Member since 2012
  • Technical Architect
  • FinancialForce.com


Badges

  • Chatter
    Feed
  • 1
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 0
    Questions
  • 7
    Replies

See last paragraph for summary...

 

I was trying to create an adaptive loader routine in Apex Code, and I came across an interesting bug. First, let's take a look at what I was attempting to do:

 

sobject record = cache.load( recordId );
set< id > relatedIds = new set< Id >( );

for( SObjectField field: Cache.getFieldTokens( record.getSObjectType( ) ) ) {
   if( record.get( field ) != null && record.get( field ) instanceOf id ) {
       relatedIds.add( Id.valueOf( record.get( field ) );
   }
}
map< id, sobject > related = new map< id, sobject >( Cache.load( relatedIds ) );

Where:

* Cache.load( Id ) returns a single record from a static map, querying the record, if necessary.

* Cache.getFieldTokens( SObjectType ) returns all tokens from a SObjectType.getDescribe().fields.getMap().values(), again loading from a static map if previously defined.

* Cache.load( Set< Id > ) is a batch version of above, returning a list of SObject records in arbitrary order, querying records that are missing from the cache, and capable of returning multiple types of SObjects.

 

When I tried this initially, I got an odd exception: "Invalid ID."; the exception was thrown from my Cache class, so I wondered how it could have gotten there.

 

I fiddled around with the straightforward means of assigning an ID via a string:

 

Id a = '0013000000f3adA'; // OKAY
Id b = 'john doe';        // EXCEPTION

So, it would appear the setter function works fine.

 

Next, I tried casting:

 

String a = '0013000000f3Adf', b = 'john doe';
Id c = ( Id )a; // OKAY
Id d = ( Id )b; // EXCEPTION

So far, so good; it's also using the setter function of ID.

 

Next, I tried using Id.valueOf:

 

Id a = Id.valueOf( '0013000000d3afA' ); // OKAY
Id b = Id.valueOf( 'john doe' );        // OKAY ?!?!

This means that Id.valueOf doesn't use the setter method, but instead internally constructs an ID.

 

The next tidbit came when I tested the Set<T> class against an ID.

 

First, a straight assignment:

 

Set< Id > a = new set< Id >( );
a.add( '00130000003faZs' ); // OKAY
a.add( 'john doe' ); // EXCEPTION

So, it seems that Id's setter is in play here.

 

Next, I tried using the defunct valueOf:

 

Set< Id > a = new Set< Id >( );
a.add( Id.valueOf( 'john doe' ) ); // OKAY ?!?!

So, it seems that a "corrupted" ID value will be accepted into a set of IDs.

 

This led to the next problem:

 

for( Id b: a) {
  // Do something
}

If a is a set of IDs, and a corrupted ID value (via valueOf) is in the set, you will receive an "invalid ID" error here.

 

Finally, this led me back to my source code:

 

if( Id.valueOf( 'john doe' ) instanceOf Id ) {
  System.debug('** Invalid ID was accepted by instanceOf **');
}

So, Set<T>.add(Object) apparently checks the class of the incoming object against the class of its template, and automatically accepts them without question, otherwise attempts a cast (calling the correctly-working setter function).

 

I submitted a case to support, and they told me to go away because I don't have premier support, and all I wanted to do was log a bug with the dev team.

 

Hopefully an admin will see this and it will get logged as a bug. In the interim, the community should note that Id.valueOf is broken, and instanceOf is also broken as a side-effect. Instead, you should always use casting, and try-catch the cast so you can detect incorrect ID values.

 

Last week, it was brought to my attention that security reviews and audits are now asking ISVs to check for Field Level Security (FLS) and Object CRUD permissions prior to any DML outside of standard controllers.  

This is a fairly radical change that impacts a lot of managed package applications across the board. I and others have several concerns about this change in the security review process:
  1. Why the sudden change in security review policy?  
    • None of the ISVs I have talked to were informed of the change prior to being either audited or submitting any apps for security review.  The only official documentation I can find on the change is a blurb in the Security Scanner help page here: http://security.force.com/security/tools/forcecom/scannerhelp.  
    • As ISVs, it would be greatly appreciated to have an official Security Review Guide, that is updated well in advance to when policy changes like this take place.  Some ISVs have several packages, others lots of customizations, and we all need time to prepare for the security review.
  2. Has the security scanner been updated to enforce this rule yet?
    1. I have not run an app through the Security Review process recently, so I am curious if this rule has been implemented already in the security scanner. (http://security.force.com/security/tools/forcecom/scanner)
  3. Why force FLS and CRUD checks on every DML transaction?
    • I am a fan of using standard controllers when necessary, but several apps, including one my company develops rely heavily on Custom Controllers.  In most cases where FLS comes into play, typically it's a simple fix of a profile permission or permission set that resolves the issue.  Instead, now, we have to implement FLS and CRUD checking prior to each DML transaction.  This adds complexity on top of existing DML calls.  
    • If need be, can the FLS and CRUD checking be done on a one-time run in an install script?
    • Does Salesforce have any plans of either adding FLS checking for custom controllers or adding methods to Apex for checking credentials similar to the Force.com EASPI library? (https://code.google.com/p/force-dot-com-esapi/)
Thanks, I look forward to hearing any feedback on this issue.

See last paragraph for summary...

 

I was trying to create an adaptive loader routine in Apex Code, and I came across an interesting bug. First, let's take a look at what I was attempting to do:

 

sobject record = cache.load( recordId );
set< id > relatedIds = new set< Id >( );

for( SObjectField field: Cache.getFieldTokens( record.getSObjectType( ) ) ) {
   if( record.get( field ) != null && record.get( field ) instanceOf id ) {
       relatedIds.add( Id.valueOf( record.get( field ) );
   }
}
map< id, sobject > related = new map< id, sobject >( Cache.load( relatedIds ) );

Where:

* Cache.load( Id ) returns a single record from a static map, querying the record, if necessary.

* Cache.getFieldTokens( SObjectType ) returns all tokens from a SObjectType.getDescribe().fields.getMap().values(), again loading from a static map if previously defined.

* Cache.load( Set< Id > ) is a batch version of above, returning a list of SObject records in arbitrary order, querying records that are missing from the cache, and capable of returning multiple types of SObjects.

 

When I tried this initially, I got an odd exception: "Invalid ID."; the exception was thrown from my Cache class, so I wondered how it could have gotten there.

 

I fiddled around with the straightforward means of assigning an ID via a string:

 

Id a = '0013000000f3adA'; // OKAY
Id b = 'john doe';        // EXCEPTION

So, it would appear the setter function works fine.

 

Next, I tried casting:

 

String a = '0013000000f3Adf', b = 'john doe';
Id c = ( Id )a; // OKAY
Id d = ( Id )b; // EXCEPTION

So far, so good; it's also using the setter function of ID.

 

Next, I tried using Id.valueOf:

 

Id a = Id.valueOf( '0013000000d3afA' ); // OKAY
Id b = Id.valueOf( 'john doe' );        // OKAY ?!?!

This means that Id.valueOf doesn't use the setter method, but instead internally constructs an ID.

 

The next tidbit came when I tested the Set<T> class against an ID.

 

First, a straight assignment:

 

Set< Id > a = new set< Id >( );
a.add( '00130000003faZs' ); // OKAY
a.add( 'john doe' ); // EXCEPTION

So, it seems that Id's setter is in play here.

 

Next, I tried using the defunct valueOf:

 

Set< Id > a = new Set< Id >( );
a.add( Id.valueOf( 'john doe' ) ); // OKAY ?!?!

So, it seems that a "corrupted" ID value will be accepted into a set of IDs.

 

This led to the next problem:

 

for( Id b: a) {
  // Do something
}

If a is a set of IDs, and a corrupted ID value (via valueOf) is in the set, you will receive an "invalid ID" error here.

 

Finally, this led me back to my source code:

 

if( Id.valueOf( 'john doe' ) instanceOf Id ) {
  System.debug('** Invalid ID was accepted by instanceOf **');
}

So, Set<T>.add(Object) apparently checks the class of the incoming object against the class of its template, and automatically accepts them without question, otherwise attempts a cast (calling the correctly-working setter function).

 

I submitted a case to support, and they told me to go away because I don't have premier support, and all I wanted to do was log a bug with the dev team.

 

Hopefully an admin will see this and it will get logged as a bug. In the interim, the community should note that Id.valueOf is broken, and instanceOf is also broken as a side-effect. Instead, you should always use casting, and try-catch the cast so you can detect incorrect ID values.

 

I've been working in an org for almost 2 years.  They just installed a managed package; it's a large 100% native accounting application (I didn't want to put the name in this thread just yet).

 

Everything has been speedy.  However, after the installation, I've noticed that it now takes over 2 minutes to save triggers, classes and visualforce pages via Eclipse.  I have clients on the same CS12 instance and the performance is fine.  Has anyone experience a significant performance decrease in the ID after installing "FF" ?

 

All I'm doing is a save/build.  No unit tests or anything.  Just a save of small modifications to triggers and stuff.  

 

To troubleshoot, I re-created my project in Eclipse and it took over 15 minutes just to get the listing of items that I wanted to add to my project.  Any ideas?  Thanks,

 

George Sowards

www.RedPointSolutions.com

  • August 17, 2012
  • Like
  • 0

Hello.  I'm using Lexiloader v. 24 on OS X 10.6.8.  I've noticed that when I run Lexiloader, it creates a subfolder in Applications folder named 

 

C/\Users\jeffrey.lai\AppData\local\temp

 

with a zero-btye file named sdl.log in it.

 

Anyone know where this comes from?  If I delete the folder, Lexiloader always recreates it.

 

Thanks

David