J2EE 1.3/1.4 specifications were relatively easy. The reason: the hard stuff like locking, concurrency, versioning, eager/lazy loading or primary key generation wasn't specified. In projects such functionality was needed - so developers had to use vendor specific stuff to provide the required (actually essential) foundation. Application servers offered these services as additional functionality, which was configured and "activated" using proprietary deployment descriptors. The problem here: even basic functionality like locking had to be specified in vendor-specific descriptors. There were also subtle differences between the application servers. The main work porting J2EE 1.X applications was to take into consideration this differencies and translate them between vendors (often mission impossible :-)). Tools like XDoclet were crucial, but XDoclet didn't supported all vendor specific extensions of different vendors. The meta-tags varied also between vendors so it wasn't pleasure to built portable applications.
The Java EE 5 simplified the programming model, but the specification is more complex now. This is actually good, because now the vendor specific functionality is standardized. So large, vendorspecific, deployment descriptors are no more needed. Actually no xml-Deployment Descriptor is needed. In case you entity 3.0 persistence is used only a short descriptor (for all entities) is needed. Sample:
<persistence-unit name="test" >
//vendor specific stuff
Vendor specific extensions can be provided as key-value pairs - but are not essential. I started with my first Java EE 5 project on JBoss 4.0.4. then moved to glassfish. No recoding or refactoring was needed. I only provided two optional toplink key-value pairs. Now I'm developing with glassfish and deploying to JBoss - it still works. I will then migrate the whole app to glassfish - and I do not expect any problems. The application is rather small (some entities, stateless sessions beans, timer service, webservice client and JMS) but uses most of the Java EE 5 APIs. It is also critical (heating control) :-).
In the practice we will still have to struggle with different implementations and especially quality of different vendors. But the syntactic "war" in vendor-specific deployment descriptors is over :-).
NEW: Effective Java EE 7 -- Available For Streaming