代码之家  ›  专栏  ›  技术社区  ›  GKelly

有什么方法可以在编译时为Java定义一个常量值吗

  •  13
  • GKelly  · 技术社区  · 16 年前

    当我过去用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 回复  |  直到 8 年前
        1
  •  16
  •   martin clayton egrunin    14 年前

    我赞成基于标准的方法。 将您的版本信息(以及其他有用的发布者信息,如内部版本号、颠覆版本号、作者、公司详细信息等)放在jar中 Manifest File .

    这是一个记录良好且易于理解的Java规范。 存在强大的工具支持来创建清单文件(a core Ant task 例如,或者 maven jar plugin ).这些可以帮助自动设置一些属性——我已经将maven配置为在构建时将jar的maven版本号、Subversion修订版和时间戳放入清单中。

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

    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
  •  11
  •   Karl    16 年前

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

    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
  •  2
  •   martin clayton egrunin    14 年前

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

    Here's an Ant type 这将是有益的。

        4
  •  1
  •   basszero    16 年前

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

    你会想用这个:

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

    这将为您获取类路径上的所有清单。通过解析URL,您可以找出它们可以来自哪个jar。

        5
  •  1
  •   MB.    16 年前

    就我个人而言,我会在jar中选择一个单独的属性文件,在运行时加载。..类加载器有一个定义好的搜索文件的顺序——我暂时不记得它是如何工作的,但我认为类路径上某处同名的另一个文件不太可能引起问题。

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

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

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

        6
  •  1
  •   Peter Hilton    16 年前

    也许一种更Java风格的指示库版本的方法是将版本号添加到JAR的清单中,如 manifest documentation .

        7
  •  0
  •   Paul A. Hoadley    16 年前

    我从同事那里得到的一个建议 就是获取ant文件来创建一个 类路径上的文件和打包 将其放入JAR中,并由其读取 方法。 ...在我看来,这是一个 黑客攻击,可以绕过/破解 由名字相似的人 文件在JAR之外,但在 类路径。

    我不确定让Ant生成文件是否是一个极其恶劣的黑客行为,如果真的是黑客行为的话。为什么不生成一个属性文件并使用 java.util.Properties 处理它?