Stateful web/ejb components are convenient to use and maintain - they look and feel almost like real objects (see the perfect anti-facade). You don't have to synchronize the state between layers - after transaction everything is flushed transparently to the database. This happens without any expensive copying and data / DTO transformation between layers.
In a clustered environment your stateful HTTPSession/EJB is attached to a single cluster node and is not available on the others. It is essential to come back every time to the node with your data, what can be achieved with session affinity. In case the node fails, your conversational state gets lost.
State replication and clustering seems to be the solution to the problem, but it actually is not. The problem: most application servers use the "in memory application" which is asynchronous. The state is replicated after the transaction and not in the transaction. It means: if you server fails just after the successful transaction and before the replication - your session state gets lost. This increases the availability, but is not acceptable for many applications.
You could also replicate the state synchronously, or write it synchronously to a database to overcome this problem, but this not only won't scale, but also would significantly increase the probability of dead locks.
On the other hand: the state of a HTTPSession or a Stateful Session Beans is not transactional and not persistent per definition, so you should not rely on its high availability anyway. It should be only considered as a "conversational" cache which gets persisted during the next transaction. It means: you could loose the contents of your shopping cart, but not your order at the server failure.... This should be acceptable. If not, you should store the state in the database, and not the session...
[See Chapter 1 (the basics), page 26 in "Real World Java EE Patterns Rethinking Best Practices" for state / transactions discussion]