j2me-maven-plugin

The maven2 J2ME plugin supports the development of J2ME applications. The goals of this plugin cover the packaging, instrumentation, obfuscation, preverification process of the compiled classes and the creation of a java descriptor. The goals are configured using plugin configurations and profiles.

The creation of this plugin was inspired by j2me-maven-plugin.

This plugin is tightly integrated with ProGuard optimization, obfuscation and preverification is done using this library.

Since ProGuard version 4.0 preverification can be done without WTK.

The plugin itself is using Antenna in some cases. Also you may need Sun Java Wireless Toolkit for preverification goal.

Getting started

Use use our midlet-example project or j2me-simple Archetype to start your own maven 2 project.

Parameters

Regular j2me:package parameters

  • If test parameter is true then second test artifact is created. Dependency of scope test are bundled (except junit).
  • You can use inFilter to apply ProGuard classpathentry Filters to input jar
        <inFilter>!net/sf/bluecove/awt/**</inFilter>
  • assembly allows to bundle project dependency to resulting jar. By default all provided and system scope dependency are excluded from final jar all other included. assembly is fine grain filter for dependency.

    First plugins package goal assembles all dependency in one jar then it executes ProGuard (if enabled) which applies inFilter.

        <assembly>
            <inclusions>
                <inclusion>
                    <groupId>org.abc</groupId>
                    <artifactId>core</artifactId>
                    <classifier>4j2me</classifier>
                </inclusion>
            </inclusions>
            <exclusions>
                <exclusion>
                    <!-- This is optional, exclude of junit is hardcoded -->
                    <groupId>junit</groupId>
                    <artifactId>junit</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.yyz</groupId><artifactId>art1</artifactId>
                </exclusion>
                <exclusion>
                    <!-- org.yyz:art2 without classifier will still be included -->
                    <groupId>org.yyz</groupId><artifactId>art2</artifactId><classifier>app<classifier>
                </exclusion>
            </exclusions>
        </assembly>
  • dependencies in configuration section apply ProGuard classpathentry Filters to dependencies when WTK libs not used.

    Also exclude and include flags modify -libraryjars ProGuard params. By default all provided and system scope dependency used -libraryjars when calling ProGuard. exclude and include flags will also modify preverify classpath.

                <plugin>
                    <groupId>com.pyx4me</groupId>
                    <artifactId>j2me-maven-plugin</artifactId>
                    <configuration>
                        <proguard>true</proguard>
                        <useWtkLibs>false</useWtkLibs>
                        <libs>
                            <lib>${env.WTK_HOME}/lib/cldcapi10.jar</lib>
                            <lib>${env.WTK_HOME}/lib/midpapi20.jar</lib>
                        </libs>
                        <dependencies>
                            <dependency>
                                <groupId>net.sf.bluecove</groupId>
                                <artifactId>bluecove</artifactId>
                                <filter>!javax/microedition/io/**,!com/intel/bluetooth/**</filter>
                            </dependency>
                            <dependency>
                                <groupId>com.pyx4me</groupId>
                                <artifactId>cldcunit-se</artifactId>
                                <exclude>true</exclude>
                            </dependency>
                        </dependencies>
    
                    </configuration>
                </plugin>

    withTrail flag will also exclude or include Artifact Dependency Trail.

  • libs JVM libraries usually not in dependency list will be added to ProGuard params and preverify classpath if useWtkLibs is false.
        <libs>
            <lib>${env.WTK_HOME}/lib/cldcapi10.jar</lib>
            <lib>${env.WTK_HOME}/lib/midpapi20.jar</lib>
        </libs>

    Alternatively you can use MicroEmulator SDK API modules licensed under GNU General Public License version 2 (GPL).

        <properties>
            <me2Version>2.0.2</me2Version>
        </properties>
        .....
            <libs>
                <lib>${settings.localRepository}/org/microemu/cldcapi11/${me2Version}/cldcapi11-${me2Version}.jar</lib>
                <lib>${settings.localRepository}/org/microemu/midpapi20/${me2Version}/midpapi20-${me2Version}.jar</lib>
            </libs>

    N.B. This will not download API modules to your local maven repository. You need to have some sub project that has these modules in dependencies. The safe way is to add dependencies to maven-compiler-plugin.

  • preprocess Enable classes bytecode instrumentation.

    Java bytecode instrumentation is done using Javassist with the help of http://jour.sourceforge.net/ library.

    Preprocessing is required to create CLDC Unit tests. See instrumentation for configuration details and examples.

ProGuard

ProGuard is executed in j2me:package task after instrumentation if enabled or after jar assembly has been executed.

ProGuard arguments are controlled by following configuration Parameters proguard obfuscate inFilter

Some ProGuard options are created automatically

  • -keep public class Your MIDlet class
  • -libraryjars are created base on your project dependencies if useWtkLibs false
  • -verbose When executing maven -X
  • -printmapping $project.build.directory/proguard_map.txt and -printseeds $project.build.directory/proguard_seeds.txt

Additional ProGuard configuration can be added using proguardInclude or proguardTestInclude

See proguard for configuration examples.

Preverification

proguardPreverify to true if you want to use ProGuard instead of WTK for preverification.

For now this option is false by default.

Environment variables

If you are using ProGuard instead of WTK this variables are not required.

JAVA_HOME and WTK_HOME to compile MIDlets using examples provided below. PATH variable should contain %JAVA_HOME%\bin for WTK preverify to work.

Signing

Signing the jar/jad is possible by adding

    <configuration>
        ...
        <sign>true</sign>
        <keystore>yourstore.jks</keystore>
        <keyalias>youralias</keyalias>
        <keystorepass>secret</keystorepass>
        <keypass>secret</keypass>
        ...

to the configuration part for the j2me plugin. Siging is then performed automatically during the build.

The better way to supply the passwords is to remove both password tags from pom and invoke the build like this:

    mvn install -Dj2me.storepass=secret -Dj2me.keypass=secret

Running on the WTK emulator

You can start the application in the emulator by using this command:

    mvn j2me:run

To configure different emulator:

    mvn j2me:run -Dj2me.device=DefaultGreyPhone

Check the antenna WtkRun task documentation for the list of available devices.

Usage

Simple MIDlet pom.xml example

<project>
    ...
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.3</source>
                    <target>1.1</target>
                    <compilerArguments>
                        <bootclasspath>${env.WTK_HOME}/lib/cldcapi10.jar${path.separator}${env.WTK_HOME}/lib/midpapi20.jar</bootclasspath>
                    </compilerArguments>
                </configuration>
            </plugin>

            <!-- Create application loadable on the phone -->
            <plugin>
                <groupId>com.pyx4me</groupId>
                <artifactId>j2me-maven-plugin</artifactId>
                <executions>
                   <execution>
                        <goals>
                            <goal>package</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <wtkHome>${env.WTK_HOME}</wtkHome>
                    <proguard>false</proguard>
                    <obfuscate>false</obfuscate>
                    <jadAttributes>
                        <Created-By>Bartek Teodorczyk</Created-By>
                    </jadAttributes>
                    <archive>
                        <manifestEntries>
                            <url>${pom.url}</url>
                        </manifestEntries>
                    </archive>
                    <midlets>
                        <MIDlet>
                            <name>SimpleDemo</name>
                            <icon>/me2-icon.png</icon>
                            <class>org.microemu.midp.examples.simpledemo.SimpleDemoMIDlet</class>
                        </MIDlet>
                    </midlets>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>

pom.xml example of MIDlet suite with two MIDlets the second one for tests. The application is using JSR-82 and JSR-75.

<project>
    ...
    <dependencies>

        ...

        <dependency>
            <groupId>org.microemu</groupId>
            <artifactId>microemu-jsr-75</artifactId>
            <version>2.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>net.sf.bluecove</groupId>
            <artifactId>bluecove</artifactId>
            <version>1.2.2</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>

    <properties>
        <wtk.bluetooth.enabled>true</wtk.bluetooth.enabled>
        <wtk.optionalpda.enabled>true</wtk.optionalpda.enabled>
    </properties>

    <build>
        <plugins>
            ...

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.3</source>
                    <target>1.1</target>
                    <compilerArguments>
                        <bootclasspath>${settings.localRepository}/org/microemu/cldcapi11/2.0.2/cldcapi11-2.0.2.jar${path.separator}${settings.localRepository}/org/microemu/midpapi20/2.0.2/midpapi20-2.0.2.jar</bootclasspath>
                    </compilerArguments>
                </configuration>
            </plugin>

            <plugin>
                <groupId>com.pyx4me</groupId>
                <artifactId>j2me-maven-plugin</artifactId>
                <executions>
                   <execution>
                        <goals>
                            <goal>package</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <wtkHome>${env.WTK_HOME}</wtkHome>
                    <midlets>
                        <MIDlet>
                            <name>Main App</name>
                            <icon>/app-icon.png</icon>
                            <class>com.corp.MainMIDlet</class>
                        </MIDlet>
                        <MIDlet>
                            <name>Test App</name>
                            <icon>/app-icon.png</icon>
                            <test>true</test>
                            <class>com.corp.tests.TestMIDlet</class>
                        </MIDlet>
                    </midlets>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>

pom.xml example of MIDlet using JSR-82.

<project>

    ...

    <dependencies>

        <dependency>
            <groupId>org.microemu</groupId>
            <artifactId>microemulator</artifactId>
            <version>2.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>net.sf.bluecove</groupId>
           <artifactId>bluecove</artifactId>
            <version>1.2.2</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            ...
            <plugin>
                <groupId>com.pyx4me</groupId>
                <artifactId>j2me-maven-plugin</artifactId>
                <executions>
                   <execution>
                        <goals>
                            <goal>package</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <wtkHome>${env.WTK_HOME}</wtkHome>
                    <useWtkLibs>false</useWtkLibs>
                    <midlets>
                        <MIDlet>
                            <name>Main App</name>
                            <icon>/app-icon.png</icon>
                            <class>com.corp.MainMIDlet</class>
                        </MIDlet>
                    </midlets>
                    <libs>
                        <lib>${env.WTK_HOME}/lib/cldcapi10.jar</lib>
                        <lib>${env.WTK_HOME}/lib/midpapi20.jar</lib>
                    </libs>
                    <dependencies>
                        <dependency>
                            <groupId>net.sf.bluecove</groupId>
                            <artifactId>bluecove</artifactId>
                            <!-- this is added to avoid warning like this:
                                 [proguard] Note: duplicate definition of library class [javax.microedition.io.Connection]
                            -->
                            <filter>!javax/microedition/io/**,!com/intel/bluetooth/**</filter>
                        </dependency>
                    </dependencies>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>