Rossen Stoyanchev at Spring Framework is finally ready to tackle the thorny issue of
The new annotation-based handlers allow easy definition of simple controllers, but when combined with JDK 7′s unpredictable ordering of reflected methods, problems could occur..
@ModelAttribute annotation on a method essentially defines it to provide “reference data”; being calling to populate the model, before the handler method is invoked.
Essentially the problem arose when using two or more
@ModelAttribute methods to load entities or provide reference data, with one depending on the other.
The most common scenario would probably be:
- load some entity from the database
- calculate or provide reference data, dependent on that entity.
@ModelAttribute("job") protected Job loadOrCreate (@RequestParam(value="id", required=false) Integer id); @ModelAttribute("jobDisplay") protected JobDisplay buildJobUI (@ModelAttribute("job") Job job);
Reflection order used to be fairly predictable. However in JDK 7, deliberate changes were made to reduce people depending on reflection order.
What I found, is that due to reflection ordering,
buildJobUI() was being found before
Since Spring was not coded to resolve dependencies, but just processed in the order returned,
buildJobUI() was having a blank default
Job instance created for it & data binding performed into that. Following that,
loadOrCreate() was skipped since the attribute was already present in the implicit model.
Job was never loaded from the database,
loadOrCreate() was skipped, and fields were bound into an incorrect blank instance. As you would expect, this resulted in total UI failure.
Rossen’s plan is to check
@ModelAttribute method dependencies and invoke them in an appropriate order (vs the current order determined by reflection), or raise an exception (e.g. circular dependency).
While adding a significant degree of complexity & sophistication internally, at the API level this should provide an “it just works” intuitive extension of the present mechanism.
Rossen and Patras Vlad Sebastian have also opened consideration of
@ModelAttribute method depends on an
@RequestMapping method, i.e. a command object bound and validated by the
@RequestMapping method? Rossen thinks he could treat those differently and invoke them after, not before. He’s re-opened an old ticket SPR-5695 and will explore that as an option.
To me, this makes sense. I quite often have “render” methods to build & supplement the View Model, based on the entity after request-handling. However to some extent, I miss having a clear distinction between “referenceData” and “renderModel” as these are quite different phases of the request-handling lifecycle.
Do you use
@ModelAttribute methods? What do you think about the proposed improvements?
Read the full discussion here:
- SPR-6299 Support for @ModelAttribute interdependency