Java jar version runtime

Get jar version in runtime

I’m wondering if it is possible to retrieve, in runtime, a version number of a jar from which the class comes from? I know its possible to find jar from which the class comes from:

MyClass.class.getProtectionDomain().getCodeSource().getLocation().getPath(); 

3 Answers 3

Try this, it may be helpful:

String s = new String(); System.out.println(s.getClass().getPackage().getSpecificationVersion()); System.out.println(s.getClass().getPackage().getImplementationVersion()); 
import javax.mail.internet.InternetAddress; /** Display package name and version information for javax.mail.internet. */ public final class ReadVersion < public static void main(String. aArgs)< ReadVersion readVersion = new ReadVersion(); readVersion.readVersionInfoInManifest(); >public void readVersionInfoInManifest() < InternetAddress object = new InternetAddress(); Package objPackage = object.getClass().getPackage(); //examine the package object String name = objPackage.getSpecificationTitle(); String version = objPackage.getSpecificationVersion(); //some jars may use 'Implementation Version' entries in the manifest instead System.out.println("Package name: " + name); System.out.println("Package version: " + version); >> 

Be careful using getPackage().getImplementationVersion/getSpecificationVersion()

getSpecificationVersion returns specVersion from Manifest. Manifest is a property of a jar and is used in sun.misc.URLClassPath as

 public Manifest getManifest() throws IOException

So in case somebody use your library as dependency for fat jar, it returns the version of Manifest for fat jar.

Источник

Can I determine the version of a Java library at runtime?

Third party Java library means a Jar file, and the Jar file manifest has properties specifically to specify the version of the library.

Beware: Not all Jar files actually specify the version, even though they should.

Built-in Java way to read that information is to use reflection, but you need to know some class in the library to query. Doesn’t really matter which class/interface.

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()); >> 
org.apache.http.client.HttpClient Title: HttpComponents Apache HttpClient Version: 4.3.6 Vendor: The Apache Software Foundation com.fasterxml.jackson.databind.ObjectMapper Title: jackson-databind Version: 2.7.0 Vendor: FasterXML com.google.gson.Gson Title: null Version: null Vendor: null 

You’re right, this is the more standard way. However, the Maven way is enforced by the keepers of the major repositories, so it’s more reliable. Ideally, I guess I’d combine the approaches.

This does not work properly if two jars contain the same package. Example: a-1.1.1.jar contains class com.abc.A and b-2.2.2.jar contains com.abc.B. Then the output for the package com.abc is the same for classes A and B.

Although there is no universal standard, there is a hack that works for most open source libraries, or anything that is released through a Maven repository through the Maven Release Plugin or compatible mechanisms. Since most other build systems on the JVM are Maven compatible, this should apply to libraries distributed through Gradle or Ivy as well (and possibly others).

The Maven release plugin (and all compatible processes) create a file in the released Jar called META-INF/$.$/pom.properties , which contains the properties groupId , artifactId and version .

By checking for this file and parsing it, we can detect the versions of a majority of library versions out there. Example code (Java 8 or higher):

/** * 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 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 unthrow(final Callable code) < try < return code.call(); >catch (Exception ignored) < return null; >> 

To test this code, I’ll try 3 classes, one from VAVR, one from Guava, and one from the JDK.

public static void main(String[] args)
Optional[0.9.2] Optional[24.1-jre] Optional.empty 

Источник

Class JarFile

The JarFile class is used to read the contents of a jar file from any file that can be opened with java.io.RandomAccessFile . It extends the class java.util.zip.ZipFile with support for reading an optional Manifest entry, and support for processing multi-release jar files. The Manifest can be used to specify meta-information about the jar file and its entries.

A multi-release jar file is a jar file that contains a manifest with a main attribute named «Multi-Release», a set of «base» entries, some of which are public classes with public or protected methods that comprise the public interface of the jar file, and a set of «versioned» entries contained in subdirectories of the «META-INF/versions» directory. The versioned entries are partitioned by the major version of the Java platform. A versioned entry, with a version n , 8 < n , in the "META-INF/versions/" directory overrides the base entry as well as any entry with a version number i where 8 < i < n .

By default, a JarFile for a multi-release jar file is configured to process the multi-release jar file as if it were a plain (unversioned) jar file, and as such an entry name is associated with at most one base entry. The JarFile may be configured to process a multi-release jar file by creating the JarFile with the JarFile(File, boolean, int, Runtime.Version) constructor. The Runtime.Version object sets a maximum version used when searching for versioned entries. When so configured, an entry name can correspond with at most one base entry and zero or more versioned entries. A search is required to associate the entry name with the latest versioned entry whose version is less than or equal to the maximum version (see getEntry(String) ).

Class loaders that utilize JarFile to load classes from the contents of JarFile entries should construct the JarFile by invoking the JarFile(File, boolean, int, Runtime.Version) constructor with the value Runtime.version() assigned to the last argument. This assures that classes compatible with the major version of the running JVM are loaded from multi-release jar files.

If the verify flag is on when opening a signed jar file, the content of the jar entry is verified against the signature embedded inside the manifest that is associated with its path name . For a multi-release jar file, the content of a versioned entry is verfieid against its own signature and JarEntry.getCodeSigners() returns its own signers. Please note that the verification process does not include validating the signer’s certificate. A caller should inspect the return value of JarEntry.getCodeSigners() to further determine if the signature can be trusted.

Unless otherwise noted, passing a null argument to a constructor or method in this class will cause a NullPointerException to be thrown.

  • jdk.util.jar.version can be assigned a value that is the String representation of a non-negative integer
  • jdk.util.jar.enableMultiRelease can be assigned one of the three String values true, false, or force. The value true, the default value, enables multi-release jar file processing. The value false disables multi-release jar processing, ignoring the «Multi-Release» manifest attribute, and the versioned directories in a multi-release jar file if they exist. Furthermore, the method isMultiRelease() returns false. The value force causes the JarFile to be initialized to runtime versioning after construction. It effectively does the same as this code: (new JarFile(File, boolean, int, JarFile.runtimeVersion()) .

Источник

Java: how to check jar version at runtime

Class loading issues can happen in complex execution environments. Situation gets worst when there are different versions of the same library “loaded” and we are not sure which our application is picking up.

To help debugging this issue, we could check at runtime which version of the library is loaded with the our application.

A code like the following can help:

// Example using HTMLEmail from Apache Commons Email Class theClass = HtmlEmail.class; // Find the path of the compiled class String classPath = theClass.getResource(theClass.getSimpleName() + ".class").toString(); System.out.println("Class: " + classPath); // Find the path of the lib which includes the class String libPath = classPath.substring(0, classPath.lastIndexOf("!")); System.out.println("Lib: " + libPath); // Find the path of the file inside the lib jar String filePath = libPath + "!/META-INF/MANIFEST.MF"; System.out.println("File: " + filePath); // We look at the manifest file, getting two attributes out of it Manifest manifest = new Manifest(new URL(filePath).openStream()); Attributes attr = manifest.getMainAttributes(); System.out.println("Manifest-Version: " + attr.getValue("Manifest-Version")); System.out.println("Implementation-Version: " + attr.getValue("Implementation-Version"));

The above code shows how to find jar file path and how to read the contents of a file (it is usually the Manifest) to read some info from it.

Источник

Getting Java version at runtime

I need to work around a Java bug in JDK 1.5 which was fixed in 1.6. I’m using the following condition:

if (System.getProperty("java.version").startsWith("1.5.")) < . >else

14 Answers 14

java.version is a system property that exists in every JVM. There are two possible formats for it:

Here is a trick to extract the major version: If it is a 1.x.y_z version string, extract the character at index 2 of the string. If it is a x.y.z version string, cut the string to its first dot character, if one exists.

private static int getVersion() < String version = System.getProperty("java.version"); if(version.startsWith("1.")) < version = version.substring(2, 3); >else < int dot = version.indexOf("."); if(dot != -1) < version = version.substring(0, dot); >> return Integer.parseInt(version); > 

Now you can check the version much more comfortably:

FP precision aside, for the OP’s needs the code provided should at least be (version > 1.5), not >=. To the OP: if you use your current String comparison do you need to check below 1.5 too?

@Ha: Maybe but double version = 1.6 and Double.parseDouble(«1.6») should still yield the same bit pattern, right? Since we don’t do arithmetics on the number (only a simple compare), even == will work as expected.

What about getting the version from the package meta infos:

String version = Runtime.class.getPackage().getImplementationVersion(); 

Prints out something like:

Wow, that kind of blew my mind. Though in my case, all I wanted was the first two parts of the version so: Runtime.class.getPackage().getSpecificationVersion()

Runtime.version()

Since Java 9, you can use Runtime.version() , which returns a Runtime.Version :

Runtime.Version version = Runtime.version(); 

@judovana Runtime.version().major() is deprecated since Java10, the equivalent is now Runtime.version().feature().

These articles seem to suggest that checking for 1.5 or 1.6 prefix should work, as it follows proper version naming convention.

Sun Technical Articles

Оцените статью