Java条件编译:如何防止代码块被编译?

发布于 2024-10-09 16:39:38 字数 1172 浏览 6 评论 0原文

我的项目需要Java 1.6来编译和运行。现在我需要让它与 Java 1.5 一起工作(来自营销方面)。我想替换方法体(返回类型和参数保持不变)以使其使用 Java 1.5 进行编译而不会出现错误。

详细信息:我有一个名为OS的实用程序类,它封装了所有特定于操作系统的内容。它有一种打开文件的方法

public static void openFile(java.io.File file) throws java.io.IOException {
  // open the file using java.awt.Desktop
  ...
}

,例如双击(start Windows 命令或 open Mac OS X 命令等效项)。由于它无法使用 Java 1.5 进行编译,因此我想在编译过程中排除它,并替换为另一种方法,该方法使用 调用 Windows 的 run32dll 或 Mac OS X 的 open运行时.exec

问题:我该怎么做?注释可以在这里提供帮助吗?

注意:我使用 ant,我可以制作两个 java 文件 OS4J5.javaOS4J6.java,其中将包含 OS 类,其中包含 Java 1.5 和 1.6 所需的代码,并在编译之前将其中一个复制到 OS.java (或一种丑陋的方式 - 替换 OS.java< 的内容) /code> 有条件地取决于java版本)但我不想这样做,如果有其他方法的话。

详细说明:在 CI 中可以使用 ifdef, ifndef,在 Python 中没有编译,我可以使用 hasattr 或其他东西检查功能,在 Common Lisp 中我可以使用 <代码>#+功能。 Java 有类似的东西吗?

找到这篇文章,但它似乎没有帮助。

非常感谢任何帮助。 kh.

My project requires Java 1.6 for compilation and running. Now I have a requirement to make it working with Java 1.5 (from the marketing side). I want to replace method body (return type and arguments remain the same) to make it compiling with Java 1.5 without errors.

Details: I have an utility class called OS which encapsulates all OS-specific things. It has a method

public static void openFile(java.io.File file) throws java.io.IOException {
  // open the file using java.awt.Desktop
  ...
}

to open files like with double-click (start Windows command or open Mac OS X command equivalent). Since it cannot be compiled with Java 1.5, I want to exclude it during compilation and replace by another method which calls run32dll for Windows or open for Mac OS X using Runtime.exec.

Question: How can I do that? Can annotations help here?

Note: I use ant, and I can make two java files OS4J5.java and OS4J6.java which will contain the OS class with the desired code for Java 1.5 and 1.6 and copy one of them to OS.java before compiling (or an ugly way - replace the content of OS.java conditionally depending on java version) but I don't want to do that, if there is another way.

Elaborating more: in C I could use ifdef, ifndef, in Python there is no compilation and I could check a feature using hasattr or something else, in Common Lisp I could use #+feature. Is there something similar for Java?

Found this post but it doesn't seem to be helpful.

Any help is greatly appreciated. kh.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

硪扪都還晓 2024-10-16 16:39:38

不,Java 中不支持条件编译。

通常的计划是将应用程序的操作系统特定位隐藏在Interface后面,然后在运行时检测操作系统类型并使用Class.forName(String)加载实现。

在您的情况下,没有理由不能使用 Java 1.6 和 -source 1.5 -target 1.5 编译两个 OS* (实际上是您的整个应用程序),然后在用于获取 OS 类(现在将是一个接口)的工厂方法检测到 java.awt.Desktop
类可用并加载正确的版本。

像这样的东西:

 public interface OS {
     void openFile(java.io.File file) throws java.io.IOException;
 }

 public class OSFactory {
     public static OS create(){
         try{
             Class.forName("java.awt.Desktop");
             return new OSJ6();
         }catch(Exception e){
             //fall back
             return new OSJ5();
         }
     }
 }

Nope there isn't any support for conditional compilation in Java.

The usual plan is to hide the OS specific bits of your app behind an Interface and then detect the OS type at runtime and load the implementation using Class.forName(String).

In your case there no reason why you can't compile the both OS* (and infact your whole app) using Java 1.6 with -source 1.5 -target 1.5 then in a the factory method for getting hold of OS classes (which would now be an interface) detect that java.awt.Desktop
class is available and load the correct version.

Something like:

 public interface OS {
     void openFile(java.io.File file) throws java.io.IOException;
 }

 public class OSFactory {
     public static OS create(){
         try{
             Class.forName("java.awt.Desktop");
             return new OSJ6();
         }catch(Exception e){
             //fall back
             return new OSJ5();
         }
     }
 }
沫离伤花 2024-10-16 16:39:38

像 Gareth 提议的那样,将两个实现类隐藏在一个接口后面可能是最好的方法。

也就是说,您可以使用 ant 构建脚本中的替换任务引入一种条件编译。诀窍是在代码中使用注释,这些注释在编译源代码之前通过文本替换打开/关闭,例如:

/*{{ Block visible when compiling for Java 6: IFDEF6

public static void openFile(java.io.File file) throws java.io.IOException {
  // open the file using java.awt.Desktop
  ...

/*}} end of Java 6 code. */

/*{{ Block visible when compiling for Java 5: IFDEF5

  // open the file using alternative methods
  ...

/*}} end of Java 5 code. */

现在在 ant 中,当您编译 Java 6 时,将“IFDEF6”替换为“*/”,给出

/*{{ Block visible when compiling for Java 6: */

public static void openFile(java.io.File file) throws java.io.IOException {
  // open the file using java.awt.Desktop
  ...

/*}} end of Java 6 code. */

/*{{ Block visible when compiling for Java 5, IFDEF5

public static void openFile(java.io.File file) throws java.io.IOException {
  // open the file using alternative methods
  ...

/*}} end of Java 5 code. */

:针对 Java 5 进行编译时,替换“IFDEF5”。请注意,在 /*{{/*}} 块内使用 // comments 时需要小心。

Hiding two implementation classes behind an interface like Gareth proposed is probably the best way to go.

That said, you can introduce a kind of conditional compilation using the replace task in ant build scripts. The trick is to use comments in your code which are opened/closed by a textual replacement just before compiling the source, like:

/*{{ Block visible when compiling for Java 6: IFDEF6

public static void openFile(java.io.File file) throws java.io.IOException {
  // open the file using java.awt.Desktop
  ...

/*}} end of Java 6 code. */

/*{{ Block visible when compiling for Java 5: IFDEF5

  // open the file using alternative methods
  ...

/*}} end of Java 5 code. */

now in ant, when you compile for Java 6, replace "IFDEF6" with "*/", giving:

/*{{ Block visible when compiling for Java 6: */

public static void openFile(java.io.File file) throws java.io.IOException {
  // open the file using java.awt.Desktop
  ...

/*}} end of Java 6 code. */

/*{{ Block visible when compiling for Java 5, IFDEF5

public static void openFile(java.io.File file) throws java.io.IOException {
  // open the file using alternative methods
  ...

/*}} end of Java 5 code. */

and when compiling for Java 5, replace "IFDEF5". Note that you need to be careful to use // comments inside the /*{{, /*}} blocks.

清秋悲枫 2024-10-16 16:39:38

您可以使用反射进行调用并使用 Java 5 编译代码。

例如,

Class clazz = Class.forName("java.package.ClassNotFoundInJavav5");
Method method = clazz.getMethod("methodNotFoundInJava5", Class1.class);
method.invoke(args1);

您可以捕获任何异常并回退到可在 Java 5 上运行的内容。

You can make the calls using reflection and compile the code with Java 5.

e.g.

Class clazz = Class.forName("java.package.ClassNotFoundInJavav5");
Method method = clazz.getMethod("methodNotFoundInJava5", Class1.class);
method.invoke(args1);

You can catch any exceptions and fall back to something which works on Java 5.

心碎无痕… 2024-10-16 16:39:38

下面介绍的 Ant 脚本提供了漂亮而干净的技巧。

链接: https://weblogs.java.net/blog/schaefa /archive/2005/01/how_to_do_condi.html

例如

//[ifdef]
public byte[] getBytes(String parameterName)
        throws SQLException {
    ...
}
//[enddef]

,使用 Ant 脚本

        <filterset begintoken="//[" endtoken="]">
            <filter token="ifdef" value="${ifdef.token}"/>
            <filter token="enddef" value="${enddef.token}"/>
        </filterset>

请访问上面的链接了解更多详细信息。

The Ant script introduced below gives nice and clean trick.

link: https://weblogs.java.net/blog/schaefa/archive/2005/01/how_to_do_condi.html

in example,

//[ifdef]
public byte[] getBytes(String parameterName)
        throws SQLException {
    ...
}
//[enddef]

with Ant script

        <filterset begintoken="//[" endtoken="]">
            <filter token="ifdef" value="${ifdef.token}"/>
            <filter token="enddef" value="${enddef.token}"/>
        </filterset>

please go to link above for more detail.

时光与爱终年不遇 2024-10-16 16:39:38

java 9 中,可以创建多版本 jar 文件。本质上,这意味着您创建同一个 java 文件的多个版本。

当你编译它们时,你用所需的jdk版本编译java文件的每个版本。接下来,您需要将它们打包成如下所示的结构:

+ com
  + mypackage
    + Main.class
    + Utils.class
+ META-INF
  + versions
    + 9
      + com
        + mypackage
          + Utils.class

在上面的示例中,代码的主要部分是在 java 8 中编译的,但对于 java 9,还有一个附加(但不同)版本的 Utils类。

当您在 java 8 JVM 上运行此代码时,它甚至不会检查 META-INF 文件夹中的类。但在 java 9 中它将查找并使用该类的更新版本。

In java 9 it's possible to create multi-release jar files. Essentially it means that you make multiple versions of the same java file.

When you compile them, you compile each version of the java file with the required jdk version. Next you need to pack them in a structure that looks like this:

+ com
  + mypackage
    + Main.class
    + Utils.class
+ META-INF
  + versions
    + 9
      + com
        + mypackage
          + Utils.class

In the example above, the main part of the code is compiled in java 8, but for java 9 there is an additional (but different) version of the Utils class.

When you run this code on the java 8 JVM it won't even check for classes in the META-INF folder. But in java 9 it will, and will find and use the more recent version of the class.

土豪我们做朋友吧 2024-10-16 16:39:38

如果您不想在应用程序中条件启用代码块,那么预处理器是唯一的方法,您可以查看 java-comment-preprocessor 可用于 maven 和 ant 项目
附:
我还制作了 一些示例如何使用 Maven 进行预处理来构建 JEP-238 多版本没有重复源的 JAR

if you don't want conditionally enabled code blocks in your application then a preprocessor is only way, you could take a look at java-comment-preprocessor which can be used for both maven and ant projects
p.s.
also I have made some example how to use preprocessing with Maven to build JEP-238 multi-version JAR without duplication of sources

蓝眼泪 2024-10-16 16:39:38

我不是一个很好的 Java 专家,但似乎 Java 中支持条件编译并且很容易做到。请阅读:

http://www.javapractices.com/topic/TopicAction.do? Id=64

引用要点:

条件编译实践用于有选择地从类的编译版本中删除代码块。它利用了这样一个事实:编译器将忽略任何无法访问的代码分支。
要实现条件编译,

  • 将静态最终布尔值定义为某个类的非私有成员
  • 将要条件编译的代码放置在计算布尔值的 if 块中
  • 将布尔值设置为 false 以使编译器忽略 if 块;否则,保持其值为 true

当然,这使我们可以在任何方法内“编译出”代码块。要删除类成员、方法甚至整个类(可能只留下一个存根),您仍然需要一个预处理器。

I'm not such a great Java expert, but it seems that conditional compilation in Java is supported and easy to do. Please read:

http://www.javapractices.com/topic/TopicAction.do?Id=64

Quoting the gist:

The conditional compilation practice is used to optionally remove chunks of code from the compiled version of a class. It uses the fact that compilers will ignore any unreachable branches of code.
To implement conditional compilation,

  • define a static final boolean value as a non-private member of some class
  • place code which is to be conditionally compiled in an if block which evaluates the boolean
  • set the value of the boolean to false to cause the compiler to ignore the if block; otherwise, keep its value as true

Of course this lets us to "compile out" chunks of code inside any method. To remove class members, methods or even entire classes (maybe leaving only a stub) you would still need a pre-processor.

柏拉图鍀咏恒 2024-10-16 16:39:38

Java Primitive Specializations Generator 支持条件编译:

   /* if Windows compilingFor */
   start();
   /* elif Mac compilingFor */
   open();
   /* endif */

该工具有 Maven 和 Gradle 插件。

Java Primitive Specializations Generator supports conditional compilation:

   /* if Windows compilingFor */
   start();
   /* elif Mac compilingFor */
   open();
   /* endif */

This tool has Maven and Gradle plugins.

朦胧时间 2024-10-16 16:39:38

嗨,当我在 Java SDK 和 Android 之间共享库并且在两种环境中都使用图形时,我遇到了类似的问题,所以基本上我的代码必须同时使用这两种环境
java.awt.Graphics 和 android.graphics.Canvas,
但我不想重复几乎任何代码。
我的解决方案是使用包装器,因此我间接访问 graphisc API,并且
我可以更改一些导入,以导入我想要编译项目的包装器。
这些项目有一些圆锥体阴影,有些是独立的,但除了几个包装纸等之外没有任何重复的东西。
我认为这是我能做的最好的事情。

hi I have got similar problem when I have shared library between Java SDK abd Android and in both environments are used the graphics so basically my code must to work with both
java.awt.Graphics and android.graphics.Canvas,
but I don't want to duplicate almost any code.
My solution is to use wrapper, so I access to graphisc API indirectl way, and
I can change a couple of imports, to import the wrapper I want to compile the projects.
The projects have some cone shaded and some are separate, but there is no duplicating anything except of couple of wrappers etc.
I think it is the best what I can do.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文