How portable is J2EE?
Portability - which has been a key tenet of J2EE development - has proved to be a double-edged sword.
The write-once run-anywhere paradigm - in practice - results in a write once - and re-write 10% again to
deploy on the new platform. It takes another full project life cycle to determine that elusive '10%' that needs to be re-written and to re-write and re-test the application.
Continual 'extension' of existing frameworks by J2EE vendors
When an open source framework such as Struts or Hibernate gains popularity, each J2EE vendor releases their own
enhanced version of the framework (WebSphere Struts, OracleAS Toplink etc.).
This makes moving from one J2EE server to another that much more difficult.
Continual replacement of existing frameworks by the java community
As vendors create their own productivity enhancing variations of existing frameworks, the java community at large views these as proprietary - and launches a huge overhaul effort to replace the existing underlying framework.
Hence - Struts (a perfectly good, useful and powerful framework) has to-date been replaced by Spring MVC which has been superceded by JSF (not to mention
a few other competitors like Wicket
and Tapestry