It's about how null checking differs if occurring from outside or inside an Apex Class.
For those who are TL;DR (like me), jump to the following Gist and comment if you have an explanation.
Let's take this simple class:
1 2 3 4 5 6 7 8 9 10 11 12 | public class MyController { public Account tst{get;set;} public MyController(){ this .tst = [Select Id, Name From Account limit 1 ]; } public void myMethod(){ system.debug( 'Test inside: ' +(tst.Name == null )); //Throws null pointer exceptions system.debug( 'Test inside: ' +(tst == null )); system.debug( 'Test inside: ' +json.serializepretty(tst)); } } |
Let's take the following anonymous code:
1 2 3 4 5 6 7 | MyController cnt = new MyController(); cnt.tst.Name = 'test' ; cnt.tst = null ; system.debug( 'Test outside: ' +(cnt.tst.Name == null )); system.debug( 'Test outside: ' +(cnt.tst == null )); system.debug( 'Test outside: ' +json.serializepretty(cnt.tst)); cnt.myMethod(); |
Question: What do you think is the debug?
Answer:
19:06:58.24 (32784451)|USER_DEBUG|[5]|DEBUG|Test outside: true
19:06:58.24 (32903967)|USER_DEBUG|[6]|DEBUG|Test outside: true
19:06:58.24 (33182107)|USER_DEBUG|[7]|DEBUG|Test outside: null
19:06:58.24 (33393615)|EXCEPTION_THROWN|[7]|System.NullPointerException: Attempt to de-reference a null object
19:06:58.24 (32903967)|USER_DEBUG|[6]|DEBUG|Test outside: true
19:06:58.24 (33182107)|USER_DEBUG|[7]|DEBUG|Test outside: null
19:06:58.24 (33393615)|EXCEPTION_THROWN|[7]|System.NullPointerException: Attempt to de-reference a null object
Yes, that is!
Apparently calling a nullified member of type Sobject of an object instance from outside is somehow handled by the runtime as null, whether you recall a field (cnt.tst.Name == null) or the member itself (cnt.tst == null); while calling the same member from inside an object method, correctly throws a null pointer exception as expected.
This seems related to how Sobjects are handled when used in SOQL relationship fields, such as:
1 2 3 | List<Contact> cntList = [Select Id, Account.Name From Contact limit 1 ]; System.debug( 'Account is: ' +cntList[ 0 ].Account); System.debug( 'Account.Name is: ' +cntList[ 0 ].Account.Name); |
In this example if the Account parent object is not presente, the debug outputs:
19:18:17.18 (79345369)|USER_DEBUG|[3]|DEBUG|Account is: null
19:18:17.18 (79634328)|USER_DEBUG|[4]|DEBUG|Account.Name is: null
19:18:17.18 (79634328)|USER_DEBUG|[4]|DEBUG|Account.Name is: null
This is somehow confusing.
I get that when dealing with SOQL queries this is useful (no null checking) but dealing with custom Apex Classes this can lead to real confusion.
These are my 2 cents, what do you think?
No comments:
Post a Comment