Is there any truly practical way to avoid using DTOs, when passing data through Hibernate-backed transactional service methods? In other words, are DTOs the only non-hacky solution to avoiding lazy initialization problems?
I think the two popular alternatives to DTOs and the reasons I don't really like them are:
Open Session in View pattern. This I don't like as I would like to keep the service methods truly transactional (i.e. the Hibernate session is committed and closed when the method exits). This is mainly because I would like to not have to worry about transactions if I for example need to publish the service as a web service later on.
Passing domain/business objects through service methods instead of DTOs and eager fetching the needed attributes/properties. This is somewhat better. However in a non-trivial domain object hierarchy with complicated entity relations the eager fetching has to stop somewhere. And when it does, I can't see how this wouldn't very quickly turn into a complete hackaton replacing entities with referencing ids all over the place.
Am I missing something or are DTOs in fact the only solid approach from maintainability's point of view?
The only way to really use entities end to end is to use something a little bit more sophisticated than OpenSessionInView. In my experience you're going to have to manage the hibernate session manually at the application level. OpenSessionInView will only give you the same session for one request. After that you'll need to be constantly reattaching to the current session. Take a look at Seam and conversations, or implement your own Hibernate Session management. We currently manually manage our sessions based on when a wizard starts and ends and use Spring AOP to attach sessions to the right threads just in time(Sessions are not thread safe, not a good mix with AJAX)
WebServices on the other hand most certainly are going to need some form of DTO. I don't see a way around that. Entities may look like POJOs but aren't really, serializing them can range from difficult to nearly impossible. Just create DTOs that fit with the goal of the service method and be done with it.
Personally I don't think the DTO pattern is terrible, if you're just making a website it's feasible to go end to end with entities and it may even buy you some performance but if you'd like a more flexible architecture, stick with DTOs.