Подтвердить что ты не робот

Время печати Java последней компиляции

Я хочу внедрить фрагмент кода, который будет распечатывать время последнего компиляции текущего класса. Как это реализовать на Java?

4b9b3361

Ответ 1

В java нет прямой поддержки, поскольку нет препроцессора. Ближайшим эквивалентом является атрибут "Build-Date" в манифесте JAR. Многие системы сборки добавляют этот атрибут по умолчанию или предоставляют средства для его добавления.

Затем вы можете прочитать манифест JAR во время выполнения, чтобы получить дату. Ответ на этот вопрос SO описывает, как читать значения из манифеста JAR.

Альтернативой является использование фильтрации ресурсов для добавления даты в файл свойств, который затем считывается во время выполнения. Это довольно ad-hoc, нестандартное, и если у вас много банок, с разными временами компиляции, то это быстро становится трудно управлять, если вы не можете включить это в общую часть того, как все банки построены.

Ответ 2

Этот вопрос был дан ответ давным-давно. Но в случае, если кто-то качается здесь, решение, которое работает для меня, похоже на то, что предложил 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 файлы или статический контекст, и он выдает исключения вместо того, чтобы возвращать 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;
}

Ответ 3

Поскольку это никогда не упоминалось, любой, кто хочет решить эту проблему любыми средствами, может найти это как подходящее, но взломанное решение:

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

Это может быть не очень хорошо, и это очень хорошо не может быть совместимо с другими платформами, но это единственный способ найти дату компиляции текущего класса в родной Java.

Ответ 4

Это немного неуклюже, но вы можете сделать это с помощью фильтрации Ant.

Выполните следующий метод в своем классе:

public static String timeBuilt(){
    return "Built at @[email protected] on @[email protected]";
}

Затем добавьте следующее в файл сборки Ant.

<target name="get-time">
    <tstamp>
        <format property="buildTime" pattern="HH:mm:ss" locale="en,UK"/>
        <format property="buildDate" pattern="dd-MM-yyyy" locale="en,UK"/>
    </tstamp>
</target>

<target name="copy-files" depends="get-time">
    <filter token="timeBuilt" value="${buildTime}"/>
    <filter token="dateBuilt" value="${buildDate}"/>
    <copy includeemptydirs="false" todir="build" filtering="true">
        <fileset dir="src"/>
    </copy>
</target>

Это скопирует все в директории "src" в "build" и при этом заменит @timeBuilt @и @dateBuilt @на время и дату сборки соответственно. Просто сделайте свою цель сборки зависимой от файлов-копий и создайте из каталога "build", а не в каталоге "src".

Преимущество замены содержимого статического метода заключается в том, что это будет работать на основе каждого класса - если вы должны взять созданные файлы классов и объединить их с некоторыми другими файлами классов, которые были построены в другое время, они каждый знал бы, когда они были построены. Файлы свойств разумны, но если у вас не будет нескольких файлов свойств, вы сможете иметь только время сборки для пакета в целом.

Ответ 5

Создайте оболочку script, которая обновляет код класса с временем компиляции, заменяя специальные заполнители:

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

Для получения дополнительной информации см. в этой статье.

Ответ 6

Не зная стандартный способ сделать это, мое предложение похоже на ссылку spektom, но было бы добавить файл свойств в вашу банку, заполненную вашей сборкой script (Ant имеет встроенную задачу для генерируя файл свойств). Возможно, поместите его в /buildinfo.properties. Затем создайте класс Java, который просто проверяет этот файл свойства во время выполнения.

В Ant он может выглядеть примерно так:

...
<tstamp/>    
...
<propertyfile file="${output.dir}/buildinfo.properties">
   <entry key="build.date" value="${TSTAMP}"/>
</propertyfile>

И затем соответствующая Java

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

Ответ 7

Пусть ваша процедура сборки создаст файл свойств, содержащий нужную вам информацию, а затем прочитайте свойства как ресурс в коде

Ответ 8

Вот мой класс для определения времени сборки вашей 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");
    }
}