20

I'm a longtime C++ programmer, new to Java. I'm developing a Java Blackberry project in Eclipse. Question - is there a way to introduce different configuration sets within the project and then compile slightly different code based on those?

In Visual Studio, we have project configurations and #ifdef; I know there's no #ifdef in Java, but maybe something on file level?

Kevin Panko
  • 8,356
  • 19
  • 50
  • 61
Seva Alekseyev
  • 59,826
  • 25
  • 160
  • 281
  • 2
    If you're just concerned about what goes into your jar files (i.e., production, not development), your build system (for example, Ant) is the place where you can control what files get built. – jdigital Dec 17 '09 at 15:36
  • Thanks all, I see. Conditional compilation (sort of) is easy enough, but there's apparently no native support for multiple targets in a project in Eclipse. I'll go read up on Ant. – Seva Alekseyev Dec 17 '09 at 20:44

11 Answers11

17

You can set up 'final' fields and ifs to get the compiler to optimize the compiled byte-codes.

...
public static final boolean myFinalVar=false;
...
if (myFinalVar) { 
 do something ....
 ....
}

If 'myFinalVar' is false when the code is compiled the 'do something....' bit will be missed out of the compiled class. If you have more than one condition - this can be tidied up a bit: shift them all to another class (say 'Config.myFinalVar') and then the conditions can all be kept in one neat place.

This mechanism is described in 'Hardcore Java'.

[Actually I think this is the same mechanism as the "poor man's ifdef" posted earlier.]

Community
  • 1
  • 1
monojohnny
  • 5,894
  • 16
  • 59
  • 83
  • 1
    @Pacerier - thanks for the link - as per the critique I also found that the edition of the book I bought had several issues that needed to be corrected (some of the code examples for instance were 'out-of-order') - and I think it's good people should view the book critique - but I just want to point out to anyone reading this post that the specific mechanism described about 'conditional compilation' (as with a lot of the book in fact) is still sound. – monojohnny Jul 07 '14 at 09:36
6

you can manage different classpath, for example, implement each 'Action' in a set of distinct directories:

dir1/Main.java
dir2/Action.java
dir3/Action.java

then use a different classpath for each version

javac -sourcepath dir1 -cp dir2 dir1/Main.java

or

javac -sourcepath dir1 -cp dir3 dir1/Main.java
Pierre
  • 34,472
  • 31
  • 113
  • 192
  • But doesn't this mean that we need to maintain multiple copies of the source code? – Pacerier Jul 17 '14 at 21:24
  • no, only the conditional part. I wrote this 5 years ago. I would use a good' old 'if' statement now. – Pierre Jul 17 '14 at 23:54
  • Hm, but for this to work, the conditional part needs to be mixed in with the source code as well, so effectively we'd have two copies of the source code? – Pacerier Jul 18 '14 at 09:21
  • yes but you should only write *small* codes like `class Log { public void log(String s) { System.err.println(s);}}` and `class Log { public void log(String s) {}}` – Pierre Jul 18 '14 at 09:30
6

In JDK6, you can do it by using Java's ServiceLoader interface. Check it here.

Shamik
  • 6,938
  • 11
  • 55
  • 72
  • this is a nice feature which I'd never heard of until now. – Joel Dec 17 '09 at 18:30
  • 1
    this is really not so famous because of so much dominant players are present in the open source market. But I found this extremely useful considering the fact you do not want to use full blown IOC containers and just want to load different implementation of the same interface. – Shamik Dec 18 '09 at 04:45
  • 1
    This isn't going to work for him as his target is BlackBerry which is J2ME. – Jeremy Raymond Dec 18 '09 at 17:39
6

If you want this specifically for BlackBerry, the BlackBerry JDE has a pre-processor:

You can enable preprocessing for your applications by updating the Eclipse™ configuration file.

In C:\Program Files\Eclipse\configuration\config.ini, add the following line: osgi.framework.extensions=net.rim.eide.preprocessing.hook If you enable preprocessing after you have had a build, you must clean the project from the Project menu before you build the project again.

Then you can do things in the code like:

//#ifdef SOMETHING
// do something here
//#else
// do something else
//#endif

For details see Specifying preprocessor defines

Jeremy Raymond
  • 5,817
  • 3
  • 31
  • 33
4

Can one call that a poor mans ifdef: http://www.javapractices.com/topic/TopicAction.do?Id=64?

miku
  • 181,842
  • 47
  • 306
  • 310
3

No, Java doesn't have an exact match for that functionality. You could use aspects, or use an IOC container to inject different implementation classes.

Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276
1

You could use maven's resource filtering in combination mit public static final fields, which will be indeed get compiled conditionally.

private static final int MODE = ${mode};

...

if (MODE == ANDROID) {
    //android specific code here
} else {

}

Now you need to add a property to your maven pom called "mode", which should be of the same value as your ANDROID constant.

The java compiler should (!) remove the if and the else block, thus leaving your android code.

Not testet, so there is no guarantee and i would prefer configuration instead of conditional compilation.

whiskeysierra
  • 5,030
  • 1
  • 29
  • 40
1

You can integrate m4 into your build process to effectively strap an analogue to the C preprocessor in front of the Java compiler. Much hand-waving lies in the "integrate" step, but m4 is the right technology for the text processing job.

seh
  • 14,999
  • 2
  • 48
  • 58
  • 2
    Java has other answers to the same problems. If you have to fiddle with files for this kind of most common of problems you really are doing something wrong in the design. – extraneon Dec 17 '09 at 15:50
  • 1
    Note the OP's request: *[I]s there a way to introduce different configuration sets within the project and then compile slightly different code based on those?* To "compile slightly different code", one must feed different source code to the compiler. Yes, I've read about the static final boolean trick, but I don't think that's what the OP was after. – seh Dec 17 '09 at 15:56
1

Besides Maven, Ant and other build tools that provide similar functionality, one would rather build interfaces in Java and switch the implementations at Runtime.
See the Strategy Pattern for more details

In opposite to C/C++ this will not come with a big performance penality, as Javas JIT-compiler optimizes at runtime and is able to inline this patterns in most cases.
The big pro of this pattern is the flexibility - you can change the underlying Implementation without touching the core classes.

You should also check IoC and the Observer Pattern for more details.

Hardcoded
  • 6,476
  • 2
  • 22
  • 20
1

There are a couple of projects that bring support for comment-based conditional compilation to Java:

Example in JPSG:

/* with Android|Iphone platform */
class AndroidFoo {
  void bar() {
    /* if Android platform */
    doSomething();
    /* elif Iphone platform */
    doSomethingElse();
    /* endif */
  }
}
leventov
  • 14,760
  • 11
  • 69
  • 98
0

In eclipse you could use multiple projects

  • Main (contains common code)
  • Version1 (contains version1 code)
  • Version2 (contains version2 code)

    1. Main -> Select Project->Properties->Java Build Path->Projects tab
    2. Select Add...
    3. Add "Version1" xor "Version2" and OK back to the workspace.

Version1 and Version two contain the same files but different implementations. In Main you normally write e.g.

import org.mycustom.Version;

And if you included Version1/Version2 project as reference it will compile with the Version.java file from Version1/Version2 project.

jitter
  • 53,475
  • 11
  • 111
  • 124
  • But wouldn't you need to maintain multiple copies of the source code with only selected parts that differ? – Pacerier Jun 25 '14 at 03:03