How To Make J2ME Apps Work for the WAP Flat

Because I am a big fan of networked J2ME applications, such as Google Maps Mobile, I want to use them with my WAP flatrate. The downside is that the WAP flat requires some special HTTP headers to be set, otherwise the HTTP requests get blocked by their gateway – and most of the J2ME apps don’t have these headers.

So what can you do?

If the application is open source, fine. Go ahead, add the headers to the sourcecode and recompile. With closed source applications, e.g. Google Maps Mobile, it gets a little tricky. Here are the basic steps you need to do:

  1. download j2me app (.jar + .jad)
  2. extract class files from .jar file
  3. decompile (*)
  4. search decompiled classes for networking code
  5. add special http headers to networking code
  6. recompile changed classes
  7. preverify changed classes
  8. update .jar file with changed classes
  9. update .jad file if necessary

(*) note: obfuscation and preverification of class files makes it hard to decompile the j2me app with a decompiler such as JAD Decompiler (http://www.kpdus.com/jad.html). It results in decompilation errors and thus you can not recompile the code, as the sources are full of errors.

Because the standard decompile/change/recompile procedure does not work if decompilation fails, the only way to add the required HTTP headers is to modify the application’s bytecode directly without decompiling the class files. For this purpose you could use the javassist bytecode engineering API (http://www.csg.is.titech.ac.jp/~chiba/javassist/):

if (m.getClassName().equals(“javax.microedition.io.Connector”)
&& m.getMethodName().equals(“open”)) {
m.replace(“{“
+ “$_ = $proceed($$);”
+ “$_.setRequestProperty(\”User-Agent\”,\”Profile/MIDP-2.0 Configuration/CLDC-1.0\”);”
+ “$_.setRequestProperty(\”X-WAP-Profile\”,\”foo\”);”
+ “}”);
}
powered by Java2html

The snippet above sets the User-Agent and X-WAP-Profile header directly after each call to Connector.open(). “$_ = $proceed($$)” inserts the original call to Connector.open(), with “$_” being the returned value (an object of type HttpConnection in this case) and “$$” being the parameters (the URL of the server in this case). After the connection has been opened, we use the returned HttpConnection object (“$_”) to set the User-Agent and X-WAP-Profile headers. See the complete source code here.

For more information about the javassist library you might want to check out their javassist tutorial or this article from IBM developerworks.

1 comment so far

  1. ali on

    Hi,
    i am using javassist to convert a midlet class.
    i want the midlet to implement commandListener for eg if the midlet class is declared as follows public class a extends MIDlet i want to change it to public class a extends MIDlet implements CommandListener. i know how to add a new method for commandAction and i also would like to know if the midlet is already implementing the commandListener. hope you can help me out. thanks in advance.


Leave a reply