11

I know there are no macros in Java, but is there a workaround to do something like this:

#ifdef _FOO_FLAG_
import com.x.y.z.Foo;
#else
import com.a.b.c.Foo;
#endif

Both Foo classes have the same methods. One of them is from a 3rd party library. I want to be able to switch to default library easily by changing a single line of code. Is this possible?

EDIT:
Both classes are out of my control(one of them is from SQLCipher for Android project, other one is from Android SDK). I need this because SQLCipher library doesn't work on SAMSUNG phones at the moment.

Caner
  • 57,267
  • 35
  • 174
  • 180
  • run it all through a preprocessor as part of the build (and see the hate come in) – ratchet freak Oct 27 '11 at 10:49
  • 1
    May I ask why you need this? There could be other ways, but certainly Java deliberately doesn't want you to do this. Your only option would be going outside it and generating the .java file (with Ant for example). – Vala Oct 27 '11 at 10:51
  • 1
    This is the kind of stuff that Spring is supposed to do, isn't it? DI and IoC and all that. –  Oct 27 '11 at 10:54
  • @bdares: among others. But Spring can only help here if both `Foo` implement a common interface or have a common base class with all the necessary methods exposed. – Joachim Sauer Oct 27 '11 at 10:55
  • 1
    James Gosling explaining absence of preprocessor in Java 15 years ago: http://java.sun.com/docs/white/langenv/Simple.doc2.html#4078. IIRC elsewhere he wrote Java does not have its own because it has a simple grammar and a tool can be written easily. – Miserable Variable Oct 27 '11 at 11:24
  • I just got the C preprocessor working with Eclipse http://stackoverflow.com/a/10497206/1137626 – Josh S May 08 '12 at 11:20
  • http://stackoverflow.com/questions/4526113/java-conditional-compilation-how-to-prevent-code-chunks-from-being-compiled – Ciro Santilli OurBigBook.com Jul 11 '15 at 10:48
  • 1) http://manifold.systems/ https://github.com/manifold-systems/manifold 2) https://spoon.gforge.inria.fr/ https://github.com/INRIA/spoon – Dmytro Mitin Oct 22 '22 at 02:01

4 Answers4

20

No, there is no commonly used pre-processor in Java (although you could use the C preprocessor on your Java code, but I'd discourage it, as it would be very unusual and would break most tools that handle your code). Such selections are usually done at runtime rather than compile-time in Java.

The usual Java-way for this is to have both classes implement the same interface and refer to them via the interface only:

IFoo myFoo;
if (FOO_FLAG) { // possibly a public static final boolean
  myFoo = new com.x.y.z.Foo();
} else {
  myFoo = new com.a.b.c.Foo();
}

If this is not possible (for example if at least one of the Foo classes is not under your control), then you can achieve the same effect by an abstract FooWrapper class (or interface) with two different implementations (XYZFooWrapper, ABCFooWrapper).

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
3

The way this sort of thing is typically handled in Java is with a dependency injection framework such as Spring or Guice. In Spring, for example, you'd have two different "application contexts" to switch between the two implementations, but the rest of the Java code would be identical.

The only catch is that your com.a.b.c.Foo and com.x.y.z.Foo do need to implement a common interface -- it's not good enough for them to simply have the same methods, even with a nice dependency injection framework.

mergeconflict
  • 8,156
  • 34
  • 63
  • 1
    -1 This doesn't solve the problem, given that the "catch" makes it unusable for the OP's purpose. I also disagree with solving a problem like this by introducing a whole framework. A wrapper class works nicely. – Erick Robertson Oct 27 '11 at 12:52
  • A wrapper class is a very ineffective workaround for conditional compilation: https://en.wikipedia.org/wiki/Conditional_compilation. It works nicely in only a limited number of cases, in other cases it is either not practical or too complicated. – Alex Oct 26 '16 at 00:57
0

My answer linking to how to use the C-preprocessor was converted to a comment by someone who seemed to miss the fact that using that would precisely allow you write:

#ifdef _FOO_FLAG_
import com.x.y.z.Foo;
#else
import com.a.b.c.Foo;
#endif

Look for the hidden comment under the question.

Anyway since all you need is versioning, here's a simpler to use preprocessor that should work with the android setup: http://prebop.sourceforge.net/

If what you really want is two builds, then wrapping classes or writing code to choose at run time is a waste of effort and unnecessary complexity.

Josh S
  • 147
  • 1
  • 7
0

You can also detect the presence of certain classes at runtime using Class.forName(). This allows you to deploy the same build to different environments/devices.

JimmyB
  • 12,101
  • 2
  • 28
  • 44