Even in areas you'd expect the Java EE specification to cover have incompatibilities or inconsistencies. As an example, in an ejb-jar.xml file if an unused <resource-ref> is included then some versions of WebLogic ignore the entry while some versions of WebSphere generate misleading error messages.
Transaction management is another minefield, with different application servers having differing defaults - resulting in strange error messages from applications that might work on WebLogic but throw exceptions relating to nested transactions on WebSphere. There are other examples, such as shared connections, where - depending upon the application server - a connection sharing scheme may be emulated or actually shared. The end result may be that a working application on one server may result in unpredictable behavior on another.
Application servers may also implement the Java specification in differing ways. For example, on WebLogic it is possible to have an interface hierarchy in which the remove (Object primaryKey) method occurs both in an application interface and in the EJBHome interface, both of which are used in the same EJB implementation class. While this is fine in WebLogic, errors are generated by the EJB compiler at deployment time in WebSphere.
So there is considerable variability between different application servers for those aspects of an application that sit outside or on the fringe of the specification. Oracle's purchase of BEA at least raises the possibility of the companies working together either on a consolidated application server or on making the two application servers more consistent. If they do this, it will be a considerable step towards establishing an implicit standard in these areas. This may mean greater consensus around how some of these fringe items should work or be defined.
I suspect IBM is unlikely to follow Oracle in ironing out its differences with BEA. However, others in the field - possibly in the open-source camp - might be able to agree a common model and this may become accepted as an implicit standard over time. This can only be a good thing for those of us tasked with the niggling difficulties in working with different Java containers.®
Wow, where to begin?
Oooh, a topic for me. To add to your list:
1. Converting from byte to String without specifying the encoding. Good trap for young players this - 7-bit bytes work fine until... until... you run on an OS/390 box running EBCDIC.
2. java.nio. An absolute dogs breakfast this. Garbage collection is different on Windows or UNIX (to be fair this is due to differences in the underlying file system model, but Java should be abstracting this). If you're copying files to an SMB mounted drive on windows using nio, the maximum block size is 62MB. The maximum number of open files on Sun/Windows 1.4 is much smaller than it should be. The list goes on.
3. Swing. Yes, this should be obvious, but it's not just a case of different layouts, it's different functionality too. I give you JComboBox.setPrototypeDisplayValue, which does not work as advertised on Windows. And don't even start me on the GTK+ widgets. Any moderately complex, well designed UI really has to include different code for different LayoutManagers.
4. Memory requirements. Back in the bad old days on JDK 1.4 we found simply switching JVM from Sun to IBM on Linux raised memory requirements by 50%. Again, less of an issue now but still crops up now and again.
5. JVM bugs. Goes without saying I suppose. The IBM 1.3 JVM was big trouble, but even though it's much better now we still hit a few. We have IBM, Sun, JRockit and Apple JVMs here and find ourselves needing to test on all of them more than I'd like.
6. Security. Different JCE Providers supply different algorithms, different root certificates and have differing support for X.509 Certificate extensions. This is a definite issue for us, although things are much better than they were with Java 1.4.
7. Locales. A variation on point 2, but the number of questions we've had when a client has moved from staging to production and found all their ISO-8859-1 characters are now mapping to some Windows codepage are now legion.
That's off the top of my head, that's just J2SE, and that's ignoring the obvious no-no's like calling the com.sun packages directly.
Obviously things are a lot better than coding in C, but I can guarantee that if you're developing for multiple customer environments, any form of I/O to disk, screen or network is a potential problem.
"if we just take the CLR functions, .NET is vastly superior to Java and better organised"
And you clearly don't know what you're talking about. CLR is the runtime environment (bytecode compiler / interpreter), the equivalent of the JVM. The bytecode instructions for both are remarkably similar, which isn't surprising since the CLR evolved from J++ (the deliberately incompatible implementation of Java that got MS into legal hot water).
I think you meant that the .Net class library is "vastly superior" to the Java one. While there is some cruft in the Java class library (just how long are come things going to be deprecated before they're removed?) the differences are minor. The only area where differences are considerable is in the GUI components, and it took a long while for MS to even provide a decent layout manager.
When it comes down to it, the differences between C# and Java (the languages themselves) aren't enough to say one is better than the other. Likewise for the class libraries, although much more third party software exists for Java than C#/.Net. It's really whether you want to be tied to a platform like Windows, with it's indifferent performance, limited scalability, expensive licensing and legendary security issues.
It really boils down to the implementation
Take these sentences: "For example, we had an application running on one hardware platform using a 64-bit JVM and all was fine. In moving to a new platform, there was only a 32-bit JVM available. On this platform the application suddenly started experiencing out of memory exceptions." What was he doing? Some high performance application that soaked up every iota of memory on the system? In general, the java apps I've worked with do not do this when going from platform to platform, so it's something in the code.
Odds are all too good that it is another app where the developers "assumed" they had unlimited amounts of memory available, and good memory management practices went out the window. Or, worse, they just didn't give any thought as to the memory footprint. No wonder most java apps are slow, clunky memory hogs. Just because the platform reclaims unused memory doesn't mean you don't need to manage it. I can write a perl script for ETL that can use everything our mainframes have and then some, or I can write them to manage what I use. It's up to me and my program, not the language.
I speak from the receiving end of having to push these apps out and manage them -- not all apps are equal, and not all coding memes fix things. Remember the coders that thought their memory problems in wfw 3.11 would go away with win95? It was BS then, and it is BS now. Well written, .NET and java apps are useful and portable. So are perl scripts. But when good practices go by the wayside, portability is lost.
It's not to say that they are poor programmers -- just that apps written that don't follow portability guidelines and best practices won't port all that good, and who should be surprised? As to waving the magic .NET wand at it -- wow. Portability within the Windows platform? <sarcasm>Mighty portable, mighty portable.</sarcasm>