J2ME in 2026

Basically all tutorials on J2ME I can find are

  1. ancient
  2. assuming you're using some kind of IDE
  3. working off of Sun's WTK
  4. some combination of the above
This is not great.

I have, fortunately however, managed to piece together enough information to be able to do so. I'll walk through building a simple J2ME app, using only free software that's still maintained (well, mostly) so that this is documented somewhere.

For tooling, we'll be using

OpenJDK 8
Still maintained for the time being. It's the last version of OpenJDK that supports code generation for the old versions of Java we're targeting.[citation needed]
ProGuard
We're not interested in "protecting" our application, but J2ME requires preverification and ProGuard appears to be the best choice here somehow.
MicroEmulator
Okay this one's not actually maintained anymore. But we're just using their stub libraries for the J2ME APIs.
bsdtar
Other ZIP-file creation utilities are available.
FFmpeg
Other image processing utilities are available.

$ mkdir -p ro/plesoianu lib out/ro/plesoianu out/META-INF
$ cd ro/plesoianu
ro/plesoianu$ wcurl https://felix.plesoianu.ro/mobile/pocket-gopher/PocketGopher.java
  % Total    % Received % Xferd  Average Speed  Time    Time    Time   Current
                                 Dload  Upload  Total   Spent   Left   Speed
100  22743 100  22743   0      0  28807      0                              0
ro/plesoianu$ cd ../../lib
lib$ wcurl https://repo1.maven.org/maven2/org/microemu/midpapi20/2.0.4/midpapi20-2.0.4.jar https://repo1.maven.org/maven2/org/microemu/cldcapi11/2.0.4/cldcapi11-2.0.4.jar
DL% UL%  Dled  Uled  Xfers  Live Total     Current  Left    Speed
100 --  87390     0     2     0                              449k      
lib$ cd ..
$ /usr/local/openjdk8/bin/javac -source 1.2 -target 1.2 -d out -bootclasspath lib/midpapi20-2.0.4.jar:lib/cldcapi11-2.0.4.jar ro/plesoianu/PocketGopher.java
warning: [options] source value 1.2 is obsolete and will be removed in a future release
warning: [options] target value 1.2 is obsolete and will be removed in a future release
warning: [options] To suppress warnings about obsolete options, use -Xlint:-options.
3 warnings
$ cd out
out$ wcurl https://felix.plesoianu.ro/mobile/pocket-gopher/home.txt
  % Total    % Received % Xferd  Average Speed  Time    Time    Time   Current
                                 Dload  Upload  Total   Spent   Left   Speed
100   1245 100   1245   0      0   3383      0                              0
out$ ffmpeg -loglevel error -f pbm_pipe -i - gdimp.png << EOT
> P1
> 32 32
> 0000000000000000000000000000000000000000000000000000000000000000000000
> 0000000000000000000000000000000000000000000000000000000000000001110000
> 0000000000000000000000001100000000000000000000000000000110000000000000
> 0000000010000000010000000000011000000001100000000100000000001010011000
> 0100000000110010000001101001111001110000001001111000110010010010011100
> 0000110001100010001001001001011000000111110000111010010110010010000000
> 0000000000111011110000001000000000000000000000111000000010000000000000
> 0000000011000000001000000000000000000000100000000000000000000000000000
> 0000000000000000000000111100000000000000000000000000001001111100000000
> 0000000000000000100000010000000000000000000000001000001100011110000000
> 0000000000111011100001101100000000000000000011100000011001100000000000
> 0000000011000001100000000000000000000000010000010000000000000000000000
> 0000000001000000000000000000000000000000010000000000000000000000000000
> 0001000000000000000000000000000000000000000000000000000000000000000000
> 00000000000000000000000000000000000000000000
> EOT
out$ unix2dos > META-INF/MANIFEST.MF << EOT
> Manifest-Version: 1.0
> MicroEdition-Configuration: CLDC-1.1
> MicroEdition-Profile: MIDP-2.0
> MIDlet-1: Pocket Gopher rebuilt, /gdimp.png, ro.plesoianu.PocketGopher
> MIDlet-Description: Rebuild of PocketGopher sources in 2026
> MIDlet-Icon: /gdimp.png
> MIDlet-Info-URL: http://microblog.ahti.space/nortti/2026-08-25-j2me-in-2026.html
> MIDlet-Name: Pocket Gopher rebuilt
> MIDlet-Vendor: Felix Pleșoianu, nortti
> MIDlet-Version: 1.0
> EOT
out$ tar -cf ../not-preverified.jar --format zip *
out$ cd ..
$ proguard -injars not-preverified.jar -outjars pocketgopher-rebuilt.jar -libraryjars lib/midpapi20-2.0.4.jar -libraryjars lib/cldcapi11-2.0.4.jar -dontshrink -dontoptimize -dontobfuscate -microedition
ProGuard, version 7.0.0
Reading program jar [not-preverified.jar] (filtered)
Reading library jar [lib/midpapi20-2.0.4.jar] (filtered)
Reading library jar [lib/cldcapi11-2.0.4.jar] (filtered)
Preparing output jar [pocketgopher-rebuilt.jar] (filtered)
  Copying resources from program jar [not-preverified.jar] (filtered)

Inshallah I'll write a proper writeup that exaplains what every bit here actually is for. For now, my sources were:

Creating deployable MIDlets with free software,
Pointed me at the proper FOSS software to look at and explained what ProGuard is actually needed for.
[EN] (Much) Faster Way to J2ME Development in 2026, 2026
Told me where to get the MicroEmulator stub libraries nowadays (the answer is Maven Central).
sdk/compile.sh in the discord-j2me project
Showed the actual commands to run if you are not using an IDE.