【问题标题】:Is there any way to define a constant value to Java at compile time有没有办法在编译时为Java定义一个常量值
【发布时间】:2010-09-11 04:54:30
【问题描述】:

当我使用 C/C++ 编写库时,我养成了使用方法返回编译日期/时间的习惯。这始终是编译到库中的,因此会区分库的构建。我通过在代码中返回 #define 得到这个:

C++:

#ifdef _BuildDateTime_
   char* SomeClass::getBuildDateTime() {
      return _BuildDateTime_;
   }
#else
   char* SomeClass::getBuildDateTime() {
      return "Undefined";
   }
#endif

然后在编译时,我在构建脚本中有一个“-D_BuildDateTime_=Date”。

有没有什么方法可以在 Java 中实现这个或类似的,而不需要记住手动编辑任何文件或分发任何单独的文件。

我从一位同事那里得到的一个建议是让 ant 文件在类路径上创建一个文件,并将其打包到 JAR 中并由方法读取。

类似(假设创建的文件名为“DateTime.dat”):

// I know Exceptions and proper open/closing 
// of the file are not done. This is just 
// to explain the point!
String getBuildDateTime() {
    return new BufferedReader(getClass()
            .getResourceAsStream("DateTime.dat")).readLine();
}

在我看来,这是一个 hack,可能会被具有类似名称的文件的人绕过/破坏。在 JAR 之外,但在类路径上。

无论如何,我的问题是是否有办法在编译时将常量注入到类中

编辑

我认为在 JAR 中使用外部生成的文件是因为这个 )一个库并将嵌入到客户端应用程序中。这些客户端应用程序可能会定义自己的类加载器,这意味着我不能依赖标准的 JVM 类加载规则。

我个人的偏好是按照 serg10 的建议使用 JAR 文件中的日期。

【问题讨论】:

  • 在我看来,这是一个 hack,可能会被在 JAR 之外但在类路径上具有类似名称文件的人规避/破坏。 你在什么工作环境中编程你担心人们“规避”这个吗?让 Ant 生成文件根本不是 hack。当然,清单方法甚至更好的 Java 主义(你也可以让 Ant 自动化)。

标签: java c++ c


【解决方案1】:

我更喜欢基于标准的方法。 将您的版本信息(以及其他有用的发布者资料,如内部版本号、颠覆修订号、作者、公司详细信息等)放入 jar 的 @987654321 @。

这是一个有据可查且易于理解的 Java 规范。 强大的工具支持用于创建清单文件(例如 core Ant taskmaven jar plugin)。这些可以帮助自动设置一些属性 - 我已将 maven 配置为在构建时将 jar 的 maven 版本号、Subversion 修订版和时间戳放入清单中。

您可以在运行时使用标准 java api 调用读取清单的内容 - 类似于:

import java.util.jar.*;

...

JarFile myJar = new JarFile("nameOfJar.jar");    // various constructors available
Manifest manifest = myJar.getManifest();
Map<String,Attributes> manifestContents = manifest.getAttributes();

对我来说,这感觉像是一种更标准的 Java 方法,因此后续代码维护人员可能更容易遵循。

【讨论】:

    【解决方案2】:

    我记得在一个开源项目中看到过类似的东西:

    class Version... {
      public static String tstamp() {
        return "@BUILDTIME@";
      }
    }
    

    在模板文件中。使用 Ant 的过滤副本,您可以给这个宏一个值:

    <copy src="templatefile" dst="Version.java" filtering="true">
        <filter token="BUILDTIME" value="${build.tstamp}" />
    </copy>
    

    在编译步骤之前,使用它在构建过程中创建一个 Version.java 源文件。

    【讨论】:

      【解决方案3】:

      AFAIK 没有办法用 javac 做到这一点。这可以使用 Ant 轻松完成——我将创建一个名为 BuildTimestamp.java 的第一类对象,并在编译时通过 Ant 目标生成该文件。

      Here's an Ant type 这会很有帮助。

      【讨论】:

        【解决方案4】:

        除非您想通过 C/C++ 预处理器运行您的 Java 源代码(这是一个很大的禁忌),否则请使用 jar 方法。还有其他方法可以从 jar 中获取正确的资源,以确保没有人在类路径上放置重复的资源。您也可以考虑为此使用 Jar 清单。我的项目使用清单完全符合您的要求(包括构建日期、修订版本、作者等)。

        你会想用这个:

        Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources("META-INF/MANIFEST.MF");
        

        这将为您提供类路径上的所有清单。您可以通过解析 URL 来确定它们可以来自哪个 jar。

        【讨论】:

          【解决方案5】:

          我个人会在你的 jar 中找到一个单独的属性文件,你会在运行时加载它......类加载器有一个定义的文件搜索顺序 - 我不记得它是如何工作的,但是我不认为类路径中某个位置的另一个同名文件可能会导致问题。

          但另一种方法是在编译之前使用 Ant 将 .java 文件复制到不同的目录中,并在适当的情况下过滤字符串常量。你可以使用类似的东西:

          public String getBuildDateTime() {
              return "@BUILD_DATE_TIME@";
          }
          

          并在您的 Ant 文件中编写一个过滤器以将其替换为构建属性。

          【讨论】:

            【解决方案6】:

            manifest documentation 中所述,也许一种更Java 风格的方式来指示您的库的版本是在JAR 的清单中添加一个版本号。

            【讨论】:

              【解决方案7】:

              我从同事那里得到的一个建议 是让ant文件创建一个 类路径上的文件并打包 将其放入 JAR 并由其读取 方法。 ...在我看来,这是一个 hack并且可以被规避/破坏 由同名的人 文件在 JAR 之外,但在 类路径。

              我不确定让 Ant 生成文件是否是一个非常令人震惊的 hack,如果它完全是一个 hack。为什么不生成一个属性文件并使用java.util.Properties 来处理呢?

              【讨论】:

                猜你喜欢
                • 2014-02-10
                • 2016-07-09
                • 1970-01-01
                • 2014-01-26
                • 2012-10-30
                • 2011-01-15
                • 1970-01-01
                • 2018-11-26
                相关资源
                最近更新 更多