|
|
|
@ -16,12 +16,28 @@ import java.util.logging.Logger; |
|
|
|
|
*/ |
|
|
|
|
public final class RuntimeVersion { |
|
|
|
|
|
|
|
|
|
private static final Logger logger = Logger.getLogger(RuntimeVersion.class.getName()); |
|
|
|
|
|
|
|
|
|
/** Indicates the domain of the Protobuf artifact. */ |
|
|
|
|
public enum RuntimeDomain { |
|
|
|
|
GOOGLE_INTERNAL, |
|
|
|
|
PUBLIC, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** Indicates whether last checked runtime is the full or lite version. */ |
|
|
|
|
protected enum Fullness { |
|
|
|
|
UNSPECIFIED, |
|
|
|
|
FULL, |
|
|
|
|
LITE |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Fields to the altered when initializing generated classes.
|
|
|
|
|
@SuppressWarnings({"ProtectedMembersInFinalClass", "NonFinalStaticField"}) |
|
|
|
|
protected static Fullness prevFullness = Fullness.UNSPECIFIED; |
|
|
|
|
|
|
|
|
|
@SuppressWarnings("NonFinalStaticField") |
|
|
|
|
private static String prevCheckedLocation = ""; |
|
|
|
|
|
|
|
|
|
// The version of this runtime.
|
|
|
|
|
// Automatically updated by Protobuf release process. Do not edit manually.
|
|
|
|
|
public static final RuntimeDomain DOMAIN = RuntimeDomain.PUBLIC; |
|
|
|
@ -33,82 +49,103 @@ public final class RuntimeVersion { |
|
|
|
|
private static final String VERSION_STRING = versionString(MAJOR, MINOR, PATCH, SUFFIX); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Validates that the gencode is in the same domain as the runtime. |
|
|
|
|
* Validates that the gencode version is compatible with this runtime version according to |
|
|
|
|
* https://protobuf.dev/support/cross-version-runtime-guarantee/.
|
|
|
|
|
* |
|
|
|
|
* <p>This method will be directly called by the google-internal gencode to verify no cross-domain |
|
|
|
|
* usages. |
|
|
|
|
* <p>This method is currently only used by Protobuf Java **lite version** gencode. Do not call it |
|
|
|
|
* elsewhere. |
|
|
|
|
* |
|
|
|
|
* @param gencodeDomain the domain where Protobuf Java code was generated. |
|
|
|
|
* @throws ProtobufRuntimeVersionException if gencodeDomain is not the same as DOMAIN. |
|
|
|
|
* @param domain the domain where Protobuf Java code was generated. |
|
|
|
|
* @param major the major version of Protobuf Java gencode. |
|
|
|
|
* @param minor the minor version of Protobuf Java gencode. |
|
|
|
|
* @param patch the micro/patch version of Protobuf Java gencode. |
|
|
|
|
* @param suffix the version suffix e.g. "-rc2", "-dev", etc. |
|
|
|
|
* @param location the debugging location e.g. generated Java class to put in the error messages. |
|
|
|
|
* @throws ProtobufRuntimeVersionException if versions are incompatible. |
|
|
|
|
*/ |
|
|
|
|
public static void validateProtobufGencodeDomain(RuntimeDomain gencodeDomain) { |
|
|
|
|
// Check the environmental variable, and temporarily disable validation if it's set to true.
|
|
|
|
|
String disableFlag = java.lang.System.getenv("TEMORARILY_DISABLE_PROTOBUF_VERSION_CHECK"); |
|
|
|
|
if ((disableFlag != null && disableFlag.equals("true"))) { |
|
|
|
|
public static void validateProtobufLiteGencodeVersion( |
|
|
|
|
RuntimeDomain domain, int major, int minor, int patch, String suffix, String location) { |
|
|
|
|
if (checkDisabled()) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (gencodeDomain != DOMAIN) { |
|
|
|
|
throw new ProtobufRuntimeVersionException( |
|
|
|
|
String.format( |
|
|
|
|
"Mismatched Protobuf Gencode/Runtime domains: gencode %s, runtime %s. Cross-domain" |
|
|
|
|
+ " usage of Protobuf is not supported.", |
|
|
|
|
gencodeDomain, DOMAIN)); |
|
|
|
|
synchronized (RuntimeVersion.class) { |
|
|
|
|
preventFullAndLite(Fullness.LITE, location); |
|
|
|
|
} |
|
|
|
|
validateProtobufGencodeVersionImpl(domain, major, minor, patch, suffix, location); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Validates that the gencode version is compatible with this runtime version according to |
|
|
|
|
* https://protobuf.dev/support/cross-version-runtime-guarantee/.
|
|
|
|
|
* |
|
|
|
|
* <p>This method is currently only used by Protobuf Java gencode in OSS. |
|
|
|
|
* |
|
|
|
|
* <p>This method is only for Protobuf Java gencode; do not call it elsewhere. |
|
|
|
|
* <p>This method is currently only used by Protobuf Java **full version** gencode. Do not call it |
|
|
|
|
* elsewhere. |
|
|
|
|
* |
|
|
|
|
* @param domain the domain where Protobuf Java code was generated. |
|
|
|
|
* @param major the major version of Protobuf Java gencode. |
|
|
|
|
* @param minor the minor version of Protobuf Java gencode. |
|
|
|
|
* @param patch the micro/patch version of Protobuf Java gencode. |
|
|
|
|
* @param suffix the version suffix e.g. "-rc2", "-dev", etc. |
|
|
|
|
* @param location the debugging location e.g. generated Java class to put in the error messages. |
|
|
|
|
* @throws ProtobufRuntimeVersionException if versions are incompatible. |
|
|
|
|
*/ |
|
|
|
|
public static void validateProtobufGencodeVersion( |
|
|
|
|
RuntimeDomain domain, int major, int minor, int patch, String suffix) { |
|
|
|
|
RuntimeDomain domain, int major, int minor, int patch, String suffix, String location) { |
|
|
|
|
if (checkDisabled()) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
synchronized (RuntimeVersion.class) { |
|
|
|
|
preventFullAndLite(Fullness.FULL, location); |
|
|
|
|
} |
|
|
|
|
validateProtobufGencodeVersionImpl(domain, major, minor, patch, suffix, location); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** The actual implementation of version validation. */ |
|
|
|
|
private static void validateProtobufGencodeVersionImpl( |
|
|
|
|
RuntimeDomain domain, int major, int minor, int patch, String suffix, String location) { |
|
|
|
|
if (checkDisabled()) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
String gencodeVersionString = versionString(major, minor, patch, suffix); |
|
|
|
|
// Check that version numbers are valid.
|
|
|
|
|
if (major < 0 || minor < 0 || patch < 0) { |
|
|
|
|
throw new ProtobufRuntimeVersionException( |
|
|
|
|
"Invalid gencode version: " + versionString(major, minor, patch, suffix)); |
|
|
|
|
throw new ProtobufRuntimeVersionException("Invalid gencode version: " + gencodeVersionString); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
validateProtobufGencodeDomain(domain); |
|
|
|
|
// Check that runtime domain is the same as the gencode domain.
|
|
|
|
|
if (domain != DOMAIN) { |
|
|
|
|
throw new ProtobufRuntimeVersionException( |
|
|
|
|
String.format( |
|
|
|
|
"Detected mismatched Protobuf Gencode/Runtime domains when loading %s: gencode %s," |
|
|
|
|
+ " runtime %s. Cross-domain usage of Protobuf is not supported.", |
|
|
|
|
location, domain, DOMAIN)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
String gencodeVersionString = versionString(major, minor, patch, suffix); |
|
|
|
|
// Check that runtime major version is the same as the gencode major version.
|
|
|
|
|
if (major != MAJOR) { |
|
|
|
|
throw new ProtobufRuntimeVersionException( |
|
|
|
|
String.format( |
|
|
|
|
"Mismatched Protobuf Gencode/Runtime major versions: gencode %s, runtime %s. Same" |
|
|
|
|
+ " major version is required.", |
|
|
|
|
gencodeVersionString, VERSION_STRING)); |
|
|
|
|
"Detected mismatched Protobuf Gencode/Runtime major versions when loading %s: gencode" |
|
|
|
|
+ " %s, runtime %s. Same major version is required.", |
|
|
|
|
location, gencodeVersionString, VERSION_STRING)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Check that runtime version is newer than the gencode version.
|
|
|
|
|
if (MINOR < minor || (MINOR == minor && PATCH < patch)) { |
|
|
|
|
throw new ProtobufRuntimeVersionException( |
|
|
|
|
String.format( |
|
|
|
|
"Protobuf Java runtime version cannot be older than the gencode version:" |
|
|
|
|
+ "gencode %s, runtime %s.", |
|
|
|
|
gencodeVersionString, VERSION_STRING)); |
|
|
|
|
"Detected incompatible Protobuf Gencode/Runtime versions when loading %s: gencode %s," |
|
|
|
|
+ " runtime %s. Runtime version cannot be older than the linked gencode version.", |
|
|
|
|
location, gencodeVersionString, VERSION_STRING)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Check that runtime version suffix is the same as the gencode version suffix.
|
|
|
|
|
if (!suffix.equals(SUFFIX)) { |
|
|
|
|
throw new ProtobufRuntimeVersionException( |
|
|
|
|
String.format( |
|
|
|
|
"Mismatched Protobuf Gencode/Runtime version suffixes: gencode %s, runtime %s." |
|
|
|
|
+ " Version suffixes must be the same.", |
|
|
|
|
gencodeVersionString, VERSION_STRING)); |
|
|
|
|
"Detected mismatched Protobuf Gencode/Runtime version suffixes when loading %s:" |
|
|
|
|
+ " gencode %s, runtime %s. Version suffixes must be the same.", |
|
|
|
|
location, gencodeVersionString, VERSION_STRING)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -126,4 +163,33 @@ public final class RuntimeVersion { |
|
|
|
|
private static String versionString(int major, int minor, int patch, String suffix) { |
|
|
|
|
return String.format("%d.%d.%d%s", major, minor, patch, suffix); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static boolean checkDisabled() { |
|
|
|
|
// Check the environmental variable, and temporarily disable validation if it's set to true.
|
|
|
|
|
String disableFlag = java.lang.System.getenv("TEMORARILY_DISABLE_PROTOBUF_VERSION_CHECK"); |
|
|
|
|
if ((disableFlag != null && disableFlag.equals("true"))) { |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** Verifies that only full or lite linkage exists. */ |
|
|
|
|
private static void preventFullAndLite(Fullness fullness, String location) { |
|
|
|
|
if (fullness != prevFullness && prevFullness != Fullness.UNSPECIFIED) { |
|
|
|
|
String message = |
|
|
|
|
"Protobuf Java version checker saw both Lite and Full linkages during runtime, which is" |
|
|
|
|
+ " disallowed. Full gencode @%s; Lite gencode @%s"; |
|
|
|
|
if (prevFullness == Fullness.FULL) { |
|
|
|
|
message = String.format(message, prevCheckedLocation, location); |
|
|
|
|
} else { |
|
|
|
|
message = String.format(message, location, prevCheckedLocation); |
|
|
|
|
} |
|
|
|
|
throw new ProtobufRuntimeVersionException(message); |
|
|
|
|
} |
|
|
|
|
prevFullness = fullness; |
|
|
|
|
prevCheckedLocation = location; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private RuntimeVersion() {} |
|
|
|
|
} |
|
|
|
|