我可以在运行时确定Java库的版本吗?

时间:2018-04-18 00:53:23

标签: java libraries

是否可以在运行时确定第三方Java库的版本?

3 个答案:

答案 0 :(得分:12)

第三方Java库是指Jar文件,Jar文件清单具有专门用于指定库版本的属性。

注意:并非所有Jar文件都实际指定了版本,即使它们应该

内置Java方式来读取该信息是使用反射,但您需要知道库中的某些类来进行查询。

并不重要。

实施例

means = DataTD.mean()
means[[means.idxmax()]]

Swim (seconds)    5.7
dtype: float64

输出

public class Test {
    public static void main(String[] args) {
        printVersion(org.apache.http.client.HttpClient.class);
        printVersion(com.fasterxml.jackson.databind.ObjectMapper.class);
        printVersion(com.google.gson.Gson.class);
    }
    public static void printVersion(Class<?> clazz) {
        Package p = clazz.getPackage();
        System.out.printf("%s%n  Title: %s%n  Version: %s%n  Vendor: %s%n",
                          clazz.getName(),
                          p.getImplementationTitle(),
                          p.getImplementationVersion(),
                          p.getImplementationVendor());
    }
}

答案 1 :(得分:3)

虽然没有通用标准,但是有一个hack适用于大多数开源库,或者通过Maven Release Plugin或兼容机制通过Maven存储库发布的任何东西。由于JVM上的大多数其他构建系统都是Maven兼容的,因此这应该适用于通过Gradle或Ivy(以及可能还有其他)分发的库。

Maven发布插件(以及所有兼容的进程)在已发布的名为META-INF/${groupId}.${artifactId}/pom.properties的Jar中创建一个文件,其中包含属性groupIdartifactIdversion。< / p>

通过检查此文件并解析它,我们可以检测到大多数库版本的版本。示例代码(Java 8或更高版本):

/**
 * Reads a library's version if the library contains a Maven pom.properties
 * file. You probably want to cache the output or write it to a constant.
 *
 * @param referenceClass any class from the library to check
 * @return an Optional containing the version String, if present
 */
public static Optional<String> extractVersion(
    final Class<?> referenceClass) {
    return Optional.ofNullable(referenceClass)
                   .map(cls -> unthrow(cls::getProtectionDomain))
                   .map(ProtectionDomain::getCodeSource)
                   .map(CodeSource::getLocation)
                   .map(url -> unthrow(url::openStream))
                   .map(is -> unthrow(() -> new JarInputStream(is)))
                   .map(jis -> readPomProperties(jis, referenceClass))
                   .map(props -> props.getProperty("version"));
}

/**
 * Locate the pom.properties file in the Jar, if present, and return a
 * Properties object representing the properties in that file.
 *
 * @param jarInputStream the jar stream to read from
 * @param referenceClass the reference class, whose ClassLoader we'll be
 * using
 * @return the Properties object, if present, otherwise null
 */
private static Properties readPomProperties(
    final JarInputStream jarInputStream,
    final Class<?> referenceClass) {

    try {
        JarEntry jarEntry;
        while ((jarEntry = jarInputStream.getNextJarEntry()) != null) {
            String entryName = jarEntry.getName();
            if (entryName.startsWith("META-INF")
                && entryName.endsWith("pom.properties")) {

                Properties properties = new Properties();
                ClassLoader classLoader = referenceClass.getClassLoader();
                properties.load(classLoader.getResourceAsStream(entryName));
                return properties;
            }
        }
    } catch (IOException ignored) { }
    return null;
}

/**
 * Wrap a Callable with code that returns null when an exception occurs, so
 * it can be used in an Optional.map() chain.
 */
private static <T> T unthrow(final Callable<T> code) {
    try {
        return code.call();
    } catch (Exception ignored) { return null; }
}

要测试此代码,我将尝试3个类,一个来自VAVR,一个来自Guava,另一个来自JDK。

public static void main(String[] args) {
    Stream.of(io.vavr.collection.LinkedHashMultimap.class,
              com.google.common.collect.LinkedHashMultimap.class,
              java.util.LinkedHashMap.class)
          .map(VersionExtractor::extractVersion)
          .forEach(System.out::println);
}

输出,在我的机器上:

Optional[0.9.2]
Optional[24.1-jre]
Optional.empty

答案 2 :(得分:1)

由于我曾经为许多非常遗留的Java项目执行此任务,答案是“#34;它可以完成,但如何做到这一点取决于&#34;。

首先,检查您的JAR MANIFEST.MF文件。有时你很幸运。

其次,扫描JAR文件以获取版本字段。有时你会很幸运,有时候这个价值就会存在。

第三,扫描包含的属性文件。有一个通用的ANT构建模式可以将版本保存在属性文件中(更容易更新)。

第四,开始下载该项目的可用JAR文件。有时候版本号确实丢失了,验证它的唯一方法是找到一个已知的旧版本并进行JAR到JAR比较。

还有其他技术,但这4种几乎涵盖了所有场景。对于一些名不见经传的利基图书馆来说,这可能是一个很大的挑战。