It happens to face exceptions in production environment, even if during development and testing everything was working good. In most of the cases, this strange behavior will be related to wrong transient attribute usage, transient attribute which value is not passivated and then its lost after activation. You can test your code, if it contains any bad practice implementations, by disabling application module pooling. Most of ADF developers know this, however only few really understand what is happening. Today I will present sample case, where bad practice is demonstrated practically.
Let's say developer decided to store temporary values in VO transient attribute and created new DummyAttr attribute in Employees VO:
Developer thinks - since I already have my temporary value in VO, why not to use it for another, this time permanent, attribute. And he calls transient attribute from permanent attribute getter method:
Thats it, Model is implemented. Next step, transient attribute should be somehow initialized. Its easy in ADF, we can use af:setActionListener component and initialize attribute directly from ViewController:
In our case, DummyAttr will be assigned with DepartmentName value:
At this point, functionality is implemented and can be tested. On runtime, transient attribute will be initialized in Departments page:
Employees page will be successfully opened:
Everything works good during testing. In production, when there will be high workload and many concurrent users, ADF will start to passivate Application Module instances and we will face a problem with such implementation. Production environment can be simulated by disabling Application Module Pooling:
User will open Departments page and will set transient attribute value:
Will try to open next page - Employees, and will get java.lang.NullPointerException. Why? Let's find an answer in detail log. When there is not enough space in the pool (during next submit in our test case), and Application Module instance is passivated, transient DummyAttr attribute value was not passivated and this means it was simply lost:
There is nothing to activate for transient DummAttr attribute, and since this attribute is called, exception is raised.
You should avoid such use cases as I just described and develop proper quality ADF code. In worst case scenario, which is not recommended anyway, you can force transient attribute passivation on attribute level:
Or even on VO level:
Then you can see that transient attribute will be passivated as well:
This means, code will work without exception, because activation will be done successfully. However, in my opinion, you should avoid this approach and use it only when you are really forced.
Download sample application, where Application Module Pooling is disabled and described bad practice is reproduced - AppModulePooling.zip.