What I'm trying
I'm trying to use java.util.TreeMap
in a J2ME application. I know that TreeMap
is present on J2SE but not on J2ME, so I've made some efforts to port the J2SE 6.0 TreeMap
to J2ME 1.2 and included it in my Midlet Jar. This involved porting half of the collections framework, but now I'm (theoretically) done with that and want to test it.
The error
But when I start my app on a SUN J2ME SDK 3.0 emulator (DefauldClclPhone2) I get this exception:
java.lang.NoClassDefFoundError: java/util/TreeMap
java.lang.Class.invoke_verify(), bci=0
java.lang.Class.initialize(), bci=117
com.companyname.test.TestMidlet.<init>(), bci=19
java.lang.Class.newInstance(), bci=0
com.sun.midp.main.CldcMIDletLoader.newInstance(), bci=46
com.sun.midp.midlet.MIDletStateHandler.createMIDlet(), bci=66
com.sun.midp.midlet.MIDletStateHandler.createAndRegisterMIDlet(), bci=17
com.sun.midp.midlet.MIDletStateHandler.startSuite(), bci=27
com.sun.midp.main.AbstractMIDletSuiteLoader.startSuite(), bci=52
com.sun.midp.main.CldcMIDletSuiteLoader.startSuite(), bci=8
com.sun.midp.main.AbstractMIDletSuiteLoader.runMIDletSuite(), bci=161
com.sun.midp.main.AppIsolateMIDletSuiteLoader.main(), bci=26
On a real device I get "Error in Application"
but can't see the actual Exception because I don't have the matching SDK right now.
What's so stange about that error
I'm puzzled by the fact that my application successfully underwent the preverification process. I always experienced that a missing class (and I had many of them some days ago) triggers an error in the preverifier. So I concluded that after successfull preverification there cannot be any NoClassDefFoundError
on the device.
Details
The directory structure inside my jar looks like this:
test.jar
com
companyname
(my application classes, including the Midlet class)
java
lang
Comarable.class
Iterable.class
(some others which are missing on J2ME)
util
TreeMap.class
TreeSet.class
(many others which are missing on J2ME)
I also made sure that TreeMap.class
is in the Java 1.2 class file format.
I'm targeting CDLC 1.0 and MIDP 1.0, so my preverifier is using the classpath ${wtk.home}/lib/cldc_1.0.jar, ${wtk.home}/lib/midp_1.0.jar
Just a thought: Is there any special check in the J2ME classloader that prevents it from loading a java.util.*
or java.lang.*
class from an application jar? I never heard of that, but maybe they did something like this as a security feature?
Conclusion and Solution
As Joachim Sauer pointed out, the classloader will not load classes in java.*
if I defined them. So I had to move them to another package, actually to com.companyname.j2meport.java.util
. While my own code could then import those classes from there, this is not an option for closed-source third-party-libs which refer to java.util.TreeMap.
I finally managed to change these references to my own classes using the extension mechanism of Retrotranslator, a tool I was already using in my build process but of whose capabilities I was not fully aware.
My J2SE library, which has dependencies on other J2SE libraries, now runs on J2ME!