[java] 런타임에 Maven 아티팩트 버전 가져 오기

Maven 아티팩트의 JAR에서 project.version 속성이 두 파일에 포함되어 있음을 알았습니다.

META-INF/maven/${groupId}/${artifactId}/pom.properties
META-INF/maven/${groupId}/${artifactId}/pom.xml

런타임에이 버전을 읽는 권장 방법이 있습니까?



답변

특정 라이브러리 / 클래스의 버전 정보를 얻기 위해 Maven 특정 파일에 액세스 할 필요는 없습니다.

getClass().getPackage().getImplementationVersion().jar-files에 저장된 버전 정보를 얻는 데 사용할 수 있습니다 MANIFEST.MF. 운 좋게도 Maven은 충분히 영리합니다 불행하게도 Maven은 기본적으로 매니페스트에 올바른 정보를 쓰지 않습니다!

대신 하나는 수정이 <archive>의 구성 요소 maven-jar-plugin세트 addDefaultImplementationEntriesaddDefaultSpecificationEntriestrue이 같은 :

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
            </manifest>
        </archive>
    </configuration>
</plugin>

이상적으로이 구성은 회사 pom나 다른베이스 폼에 배치해야합니다 .

<archive>요소 에 대한 자세한 설명서 는 Maven Archive 설명서를 참조하십시오 .


답변

A에 대한 위의 대답을 따르 .war유물, 나는에 해당하는 구성을 적용했다 발견 maven-war-plugin보다는 maven-jar-plugin:

<plugin>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.1</version>
    <configuration>
        <archive>
            <manifest>
                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
            </manifest>
        </archive>
    </configuration>
</plugin>

이에 버전 정보를 추가 MANIFEST.MF프로젝트의에 .jar(포함 WEB-INF/lib.war)


답변

다음은 pom.properties에서 버전을 가져 와서 매니페스트에서 가져 오는 방법입니다.

public synchronized String getVersion() {
    String version = null;

    // try to load from maven properties first
    try {
        Properties p = new Properties();
        InputStream is = getClass().getResourceAsStream("/META-INF/maven/com.my.group/my-artefact/pom.properties");
        if (is != null) {
            p.load(is);
            version = p.getProperty("version", "");
        }
    } catch (Exception e) {
        // ignore
    }

    // fallback to using Java API
    if (version == null) {
        Package aPackage = getClass().getPackage();
        if (aPackage != null) {
            version = aPackage.getImplementationVersion();
            if (version == null) {
                version = aPackage.getSpecificationVersion();
            }
        }
    }

    if (version == null) {
        // we could not compute the version so use a blank
        version = "";
    }

    return version;
} 


답변

나는 여기에 두 가지 주요 접근 방식에 시간을 보냈지 만 그들은 나를 위해 운동하지 않았습니다. 빌드에 Netbeans를 사용하고 있으며 더 많은 작업이있을 수 있습니다. Maven 3의 일부 오류와 경고가 있지만 일부는 쉽게 수정할 수 있다고 생각합니다. 더 큰.

DZone 의이 기사에서 유지 관리 가능하고 구현하기 쉬운 답변을 찾았습니다.

이미 resources / config 하위 폴더를 가지고 있고 지원 URL과 같이 유지할 수있는 것들을 더 잘 반영하기 위해 app.properties라는 파일 이름을 지정했습니다.

유일한주의 사항은 Netbeans가 IDE에서 필터링을 해제해야한다는 경고를 표시한다는 것입니다. 어디서 / 어떻게 확실하지 않습니다. 이 시점에서는 효과가 없습니다. 다리를 건너야 할 경우 해결 방법이있을 수 있습니다. 행운을 빕니다.


답변

maven-assembly-plugin내 메이븐 포장에 사용 하고 있습니다. Joachim Sauer의 답변 에서 Apache Maven Archiver 를 사용하면 다음과 같이 작동 할 수 있습니다.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        <archive>
            <manifest>
                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
            </manifest>
        </archive>
    </configuration>
    <executions>
        <execution .../>
    </executions>
</plugin>

archiever는 maven 공유 구성 요소 중 하나이므로 여러 maven building plugin에서 사용할 수 있으며, archive내부 구성을 포함하여 둘 이상의 플러그인이 도입되면 충돌이 발생할 수 있습니다 .


답변

Maven 빌드뿐만 아니라 Eclipse에서도 실행하려면 다른 응답에 설명 된대로 addDefaultImplementationEntriesaddDefaultSpecificationEntriespom 항목을 추가 한 후 다음 코드를 사용해야합니다.

public synchronized static final String getVersion() {
    // Try to get version number from pom.xml (available in Eclipse)
    try {
        String className = getClass().getName();
        String classfileName = "/" + className.replace('.', '/') + ".class";
        URL classfileResource = getClass().getResource(classfileName);
        if (classfileResource != null) {
            Path absolutePackagePath = Paths.get(classfileResource.toURI())
                    .getParent();
            int packagePathSegments = className.length()
                    - className.replace(".", "").length();
            // Remove package segments from path, plus two more levels
            // for "target/classes", which is the standard location for
            // classes in Eclipse.
            Path path = absolutePackagePath;
            for (int i = 0, segmentsToRemove = packagePathSegments + 2;
                    i < segmentsToRemove; i++) {
                path = path.getParent();
            }
            Path pom = path.resolve("pom.xml");
            try (InputStream is = Files.newInputStream(pom)) {
                Document doc = DocumentBuilderFactory.newInstance()
                        .newDocumentBuilder().parse(is);
                doc.getDocumentElement().normalize();
                String version = (String) XPathFactory.newInstance()
                        .newXPath().compile("/project/version")
                        .evaluate(doc, XPathConstants.STRING);
                if (version != null) {
                    version = version.trim();
                    if (!version.isEmpty()) {
                        return version;
                    }
                }
            }
        }
    } catch (Exception e) {
        // Ignore
    }

    // Try to get version number from maven properties in jar's META-INF
    try (InputStream is = getClass()
        .getResourceAsStream("/META-INF/maven/" + MAVEN_PACKAGE + "/"
                + MAVEN_ARTIFACT + "/pom.properties")) {
        if (is != null) {
            Properties p = new Properties();
            p.load(is);
            String version = p.getProperty("version", "").trim();
            if (!version.isEmpty()) {
                return version;
            }
        }
    } catch (Exception e) {
        // Ignore
    }

    // Fallback to using Java API to get version from MANIFEST.MF
    String version = null;
    Package pkg = getClass().getPackage();
    if (pkg != null) {
        version = pkg.getImplementationVersion();
        if (version == null) {
            version = pkg.getSpecificationVersion();
        }
    }
    version = version == null ? "" : version.trim();
    return version.isEmpty() ? "unknown" : version;
}

Java 빌드가 대상 클래스를 “대상 / 클래스”이외의 다른 곳에두면 segmentToRemove의 값을 조정해야합니다.


답변

내 봄 부팅 응용 프로그램에서 허용되는 답변의 솔루션은 최근 jdk를 버전 12로 업데이트 할 때까지 작동했습니다. 다른 모든 답변도 시도했지만 작동하지 못했습니다.

그 시점에서 나는 주석 바로 다음에 스프링 부트 응용 프로그램의 첫 번째 클래스에 아래 줄을 추가했습니다. @SpringBootApplication

@PropertySources({
        @PropertySource("/META-INF/maven/com.my.group/my-artefact/pom.properties")
})

나중에 아래 값을 사용하여 값을 사용하려는 클래스의 속성 파일에서 값을 appVersion가져 와서 프로젝트 버전을 가져옵니다.

@Value("${version}")
private String appVersion;

누군가에게 도움이되기를 바랍니다.