阅读我自己的罐子清单采取 2

Posted

技术标签:

【中文标题】阅读我自己的罐子清单采取 2【英文标题】:Reading My Own Jar's Manifest Take 2 【发布时间】:2016-09-15 13:05:55 【问题描述】:

这是对near-universally accepted answer 对old question 的回应。由于答案相当陈旧(2009 年)并且对我不起作用,我想我会问是否有人知道原因。

我的用例是开发一个内部使用的 gradle 插件。每当应用插件时,我都非常希望能够打印出正在使用的插件版本。因此,我在构建插件时将版本写入插件的清单,并尝试在应用插件时使用链接答案中的技术从清单中读取它。

我根据答案编写了一些代码,但它不起作用。我加了一堆调试代码,可以看到代码首先找到了JDK自己提供的Manifest:

Manifest-Version: 1.0
Created-By: 1.7.0_07 (Oracle Corporation)

然后它找到我的清单,我正在寻找的那个,但抛出一个 FileNotFoundException:

java.io.FileNotFoundException: JAR entry META-INF/MANIFEST.MF not found in path to my plugin jar in my local maven repository。怎么可能

        Enumeration<URL> resources = getClass().getClassLoader()
                .getResources("META-INF/MANIFEST.MF");

找到清单,然后在尝试读取时抛出 FileNotFoundException:

Manifest manifest = new Manifest(resources.nextElement().openStream());

这是引发异常的行。

有人可以解释这种奇怪的行为,或者想出另一种可能更新的方式来阅读清单吗?

顺便说一句,这是在 Eclipse 下,在 Windows 中运行的。还没有在 Linux 上尝试过,它可能确实可以工作,但我希望它在这两种情况下都可以工作。

【问题讨论】:

您打算读取清单的哪些属性?许多与版本相关的清单属性可用作java.lang.Package 类的方法。 是的,我刚刚找到了同样的东西,谢谢。请参阅我刚刚发布的答案。 【参考方案1】:

如果是我,我会在构建时生成一个包含版本的 java 文件:

例如:将以下文件放入src/template/java/com/foo/MyPluginProperties.java

package com.foo;
public class MyPluginProperties 
   public static String getVersion() 
      return "@version@";
   

然后在build.gradle

def generatedJava = file("$buildDir/generated/java")
task generateSource(type:Copy) 
    def tokens = [version: project.version]

    // configure task inputs for gradle's up-to-date checks
    inputs.property "tokens", tokens
    from "src/template/java"
    filter(ReplaceTokens, tokens: tokens)
    into generatedJava


// wire the task into the gradle DAG
compileJava.dependsOn generateSource

// add the generated directory to the main source set so it's compiled
sourceSets.main.java 
   srcDir generatedJava

然后,在您的插件中,您可以调用以下内容:

com.foo.MyPluginProperties.getVersion()

【讨论】:

谢谢。这对我的特定用例很有用。我仍然想知道为什么 FileNotFoundException 在我的原始方法中发生。 不知道,也许你没有关闭之前的输入流? Tapestry IOC 做了类似的事情here 不是这样的。我想到了这一点,并确保我确实关闭了以前的输入流,但这没有任何帮助..【参考方案2】:

我们可以利用 Java 类加载器已经在 java.lang 中提供的东西,而不是尝试读取清单,因为奇怪的 IO 问题(我仍然想了解) 。包裹。当从 jar 加载包时,会调用 private Package(String name, Manifest man, URL url, ClassLoader loader) 构造函数。它读取 Manifest 的标准属性并将它们存储在 Package 成员变量中:

private final String pkgName;
private final String specTitle;
private final String specVersion;
private final String specVendor;
private final String implTitle;
private final String implVersion;
private final String implVendor;

这些清单条目必须具有正确的键,例如“Implementation-Version”等,在java.util.jar.Attributes.Name中找到

使用根据这些标准构建的清单,无需再次读取即可获得这些值。帽子提示https://***.com/a/23280647/811299

【讨论】:

以上是关于阅读我自己的罐子清单采取 2的主要内容,如果未能解决你的问题,请参考以下文章

阅读清单体系

2019 书单记录~

如何获取 LinkedIn 亚马逊阅读列表数据

4个方法快速打造你的阅读清单

Codeforces Round #446 (Div. 2)

2018年下半年计划清单