views:

554

answers:

3

Hi all,

I'm trying to build an app for both J2ME and J2SE. The presentation code will obviously be different, but I'm hoping to keep the logic common, as much as possible.

My plan is to use Ant or Antenna's preprocessor to select either the J2ME or J2SE Graphics object, with that class being the only intersection between my logic and display code. All I need is to swap a line or two of imports in a few files during my Ant/Antenna build task.

I'd like some advice on how to get this set up.

I've currently got two Eclipse projects, one J2ME and one J2SE. I have a couple ideas for how I could set up the preprocessor:

  • Have the J2SE code be the default, and only preprocess the J2SE code to swap in the J2SE specific imports
  • Use the Antenna preprocessor for both the J2ME and J2SE projects
  • Use Ant text substitution to make the necessary source modifications

i) looks hard to get set up right
ii) feels a bit kludgy
iii) seems least bad, because I don't see myself ever needing to use much more than a few conditional imports.

Has anyone had experience with this sort of thing? Some advice would be much appreciated.

+1  A: 

Antenna should do for most cases. The advantage of using a single source for both J2SE and J2ME is that you are saved from the maintenance of source code and you also eliminate the possibility of bugs creeping in. I too had similar problems, but I had to write a custom preprocessor that suited my need. But for most purposes antenna does the job beautifully

Edited: Sample build file

<project name="SomeProject" default="buildJ2ME" basedir="..">
...
...
...
    <taskdef name="jadUpdater" classname="net.jxta.j2me.tools.Jad" classpath="${lib.dir}/jxta-tools.jar"/>
    <taskdef resource="proguard/ant/task.properties" classpath="${lib.dir}/proguard.jar" />
    <taskdef resource="antenna.properties" classpath="${lib.dir}/antenna-bin-1.0.2.jar" />

    <macrodef name="preprocess">
        <attribute name="source"/>
        <attribute name="dest"/>
        <attribute name="symbols"/>
        <sequential>
            <wtkpreprocess 
                version="2"
                srcdir="@{source}" 
                destdir="@{dest}" 
                symbols="@{symbols}"
                printsymbols="true">

            </wtkpreprocess>
        </sequential>
    </macrodef>


    <target name="compile" depends="init">
        <copy todir="${temp.dir}/src" >
            <fileset dir="${src.dir}"/>
        </copy>

        <preprocess source="${temp.dir}/src" dest="${temp.dir}/preprocessed" symbols="${symbols}"/>

        <javac srcdir="${temp.dir}/preprocessed"
               destdir="${temp.dir}/classes"
               bootclasspath="${bootclasspath}"
               classpath="${lib.dir}"
               debug="off"
               source="1.3"
               target="1.1" />

       <antcall target="jarForObfuscate"/>
    </target>

    <target name="buildJ2ME" depends="clean">
        <property name="symbols" value="J2ME1,J2ME2"/>
        <antcall target="compile"/>
    </target>

    <target name="buildJ2SE">
        <property name="symbols" value="J2SE1,J2SE2"/>
        <antcall target="compile"/>
    </target>
...
...
...

</project>

Hope this helps!

Ram
So you reckon using Antenna to build the J2SE projects as well?Is there a way to process the Antenna-style defines in Eclipse, in a J2ME project? I'd like for J2ME code to be commented out while I'm editing, but as far as I can tell Eclipse can only do this in J2ME projects.
Symmetric
I would suggest that you use an ant build file with antenna-task as one of the targets in it, rather than depending on Eclipse. I know that writing an ant build file might take sometime, but you write that only once and it makes your life easy too. I have posted a sample build file in the edited answer.
Ram
+2  A: 

Both app versions have different ways to startup, right? One time it's a MIDlet and the other time a Java class with a static main method. In that case I don't see the requirement to use preprocessing. Both startup implementations could access the common code base and hand over either the J2ME or J2SE "graphics" object which implements an interface known to the common code base. This way the common code base does not need to know implementation details, it just needs the interface for the representation part.

BTW .. I had a similar situation some time ago and I felt more comfortable with setting up 3 Eclipse projects, a J2ME, a J2SE and a common logic project (technically also a J2ME project). This helps to prevent class name conflicts between the J2ME-/J2SE-only parts.

Oben Sonne
This has proven to be the best option for me -- I only needed to swap the J2ME and J2SE Graphics objects, so I've implemented an interface that wraps that object.I've also got a simple interface at every intersection of common and platform-specific code, as you suggested.Thanks for the suggestion!
Symmetric
A: 

Hi,

I've done it once with all j2me libraries replaced by my own fakes. These fakes would call all the needed j2se lib calls.

Sounds like a lot of work, but actually a lot of calls are similar, and you are probably not using everything so you only need to create a small subset of the available j2me classes

Endresult: source code which nearly doesn't need any #ifdef stuff

Toad