有没有办法在编译时为Java定义一个常量值

时间:2008-09-19 11:50:35

标签: java c++ c

当我以前用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();
}

在我看来,这是一个黑客攻击,并且可以被一个在JAR之外具有类似命名的文件但在类路径上的人绕开/打破。

无论如何,我的问题是在编译时是否有任何方法将一个常量注入一个类

修改

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

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

7 个答案:

答案 0 :(得分:15)

我赞成基于标准的方法。将您的版本信息(以及其他有用的发布商内容,例如内部版本号,颠覆版本号,作者,公司详细信息等)放入jar {{ 3}}。

这是一份记录良好且易于理解的Java规范。存在用于创建清单文件的强大工具支持(例如Manifest Filecore Ant task)。这些可以帮助自动设置一些属性 - 我已经配置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标准的方法,因此后续代码维护者可能会更容易理解。

答案 1 :(得分:11)

我记得在开源项目中看到过类似内容:

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源文件。

答案 2 :(得分:2)

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

Here's an Ant type会有所帮助。

答案 3 :(得分:1)

除非您想通过C / C ++预处理器(这是一个很大的NO-NO)运行Java源代码,否则请使用jar方法。还有其他方法可以从jar中获取正确的资源,以确保有人没有在类路径上放置重复的资源。你也可以考虑使用Jar清单。我的项目使用清单完成您正在尝试做的事情(使用构建日期,修订版,作者等)。

你想要使用它:

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

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

答案 4 :(得分:1)

就个人而言,我会在你的jar中找到一个你在运行时加载的单独的属性文件...类加载器有一个定义的搜索文件的顺序 - 我不记得它是如何完全在手边,但是我不认为类路径上某处具有相同名称的另一个文件可能会导致问题。

但另一种方法是在编译之前使用Ant将.java文件复制到另一个目录中,并根据需要过滤String常量。你可以使用类似的东西:

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

并在Ant文件中编写一个过滤器,用构建属性替换它。

答案 5 :(得分:1)

如果manifest documentation中所述,或许更符合Java风格的方式来指示您的库的版本将是向JAR的清单添加版本号。

答案 6 :(得分:0)

  

我从一位同事那里得到的一个建议   是得到ant文件来创建一个   文件在类路径和包   进入JAR并让它读取   方法。 ......在我看来,这是一个   黑客,可以被规避/破坏   由具有类似名称的人   文件在JAR之外,但在   类路径。

我不确定让Ant生成一个文件是一个非常令人震惊的黑客,如果它是一个黑客攻击。为什么不生成属性文件并使用java.util.Properties来处理它?<​​/ p>