Developers still complain about the breadth of J2EE and Java EE and sometimes about the extensive specification. J2EE 1.4 and Java EE 5+ are actually only a release of independent APIs. Servlets (JSF or another Servlet-based framework), EJBs are the the only "executable" components which are intended to use APIs like JTA, IIOP JMS, JCA, JDBC, JPA....
As a Servlet / EJB developer you don't have to know these additional services, you can go with your business logic only. In this case you will only have to learn the Servlet (or a web framework of your choice) and the EJB component model. Servlets and EJB 3.X are very simple (you can build a simple app in few minutes), a web framework can be as complex as you like, but it was your choice. You still don't have to use a single "enterprise" API to develop an application on a Java EE server, but if you have to they are ready to use.
Lets consider the remaining APIs:
- JDBC - a stripped down version runs on Java ME, even together with JavaDB
- JMS - there are implementations (even from application servers considered as heavyweight), which run on embedded devices.
- Servlets - Java Card comes with built-in Servlet support
- JPA - nothing prevents it to be executed on an embedded device
- JTA - the jini framework came with 2PC and transactions semantics and was considered to be used on embedded devices as well. Btw. JTA API is probably the simplest one. With EJB 3.X you are even not intended to use it programmatically.
- EJB - the Glassfish v3 container is about 1MB, JBoss, WLS about the same size.
- JCA - actually some J2ME persistence APIs (e.g. FileConnection) are very similar to JCA
- IIOP - it actually take offs in the embedded space. It turns out, that it is very efficient for embedded communication (and was considered as too heavy for J2EE :-))
It seems like the APIs itself are not the problem, rather their implementation. As a vendor you can put an unlimited amount of bloat into every of those APIs. And it happens on regular bases. Recently I had to deploy a single EJB on a, well known, application server with a commercial IDE and had to provide an incredible amount of settings and tweaks. But they had nothing to do with Java EE and were vendor-specific. To demonstrate the difference, I copied exactly the same ejb-jar into Glassfish, then JBoss and it worked perfectly in both cases - without any strange settings.
Java EE isn't actual the real problem, rather than proprietary vendor extensions and additional services, which not only increase the complexity, but could lock you down to a single vendor. As long an API-implementation only sits on your disc and waits to be used, it doesn't increase the complexity.
Glassfish v3 e.g. is capable to load and unload EJB 3-container as an OSGI-bundle on demand. This would mean in that case: a Servlet application with loaded EJB 3 container would be more complex, than the same app running on the same Glassfish with deinstalled EJB 3-container - from my point of view it makes no difference...
I cannot wait for the first bloated OSGI servers, with millions of bundles and services. The first one is already on the horizon.
Btw. the Java EE specs are really good. Very useful to be used as an index to lookup things...
[The first chapter in "Real World Java EE Patterns" explains Java EE basics and a bit of J2EE history.]