上次编译的Java打印时间

我想嵌入一段代码,打印出当前类最后编译的时间。 如何在Java中实现?

在java中没有直接的支持,因为没有预处理器。 最接近的等价物是JAR清单中的“Build-Date”属性。 许多构建系统默认添加此属性,或提供添加它的方法。

然后,您可以在运行时读取JAR的清单以获取日期。 这个SO问题的答案描述了如何从JAR清单中读取值。

另一种方法是使用资源过滤将日期添加到属性文件中,然后在运行时读取。 这是非常特殊的,非标准的,如果你有很多jar子,编译时间不同,那么这很快就会变得难以管理,除非你可以把它归结为所有jar子的构建方式。

很久以前这个问题已得到解答。 但是如果有人在这里摆动一个适合我的解决方案,类似于Supah Fly所建议但支持jar和文件。

private long classBuildTimeMillis() throws URISyntaxException, IllegalStateException, IllegalArgumentException { URL resource = getClass().getResource(getClass().getSimpleName() + ".class"); if (resource == null) { throw new IllegalStateException("Failed to find class file for class: " + getClass().getName()); } if (resource.getProtocol().equals("file")) { return new File(resource.toURI()).lastModified(); } else if (resource.getProtocol().equals("jar")) { String path = resource.getPath(); return new File(path.substring(5, path.indexOf("!"))).lastModified(); } else { throw new IllegalArgumentException("Unhandled url protocol: " + resource.getProtocol() + " for class: " + getClass().getName() + " resource: " + resource.toString()); } } 

但这不会处理zip文件或静态上下文,它会抛出exception,而不是在事情发生时返回null。 这有点友好:

 private static final Date buildDate = getClassBuildTime(); /** * Handles files, jar entries, and deployed jar entries in a zip file (EAR). * @return The date if it can be determined, or null if not. */ private static Date getClassBuildTime() { Date d = null; Class currentClass = new Object() {}.getClass().getEnclosingClass(); URL resource = currentClass.getResource(currentClass.getSimpleName() + ".class"); if (resource != null) { if (resource.getProtocol().equals("file")) { try { d = new Date(new File(resource.toURI()).lastModified()); } catch (URISyntaxException ignored) { } } else if (resource.getProtocol().equals("jar")) { String path = resource.getPath(); d = new Date( new File(path.substring(5, path.indexOf("!"))).lastModified() ); } else if (resource.getProtocol().equals("zip")) { String path = resource.getPath(); File jarFileOnDisk = new File(path.substring(0, path.indexOf("!"))); //long jfodLastModifiedLong = jarFileOnDisk.lastModified (); //Date jfodLasModifiedDate = new Date(jfodLastModifiedLong); try(JarFile jf = new JarFile (jarFileOnDisk)) { ZipEntry ze = jf.getEntry (path.substring(path.indexOf("!") + 2));//Skip the ! and the / long zeTimeLong = ze.getTime (); Date zeTimeDate = new Date(zeTimeLong); d = zeTimeDate; } catch (IOException|RuntimeException ignored) { } } } return d; } 

由于这一点从未被提及过,任何想要通过任何必要手段解决这个问题的人都可能会发现这是一个合适而又笨拙的解决方案:

 new Date(new File(getClass().getClassLoader().getResource(getClass().getCanonicalName().replace('.', '/') + ".class").toURI()).lastModified())) 

它可能不太漂亮,而且很可能在其他平台上不兼容,但这是我发现在本机Java中找出当前类的编译日期的唯一方法。

它有点笨重,但你可以用Ant过滤来做到这一点。

在您的class级中弹出以下方法:

 public static String timeBuilt(){ return "Built at @timeBuilt@ on @dateBuilt@"; } 

然后将以下内容放入Ant构建文件中。

              

这会将“src”目录中的所有内容复制到“build”,这样做会分别将@ timeBuilt @和@ dateBuilt @替换为构建的时间和日期。 只需使您的构建目标依赖于copy-files并从“build”目录构建 – 而不是“src”目录。

替换静态方法的内容的优点是,它将在每个类的基础上运行 – 如果您要获取生成的类文件并将它们与在另一个时间构建的其他类文件组合,他们每个人都知道什么时候建成 属性文件是明智的,但除非你有多个属性文件,否则你只能拥有整个包的构建时间。

创建一个shell脚本,通过替换特殊占位符来更新编译时的类代码:

 public final class CompilationInfo { public static final String TIME = "$COMPILE_TIME"; } 

有关详细信息,请参阅此文章 。

不知道一种标准的方法,我的建议类似于spektom的链接,但是会将一个属性文件添加到你的构建脚本填充的jar中(Ant有一个用于生成属性文件的内置任务)。 也许把它放在/buildinfo.properties上。 然后创建一个Java类,只需在运行时轮询该属性文件。

在Ant中,它可能看起来像这样:

 ...  ...    

然后对应Java

 public Date getBuildDate() { Properties buildProps = new Properties(); buildProps.load(getClass().getResourceAsStream("/buildinfo.properties")); return someConversion(buildProps.getProperty("build.date")); } 

让构建过程创建包含所需信息的属性文件,然后将属性作为代码中的资源读取

这是我的类,用于检测Java程序的构建时间。 它也使用了这个答案中的代码。

 import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.attribute.FileTime; import java.text.DateFormat; import java.util.Date; import java.util.Enumeration; import java.util.Locale; import java.util.jar.JarFile; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; public class BuildDate { private static Date buildDate; static { try { buildDate = setBuildDate(); } catch (Exception exception) { exception.printStackTrace(); } } public static String getBuildDate() { int style = DateFormat.FULL; Locale locale = Locale.getDefault(); DateFormat dateFormat = DateFormat.getDateInstance(style, locale); DateFormat timeFormat = DateFormat.getTimeInstance(style, locale); return dateFormat.format(buildDate) + " " + timeFormat.format(buildDate); } private static Date setBuildDate() throws Exception { if (ProgramDirectoryUtilities.runningFromIntelliJ()) { return getClassBuildTime(); } else { return getNewestFileDate(); } } private static Date getNewestFileDate() throws Exception { String filePath = ProgramDirectoryUtilities.getJARFilePath(); File file = new File(filePath); ZipFile zipFile = new ZipFile(file); Enumeration entries = zipFile.entries(); long millis = -1; while (entries.hasMoreElements()) { ZipEntry entry = (ZipEntry) entries.nextElement(); if (!entry.isDirectory()) { FileTime fileTime = entry.getLastModifiedTime(); long currentMillis = fileTime.toMillis(); if (millis < currentMillis) { millis = currentMillis; } } } return new Date(millis); } /** * Handles files, jar entries, and deployed jar entries in a zip file (EAR). * * @return The date if it can be determined, or null if not. */ private static Date getClassBuildTime() throws IOException, URISyntaxException { Date date = null; Class currentClass = new Object() { }.getClass().getEnclosingClass(); URL resource = currentClass.getResource(currentClass.getSimpleName() + ".class"); if (resource != null) { switch (resource.getProtocol()) { case "file": date = new Date(new File(resource.toURI()).lastModified()); break; case "jar": { String path = resource.getPath(); date = new Date(new File(path.substring(5, path.indexOf("!"))).lastModified()); break; } case "zip": { String path = resource.getPath(); File jarFileOnDisk = new File(path.substring(0, path.indexOf("!"))); try (JarFile jarFile = new JarFile(jarFileOnDisk)) { ZipEntry zipEntry = jarFile.getEntry(path.substring(path.indexOf("!") + 2));//Skip the ! and the / long zeTimeLong = zipEntry.getTime(); date = new Date(zeTimeLong); } break; } } } return date; } } 

实用类:

 import java.io.File; import java.lang.invoke.MethodHandles; import java.net.URISyntaxException; import java.net.URLDecoder; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; public class ProgramDirectoryUtilities { public static String getJARFilePath() throws URISyntaxException { return new File(MethodHandles.lookup().lookupClass().getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getAbsolutePath(); } public static boolean runningFromJAR() { try { String jarFilePath = new File(MethodHandles.lookup().lookupClass().getProtectionDomain() .getCodeSource() .getLocation() .getPath()). toString(); jarFilePath = URLDecoder.decode(jarFilePath, "UTF-8"); try (ZipFile zipFile = new ZipFile(jarFilePath)) { ZipEntry zipEntry = zipFile.getEntry("META-INF/MANIFEST.MF"); return zipEntry != null; } } catch (Exception exception) { return false; } } public static String getProgramDirectory() { if (runningFromJAR()) { return getCurrentJARDirectory(); } else { return getCurrentProjectDirectory(); } } private static String getCurrentProjectDirectory() { return new File("").getAbsolutePath(); } private static String getCurrentJARDirectory() { try { return new File(MethodHandles.lookup().lookupClass().getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParent(); } catch (URISyntaxException exception) { exception.printStackTrace(); } return null; } public static boolean runningFromIntelliJ() { String classPath = System.getProperty("java.class.path"); return classPath.contains("idea_rt.jar"); } } 

这是我认为最好的解决方案。 我正在使用eclipse的export-function’Runnable jar-file’。 此函数生成文件“META-INF / MANIFEST.MF”,我用它来确定导出时间。 当我构建程序时,那些时间告诉我。 在eclipse下,只显示参数“obj”的类的编译时间。

 private static Date getDateOfJar(String path) throws IOException { Date ret=null; JarFile jarFile = new JarFile(path); Enumeration ent = jarFile.entries(); while (ent.hasMoreElements()) { JarEntry entry = (JarEntry) ent.nextElement(); String name = entry.getName(); if (name.equals("META-INF/MANIFEST.MF")) { ret = new Date(entry.getTime()); break; } } jarFile.close(); return ret; } public static String getClassBuildTime(Object obj) { String ret = "unknown"; try { Class currentClass = obj.getClass().getEnclosingClass(); URL resource = currentClass.getResource(currentClass.getSimpleName() + ".class"); if (resource != null) { if (resource.getProtocol().equals("file")) { try { Date d = new Date(new File(resource.toURI()).lastModified()); ret = ""+d; } catch (URISyntaxException ignored) { } } else if (resource.getProtocol().equals("jar")) { String path = resource.getPath(); Date d=getDateOfJar(path.substring(5, path.indexOf("!"))); ret = ""+d; } } } catch (Exception e) { System.out.println("Error! FileLogger.getClassBuildTime() Exception e=" + e.getMessage()); e.printStackTrace(); } return ret; }