freej2me: a free J2ME emulator with libretro, AWT and SDL2 frontends
A free J2ME emulator with libretro, awt and sdl2 frontends.
At a glance
- What is it?
- freej2me is a Java ME emulator that runs classic MIDlet jars on a desktop, on a Raspberry Pi, or as a libretro core inside a frontend, and it is the kind of project that exists because the original tool chain for those games is hard to get running today. It suits a retro gaming or embedded project, and its build is Ant and make rather than a package manager.
- Who is it for?
- freej2me fits a developer restoring J2ME games, a Raspberry Pi project that needs to run MIDlets, or a libretro frontend user who can host a Java runtime alongside the core. It does not fit a phone project, since the J2ME API it emulates is gone from modern handsets, and it does not fit anyone who expects a prebuilt binary for every platform.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 19 days ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What freej2me emulates and for whom
freej2me is a free J2ME emulator with libretro, awt and sdl2 frontends, and it is written in Java.
The subject is Java ME, the small profile Java that ran on feature phones, and more specifically the MIDlet model that most of those games used. A.jar from a Nokia or Sony Ericsson handset is not a modern Java program, and it will not run on a desktop JVM without an implementation of the MIDP and CLDC APIs it expects. That is what this project provides.
The context for the project is worth understanding, because it explains the shape of the thing. The readme links a Retropie forum thread titled would you like to play nokia j2me games on retropie, and a support thread for the emulator itself. The authors are David Richardson and Saket Dandawate, both credited with the retropie tag, so the origin is a request to get J2ME games working on a Raspberry Pi running Retropie, which pairs emulators with retro game consoles.
The audience is therefore two overlapping groups: people who want to play or preserve old phone games, and people embedding a retro frontend on a small computer. The three frontends exist for exactly those situations, and the choice between them is not a matter of preference so much as of where the emulator is going to run.
Three frontends, three targets
The build produces three jar files, and the readme describes what each one is for.
freej2me.jar is the standalone AWT jar executable, which is the plain desktop version. freej2me-lr.jar is the libretro executable, and the readme notes it has to be placed on the frontend's system/ folder, since it acts as a BIOS for the libretro core and runs the J2ME jars. freej2me-sdl.jar is the jar meant to be used in conjunction with SDL2, and SDL2 is what allows FreeJ2ME to run on a Raspberry Pi.
That libretro detail is the interesting one. In the libretro model, a core is a shared library that a frontend loads, and the core here needs a Java runtime and a jar of games to work with. The jar is placed alongside the core in the frontend's system/ directory, and the core is loaded the way a BIOS would be, with the jar supplying the software that the core runs. The result is that a user with a libretro frontend can play J2ME games the same way they play console games, with the frontend handling the input and display.
The SDL2 frontend is the one for embedded hardware. It is a separate native binary in addition to the jar, which is why the build has an extra step for it, and it is the route for a Raspberry Pi.
So the choice of frontend is really a choice of host: a desktop for AWT, a retro frontend for libretro, and a small Linux box for SDL2.
Building the jars with Ant, and the two native pieces
Building the jars is a one-command job, from the root directory of the repository:
cd freej2me/
antThat produces the three jars in the build/ directory. The repository carries a build.xml at the top level, which is the Ant build file, so Ant is the build tool and there is no package manager involved.
The libretro and SDL2 jars need additional native binaries compiled before use, and the readme documents both.
The SDL2 binary is built from the root directory:
cd src/sdl2
make
make installThe libretro core on Linux is built from a terminal in the freej2me folder:
cd src/libretro
makeThat produces freej2me_libretro.so in src/libretro/, which is the core libretro will use to interface with freej2me-lr.jar. The readme then explains the deployment: move the .so into your libretro frontend's cores/ folder with freej2me-lr.jar on system/, and the frontend should then be able to load j2me files.
For Windows there is a longer path, because the core has to be cross-compiled. The readme says you need mingw or MSYS2 64, and that the guide uses MSYS2 as it is easier to set up and works closer to linux syntax. You move the freej2me folder into the MSYS2 home, open the MSYS2 UCRT64 terminal, and install the toolchain:
pacman -S mingw-w64-ucrt-x86_64-gcc
pacman -S makethen build as before, which yields freej2me_libretro.dll in freej2mefolder/src/libretro/. The readme notes the windows core has only been tested on Windows 10 x64.
The container caveat, and the Windows path problem
Two warnings in the readme will cost an afternoon if you hit them without warning, so they are worth stating plainly.
The first is about the libretro core in containers. The note says the core DOES NOT WORK on containerized and sandboxed environments unless it can call a java runtime that also resides in the same sandbox or container, and it says to keep that in mind if you are running a libretro frontend through something like flatpak or snap. That is a specific and reasonable constraint: the core is not self-contained, it shells out to a Java runtime, and if the runtime is outside the sandbox boundary the call fails. Flatpak and snap are common ways to package a libretro frontend, so this is not an edge case.
The second is a path quirk on Windows. When running under Microsoft Windows the readme says paths require an additional slash prefix, so C:\path\to\midlet.jar should be passed as file:///C:\path\to\midlet.jar. The reason is that the argument is a file URL, and a Windows drive-letter path is not a valid URL without the file:/// scheme and the extra slash.
Both of these are the kind of detail that makes an emulator feel fragile when it is actually fine, and both are documented, which is more than most projects in this space manage.
The build matrix in the repository also shows continuous integration through a Java CI workflow badge and a .gitlab-ci.yml file, and the source lives under src/ with package/ and resources/ directories for the packaged output and the assets.
Running it: the filepicker, the command line, and where your saves go
Launching the AWT frontend, freej2me.jar, brings up a filepicker to select the MIDlet to run, which is the simplest path and needs no arguments at all.
For anything scripted, the readme gives the command line form:
java -jar freej2me.jar 'file:///path/to/midlet.jar' [width] [height] [scale]where width and height are the dimensions of the simulated screen and scale is the initial scale factor of the window, and all three are optional arguments. The SDL2 frontend, freej2me-sdl.jar, accepts the same command line format aside from the scale option, which is unavailable there.
One behaviour catches people out and is documented plainly: FreeJ2ME keeps savedata and config at the working directory it is run from. And there is a precedence rule on top of that, since any resolution specified at the config file takes precedence over the values passed via command line. So a midlet that renders at the wrong size despite a width and height on the command line is usually a config file setting the resolution, not a bug in the argument parsing.
Together those two details mean the emulator has state that follows the directory, not the user. Run it from a different folder and your saved games appear to be gone.
The keymap documentation lives in a separate KEYMAP.md file in the repository root, and the readme points to it for the more complete set of bindings.
The controls, and the two things that surprise new users
The control scheme is compact and J2ME-shaped, and two parts of it catch people out.
Q and W are the left and right softkeys. Arrow keys are navigation, unless the phone is set to Standard, in which case the arrow keys become 2, 4, 6 and 8. Enter acts as the Fire key, or as 5 in Standard mode. ESC opens the settings menu. E and R are alternatives to the star and hash keys.
The first surprise is the number pad. The readme says numbers work as expected, and the number pad is inverted, with 123 swapped with 789, like a phone. That is faithful to the handsets, where the keypad layout places 1 at the top left, but it means a keyboard user pressing 7 gets 1, which looks like a bug until you know.
The second surprise is the Standard mode, which exists for games written for a different key map. The arrow keys becoming 2, 4, 6 and 8 is not a convenience, it is emulating a specific handset's keypad, and the mode setting also changes what Enter does. If a game responds to the wrong keys, switching the phone type in the settings menu is the first thing to try.
The AWT frontend has a few extras of its own: Ctrl+C takes a screenshot, and plus and minus control the window scaling factor, which is useful on a high density display where the emulated phone screen would otherwise be unreadably small.
State of the project, the licence question and the roadmap
The project is MIT licensed in spirit but the repository's licence field is recorded as a custom licence that GitHub cannot classify, so the LICENSE file in the repository is the text to read rather than any badge. This is a description of how the licensing is arranged and not legal advice.
The maintenance facts are simple. The repository is not archived, the last push was on 2026-10-04, and there are no GitHub releases, so the build from source with Ant is the only documented path to the jars. The CI badge is for a Java workflow, and there is a .gitlab-ci.yml alongside the GitHub workflow directory, so the project is built on two services.
The roadmap in the readme is refreshingly concrete and admits the real constraint. The three goals are to get as many games as possible to work well, to document games that work well in the wiki, and to reduce as many bugs as possible. The middle item is the one that tells you how the project is actually used: compatibility is per game, it is not uniform, and the answer to which games work is a wiki rather than a specification.
That is honest, and it is the right expectation to carry in. A J2ME emulator implements a large and irregular API surface, and different games use different parts of it, so a midlet that runs perfectly on one emulator may not start on another. The per-game documentation is how users find out whether a title is playable.
Contributing is straightforward in two tracks, separated by whether you write code. A developer opens an issue, tries to solve it, posts a possible solution on the issue, and then submits a pull request implementing it. Anyone who is not a developer should post on the discussion thread only, which is the Retropie support thread linked from the readme.
Editorial conclusion
freej2me fits a developer restoring J2ME games, a Raspberry Pi project that needs to run MIDlets, or a libretro frontend user who can host a Java runtime alongside the core. It does not fit a phone project, since the J2ME API it emulates is gone from modern handsets, and it does not fit anyone who expects a prebuilt binary for every platform. Before using it, build the AWT jar with ant and check the keymap file for the controls, since the number-pad inversion and the Standard mode remapping are the two things that surprise new users.
Frequently asked questions
What is freej2me and what does it emulate?
It is a free J2ME emulator written in Java, with libretro, AWT and SDL2 frontends. It runs the MIDlet jars that Java ME games shipped as, on a desktop, on a Raspberry Pi through SDL2, or inside a libretro frontend.
How do I build freej2me from source?
From the root directory, cd into freej2me/ and run ant, which creates three jars in build/: freej2me.jar for the standalone AWT frontend, freej2me-lr.jar for libretro, and freej2me-sdl.jar for use with SDL2. The libretro and SDL2 jars need extra native binaries, built with make in src/sdl2 and src/libretro.
How do I run a MIDlet jar with freej2me?
Launching freej2me.jar opens a filepicker to choose the MIDlet. From the command line you can use java -jar freej2me.jar 'file:///path/to/midlet.jar' [width] [height] [scale], where the dimensions set the simulated screen and scale sets the initial window scale factor, and the SDL2 frontend takes the same arguments without the scale option.
Does the freej2me libretro core work inside flatpak or snap?
The readme states the core does not work on containerized or sandboxed environments unless it can call a java runtime that also resides in the same sandbox or container, so a frontend packaged with flatpak or snap needs the runtime inside the same boundary.
Where does freej2me keep saved games and configuration?
FreeJ2ME keeps savedata and config at the working directory it is run from, and any resolution specified at the config file takes precedence over the values passed on the command line. The readme also notes that on Windows a path such as C:\path\to\midlet.jar has to be passed as file:///C:\path\to\midlet.jar.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/hex007-freej2me)Was this useful?