- First: Session/TA-state was, in fact, not hidden below the service facade, because domain objects (detached hibernate entities) were used in the service interface, resulting in plenty of LazyInitializationExceptions and duplicate objects. Tedious DTO's (see Fowler on local DTOs) would have avoided this, but at an unacceptably high price of cumbersome code-duplication.
- Second: The "natural unit of work" in the application was handling one http request. So, the presentation code had to be careful not to call the service facade twice (or otherwise take over session/ta-control explicitly). So, after all, the presentation layer was, indeed coded, without any knowledge of the technical details below the service facade - sadly it had to know them to work properly.
In my current project, hibernate sessions and transactions are controlled almost entirely from a ServletFilter (See Gavin King's long-session-pattern) - and wow: no more LazyInitializationExceptions - nice "per-request-transactions". And the best of it: presentation and business layer are both freed from doing awkward things pertaining to hibernate persistence (re-attaching detached objects, explicitly setting ta-boundaries, pre-loading lazy collections before handing them back to someone who might need them). It's all hidden above. The only thing left to do is to request a fresh hibernate session at some sensible point (e.g. whenever the user is done with one set of "top-level-objects" and requests a new one).
Ah, yes, so Spring turned out to be rather useless in this particular case ...