1

I want to make a code that works for Java 1.8 and 1.7. Specifically, I want to implement a static method in the interface. This is allowed in java 8 but not in 7. I read there is a way pipe C macros, also that this is not good practice. Additionally, piping the macros do not tell me which SDK is being use?

So there is any "good" solution to this?

UPDATE:

Please do not suggest implement an abstract class. Thanks.

NO DUPLICATE

Can Java 8 code be compiled to run on Java 7 jvm? asks if there is a way by command line to compile the code of java 1.8 in 1.7. At least the answer looks so. The question I do, it is if there is a way to indicate in the code which parts are from the code belongs to 1.8 and what to 1.7.

Community
  • 1
  • 1
ender.an27
  • 703
  • 1
  • 13
  • 35
  • 1
    If you are coding anything serious, then the only answer would be "don't ever do that, write and live with 1.7 code". If you decide to do it anyway then only dirty hacks are possible, but they will all include horrible scripts that cuts and moves code around. – McMonster Nov 17 '15 at 14:47
  • What @McMonster said. _Any_ attempt to do something like this will be much more difficult to pain and cause more tearing your hair out than just sucking it up and dealing with Java 1.7. – Louis Wasserman Nov 17 '15 at 18:15
  • 2
    What are you trying to achieve? If the code contains parts that need Java 8, it won’t run under Java 7 anyway, *especially* when it contains a `static` method in an `interface`, so what’s the point of marking other parts of it “belonging to Java 7”? – Holger Nov 17 '15 at 18:56
  • @Holger: Just try to write a JDBC driver which can be used in any version of Java from 5 to 8. Since the interface changes all the time, you need some form of conditional programming. In his case, my guess is that he wants to offer a library which can be used in 7 and 8 with some additional features on 8 without having to keep two code bases. – Aaron Digulla Nov 20 '15 at 09:58
  • @Aaron Digulla: you can’t do conditional programming when the condition checks need to refer to the features that are absent in certain versions. Then, they will fail with linkage errors instead of evaluating to `false`. But it’s no problem to create a base implementation compatible to version `x` and a subclassing version supporting newer version `y`. Since this requires a clean separation between the base classes and the specialized ones, there’s still no need to *mark parts of the code*. Just having two source folders or repositories is sufficient. – Holger Nov 20 '15 at 10:10
  • 1
    @Holger: I think we're having different priorities here. My goal is to reduce code duplication to reduce maintenance cost. You goal seems to be purity. I agree that it's not possible to solve cleanly but that doesn't mean the requirement is invalid as such. – Aaron Digulla Nov 20 '15 at 10:53
  • I agree with @AaronDigulla. Duplicating source code is the same as having two implementations which is just harder to maintain. Of course doing macros like code is harder to read. It is a trade off between both – ender.an27 Nov 20 '15 at 11:07
  • @Aaron Digulla: I don’t see how creating a common base class and a specific subclass, holding the code related to the newer API only, creates code duplication. Creating such a clean design implies *avoiding* code duplication. If you are talking about the necessity of putting a `class X { … }` around the specialization, that’s not really code duplication, just the known verbosity of the Java language which is acceptable, compared to the disadvantages of a preprocessor based solution. – Holger Nov 20 '15 at 11:23
  • @ender.an27: at no point, anyone here suggested creating code duplication. – Holger Nov 20 '15 at 11:23
  • @Holger: Your approach fails in this case: https://stackoverflow.com/questions/1069544/create-a-wrapper-for-java-sql-connection-that-works-with-jdbc-3-and-4 – Aaron Digulla Nov 20 '15 at 11:57
  • @Aaron Digulla: I don’t see why it should fail. What I described, is like a lot of JDBC drivers are actually implemented. But your question is unclear anyway. Are you *using* JDBC or *implementing* a JDBC driver there? – Holger Nov 20 '15 at 12:05
  • @Holger: I'm using JDBC but the only solution I found is conditional compilation. – Aaron Digulla Nov 20 '15 at 15:21
  • @AaronDigulla - I'm surprised that nobody has suggested "bytecode engineering". Not that it is a good (or even better) solution (IMO) ... but some folks think it is the solution to everything :-). – Stephen C Nov 23 '15 at 02:50
  • @Aaron Digulla: I never encountered such problems on the use site. With Sun/Oracle’s JVM interface methods absent in the driver never were a problem unless you actually try to invoke them. So only conditional code at runtime is required, but no conditional compiling. But as said, using OOP instead of conditionals makes it even safe for arbitrary JVMs. – Holger Nov 23 '15 at 09:57
  • @Holger: Compilation will fail on Java 5 if you use `@Override` for JDBC 4 methods, as a simple example. – Aaron Digulla Nov 23 '15 at 12:08
  • @Aaron Digulla: that’s why I asked whether you are *using* JDBC or *implementing* a JDBC driver. You said you *use* it, so it’s unclear, why you should ever override a JDBC method. Only the *implementing* driver does. And there is no reason to compile a driver against an older version of an interface. Besides that, using `@Override` for *interface methods* works with Java 6 or newer only (at least when using a compiler conforming to the standard)… – Holger Nov 23 '15 at 14:37

1 Answers1

2

There is no clean Java way to do this. There are several ways (which you can also combine) to implement this. The core of the solution is a small code generator which can generate the code that you need. You have to configure your build system to invoke the generator before javac is called.

  1. Put the code into different files (header, footer, Java 8 code) and create the final Java class in a prepare step of your build system (just concatenate the parts which you need). For Maven, that would be generate-sources. For Ant, use a set of targets.
  2. Put the code into the same file and use magic comments to specify where the code starts and ends. The code itself is commented out with line comments in the first column:

    /*!!!JAVA8-START!!!*/
    //...Java 8 code...
    /*!!!JAVA8-END!!!*/
    

    If your build system detects Java 8, it can search for lines which begin with // between the two comments and remove the //.

  3. If you use Maven, you can have three modules. A common module which contains the non-Java 7/8 specific code. One module for Java 7 and one for Java 8. Enable the specific modules with a build profile. Use a unit test to make sure that the code in the Java 7 and 8 modules is the same (for example by removing the Java 8 specific parts and comparing the rest to Java 7).
Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • Do you have examples links of this? not sure if 1,2,3 are independent options or steps. But, thanks, your answer looks promising! – ender.an27 Nov 17 '15 at 14:25
  • Have a look at open source JDBC drivers. They often have the problem. But the core is that you need to write a simple code generator which you need to call from your build system before the Java compiler is invoked. – Aaron Digulla Nov 17 '15 at 14:29
  • I read them as alternative approaches. One could even, probably, use the C Preprocessor. Then you would use `#ifdef` to define sections, and you would need to run `cpp` manually before running `javac`. This would probably make coding difficult since IDEs and editors won't expect these directives in the middle of the code. – dsh Nov 17 '15 at 14:30
  • @dsh you also forgot to mention how to find out that you are in javac 1.8 or 1.7, which is part of the question. – ender.an27 Nov 17 '15 at 14:34
  • @AaronDigulla your answer it look good, but is more like a hint for an answer. I have to research it before I can be sure it works or not. – ender.an27 Nov 17 '15 at 14:36
  • @ender.an27 You have to tell the build system which to use. So it would then tell cpp to define the appropriate token (just like any other use of cpp). Eg [`cpp -D JAVA_8 -o Foo.java Foo.java.in`](https://gcc.gnu.org/onlinedocs/cpp/Invocation.html#Invocation) – dsh Nov 17 '15 at 15:02
  • @dsh thanks, but this solution is quite dirty, therefore consider bad practice. – ender.an27 Nov 17 '15 at 15:05
  • @ender.an27 Sure, I don't disagree. I would generally classify any attempt at conditional compilation as "bad practice" since it is not normal and not natively supported by the java toolchain (IDEs, javac, etc) – dsh Nov 19 '15 at 21:04
  • 1
    @ender.an27: This site isn't providing canned answers. We always only give hints unless we have code lying around which solves the problem (and we can share it). I figure it would take several hours to come up with a complete example. I suggest you decide which way to go, which build system to use and then ask more specific questions. – Aaron Digulla Nov 20 '15 at 09:56