blob: 3896001a1b8e40399b5b77f5c19692cdee3c75c8 [file] [log] [blame]
Tatu Salorantaf15531c2011-12-22 23:00:40 -08001package com.fasterxml.jackson.core.util;
2
3import java.io.*;
James Roper78774992012-01-03 20:43:57 +01004import java.util.Properties;
Tatu Salorantaf15531c2011-12-22 23:00:40 -08005import java.util.regex.Pattern;
6
7import com.fasterxml.jackson.core.Version;
Tatu Saloranta45466132013-01-11 10:20:48 -08008import com.fasterxml.jackson.core.Versioned;
Tatu Salorantaf15531c2011-12-22 23:00:40 -08009
10/**
11 * Functionality for supporting exposing of component {@link Version}s.
Tatu Salorantaa629bb92013-04-07 10:33:04 -070012 * Also contains other misc methods that have no other place to live in.
Tatu Saloranta48d26092011-12-28 23:11:49 -080013 *<p>
14 * Note that this class can be used in two roles: first, as a static
15 * utility class for loading purposes, and second, as a singleton
16 * loader of per-module version information.
Tatu Salorantac3ef9f32013-02-04 20:35:22 -080017 *<p>
18 * Note that method for accessing version information changed between versions
19 * 2.1 and 2.2; earlier code used file named "VERSION.txt"; but this has serious
20 * performance issues on some platforms (Android), so a replacement system
21 * was implemented to use class generation and dynamic class loading.
Cowtowncoder88c296c2015-05-27 12:08:24 -070022 *<p>
23 * Note that functionality for reading "VERSION.txt" was removed completely
24 * from Jackson 2.6.
Tatu Salorantaf15531c2011-12-22 23:00:40 -080025 */
26public class VersionUtil
27{
Tatu Salorantafedd7952014-01-14 20:41:04 -080028 private final static Pattern V_SEP = Pattern.compile("[-_./;:]");
Tatu Saloranta48d26092011-12-28 23:11:49 -080029
Tatu Salorantafedd7952014-01-14 20:41:04 -080030 private final Version _v;
Tatu Saloranta48d26092011-12-28 23:11:49 -080031
32 /*
33 /**********************************************************
Tatu Saloranta1313ea32013-09-06 21:36:34 -070034 /* Instance life-cycle
Tatu Saloranta48d26092011-12-28 23:11:49 -080035 /**********************************************************
36 */
37
38 protected VersionUtil()
39 {
40 Version v = null;
41 try {
42 /* Class we pass only matters for resource-loading: can't use this Class
43 * (as it's just being loaded at this point), nor anything that depends on it.
44 */
45 v = VersionUtil.versionFor(getClass());
46 } catch (Exception e) { // not good to dump to stderr; but that's all we have at this low level
Tatu Saloranta1313ea32013-09-06 21:36:34 -070047 System.err.println("ERROR: Failed to load Version information from "+getClass());
Tatu Saloranta48d26092011-12-28 23:11:49 -080048 }
49 if (v == null) {
50 v = Version.unknownVersion();
51 }
Tatu Salorantafedd7952014-01-14 20:41:04 -080052 _v = v;
Tatu Saloranta48d26092011-12-28 23:11:49 -080053 }
54
Tatu Salorantafedd7952014-01-14 20:41:04 -080055 public Version version() { return _v; }
Tatu Saloranta48d26092011-12-28 23:11:49 -080056
57 /*
58 /**********************************************************
59 /* Static load methods
60 /**********************************************************
61 */
Tatu Salorantaf15531c2011-12-22 23:00:40 -080062
63 /**
64 * Helper method that will try to load version information for specified
Ben Gertzfieldf440fa02013-01-03 16:38:28 -080065 * class. Implementation is as follows:
66 *
67 * First, tries to load version info from a class named
68 * "PackageVersion" in the same package as the class.
69 *
Ben Gertzfieldf440fa02013-01-03 16:38:28 -080070 * If no version information is found, {@link Version#unknownVersion()} is returned.
Tatu Salorantaf15531c2011-12-22 23:00:40 -080071 */
72 public static Version versionFor(Class<?> cls)
73 {
Sammy Chu18ad3bc2016-01-26 11:58:58 +080074 Version version = packageVersionFor(cls);
75 return version == null ? Version.unknownVersion() : version;
Francis Galiegue6ebc7592012-11-13 17:40:58 +010076 }
77
Ben Gertzfieldf440fa02013-01-03 16:38:28 -080078 /**
79 * Loads version information by introspecting a class named
80 * "PackageVersion" in the same package as the given class.
Tatu Saloranta1fb1e272016-01-25 20:00:10 -080081 *<p>
Ben Gertzfieldf440fa02013-01-03 16:38:28 -080082 * If the class could not be found or does not have a public
83 * static Version field named "VERSION", returns null.
84 */
85 public static Version packageVersionFor(Class<?> cls)
86 {
Tatu Saloranta1fb1e272016-01-25 20:00:10 -080087 Version v = null;
Ben Gertzfieldf440fa02013-01-03 16:38:28 -080088 try {
Tatu Saloranta1313ea32013-09-06 21:36:34 -070089 String versionInfoClassName = cls.getPackage().getName() + ".PackageVersion";
Tatu Saloranta838dc4c2013-09-06 21:41:44 -070090 Class<?> vClass = Class.forName(versionInfoClassName, true, cls.getClassLoader());
91 // However, if class exists, it better work correctly, no swallowing exceptions
92 try {
Tatu Saloranta1fb1e272016-01-25 20:00:10 -080093 v = ((Versioned) vClass.newInstance()).version();
Tatu Saloranta838dc4c2013-09-06 21:41:44 -070094 } catch (Exception e) {
95 throw new IllegalArgumentException("Failed to get Versioned out of "+vClass);
96 }
Cowtowncoder88c296c2015-05-27 12:08:24 -070097 } catch (Exception e) { // ok to be missing (not good but acceptable)
Tatu Saloranta1fb1e272016-01-25 20:00:10 -080098 ;
Ben Gertzfieldf440fa02013-01-03 16:38:28 -080099 }
Tatu Saloranta1fb1e272016-01-25 20:00:10 -0800100 return (v == null) ? Version.unknownVersion() : v;
Ben Gertzfieldf440fa02013-01-03 16:38:28 -0800101 }
102
Tatu Saloranta96e131f2011-12-28 22:50:23 -0800103 /**
James Roper78774992012-01-03 20:43:57 +0100104 * Will attempt to load the maven version for the given groupId and
105 * artifactId. Maven puts a pom.properties file in
106 * META-INF/maven/groupId/artifactId, containing the groupId,
107 * artifactId and version of the library.
108 *
Tatu Salorantafedd7952014-01-14 20:41:04 -0800109 * @param cl the ClassLoader to load the pom.properties file from
James Roper78774992012-01-03 20:43:57 +0100110 * @param groupId the groupId of the library
111 * @param artifactId the artifactId of the library
112 * @return The version
Cowtowncoder88c296c2015-05-27 12:08:24 -0700113 *
114 * @deprecated Since 2.6: functionality not used by any official Jackson component, should be
115 * moved out if anyone needs it
James Roper78774992012-01-03 20:43:57 +0100116 */
Tatu Saloranta1313ea32013-09-06 21:36:34 -0700117 @SuppressWarnings("resource")
Cowtowncoder88c296c2015-05-27 12:08:24 -0700118 @Deprecated // since 2.6
Tatu Salorantafedd7952014-01-14 20:41:04 -0800119 public static Version mavenVersionFor(ClassLoader cl, String groupId, String artifactId)
Tatu Saloranta1313ea32013-09-06 21:36:34 -0700120 {
Tatu Salorantafedd7952014-01-14 20:41:04 -0800121 InputStream pomProperties = cl.getResourceAsStream("META-INF/maven/"
Tatu Saloranta838dc4c2013-09-06 21:41:44 -0700122 + groupId.replaceAll("\\.", "/")+ "/" + artifactId + "/pom.properties");
Tatu Saloranta1313ea32013-09-06 21:36:34 -0700123 if (pomProperties != null) {
James Roper78774992012-01-03 20:43:57 +0100124 try {
125 Properties props = new Properties();
Tatu Saloranta1313ea32013-09-06 21:36:34 -0700126 props.load(pomProperties);
James Roper78774992012-01-03 20:43:57 +0100127 String versionStr = props.getProperty("version");
128 String pomPropertiesArtifactId = props.getProperty("artifactId");
129 String pomPropertiesGroupId = props.getProperty("groupId");
130 return parseVersion(versionStr, pomPropertiesGroupId, pomPropertiesArtifactId);
131 } catch (IOException e) {
132 // Ignore
133 } finally {
Tatu Saloranta1313ea32013-09-06 21:36:34 -0700134 _close(pomProperties);
James Roper78774992012-01-03 20:43:57 +0100135 }
136 }
137 return Version.unknownVersion();
138 }
139
Cowtowncoder88c296c2015-05-27 12:08:24 -0700140 /**
Cowtowncoder2e262b92015-05-27 17:32:17 -0700141 * Method used by <code>PackageVersion</code> classes to decode version injected by Maven build.
Cowtowncoder88c296c2015-05-27 12:08:24 -0700142 */
Tatu Salorantafedd7952014-01-14 20:41:04 -0800143 public static Version parseVersion(String s, String groupId, String artifactId)
Tatu Salorantaf15531c2011-12-22 23:00:40 -0800144 {
Tatu Salorantafedd7952014-01-14 20:41:04 -0800145 if (s != null && (s = s.trim()).length() > 0) {
146 String[] parts = V_SEP.split(s);
Tatu Saloranta838dc4c2013-09-06 21:41:44 -0700147 return new Version(parseVersionPart(parts[0]),
148 (parts.length > 1) ? parseVersionPart(parts[1]) : 0,
149 (parts.length > 2) ? parseVersionPart(parts[2]) : 0,
150 (parts.length > 3) ? parts[3] : null,
151 groupId, artifactId);
Tatu Salorantaf15531c2011-12-22 23:00:40 -0800152 }
Tatu Saloranta1fb1e272016-01-25 20:00:10 -0800153 return Version.unknownVersion();
Tatu Salorantaf15531c2011-12-22 23:00:40 -0800154 }
155
Tatu Salorantafedd7952014-01-14 20:41:04 -0800156 protected static int parseVersionPart(String s) {
Tatu Salorantaf15531c2011-12-22 23:00:40 -0800157 int number = 0;
Tatu Salorantafedd7952014-01-14 20:41:04 -0800158 for (int i = 0, len = s.length(); i < len; ++i) {
159 char c = s.charAt(i);
Tatu Salorantaf15531c2011-12-22 23:00:40 -0800160 if (c > '9' || c < '0') break;
161 number = (number * 10) + (c - '0');
162 }
163 return number;
164 }
Tatu Salorantaa629bb92013-04-07 10:33:04 -0700165
Tatu Saloranta1313ea32013-09-06 21:36:34 -0700166 private final static void _close(Closeable c) {
167 try {
168 c.close();
169 } catch (IOException e) { }
170 }
171
Tatu Salorantaa629bb92013-04-07 10:33:04 -0700172 /*
173 /**********************************************************
174 /* Orphan utility methods
175 /**********************************************************
176 */
177
178 public final static void throwInternal() {
179 throw new RuntimeException("Internal error: this code path should never get executed");
180 }
Tatu Salorantaf15531c2011-12-22 23:00:40 -0800181}