diff --git a/java/core/BUILD.bazel b/java/core/BUILD.bazel index ace209190b..92d9982815 100644 --- a/java/core/BUILD.bazel +++ b/java/core/BUILD.bazel @@ -389,6 +389,7 @@ junit_tests( "src/test/java/com/google/protobuf/IsValidUtf8Test.java", "src/test/java/com/google/protobuf/TestUtil.java", "src/test/java/com/google/protobuf/TestUtilLite.java", + "src/test/java/com/google/protobuf/RuntimeVersionTest.java", ], ), data = ["//src/google/protobuf:testdata"], @@ -508,7 +509,6 @@ LITE_TEST_EXCLUSIONS = [ "src/test/java/com/google/protobuf/Proto2SchemaTest.java", "src/test/java/com/google/protobuf/Proto2UnknownEnumValueTest.java", "src/test/java/com/google/protobuf/RepeatedFieldBuilderTest.java", - "src/test/java/com/google/protobuf/RuntimeVersionTest.java", "src/test/java/com/google/protobuf/ServiceTest.java", "src/test/java/com/google/protobuf/SingleFieldBuilderTest.java", "src/test/java/com/google/protobuf/TestBadIdentifiers.java", diff --git a/java/core/src/main/java/com/google/protobuf/RuntimeVersion.java b/java/core/src/main/java/com/google/protobuf/RuntimeVersion.java index 1d1bdeca22..2e56f6af5e 100644 --- a/java/core/src/main/java/com/google/protobuf/RuntimeVersion.java +++ b/java/core/src/main/java/com/google/protobuf/RuntimeVersion.java @@ -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/. * - *
This method will be directly called by the google-internal gencode to verify no cross-domain - * usages. + *
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/. * - *
This method is currently only used by Protobuf Java gencode in OSS. - * - *
This method is only for Protobuf Java gencode; do not call it elsewhere. + *
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() {}
}
diff --git a/java/core/src/test/java/com/google/protobuf/RuntimeVersionTest.java b/java/core/src/test/java/com/google/protobuf/RuntimeVersionTest.java
index 0ec4318b01..d34cf453b7 100644
--- a/java/core/src/test/java/com/google/protobuf/RuntimeVersionTest.java
+++ b/java/core/src/test/java/com/google/protobuf/RuntimeVersionTest.java
@@ -23,27 +23,25 @@ public final class RuntimeVersionTest {
assertThrows(
RuntimeVersion.ProtobufRuntimeVersionException.class,
() ->
- RuntimeVersion.validateProtobufGencodeVersion(
- RuntimeVersion.DOMAIN, 1, -2, -3, ""));
+ RuntimeVersion.validateProtobufLiteGencodeVersion(
+ RuntimeVersion.DOMAIN, 1, -2, -3, "", "dummy"));
assertThat(thrown).hasMessageThat().contains("Invalid gencode version: 1.-2.-3");
}
@Test
public void versionValidation_crossDomainDisallowed() {
- RuntimeVersion.RuntimeDomain gencodeDomain = RuntimeVersion.RuntimeDomain.GOOGLE_INTERNAL;
+ RuntimeVersion.RuntimeDomain gencodeDomain =
+ RuntimeVersion.RuntimeDomain.GOOGLE_INTERNAL;
RuntimeVersion.ProtobufRuntimeVersionException thrown =
assertThrows(
RuntimeVersion.ProtobufRuntimeVersionException.class,
- () -> RuntimeVersion.validateProtobufGencodeDomain(gencodeDomain));
- assertThat(thrown).hasMessageThat().contains("Mismatched Protobuf Gencode/Runtime domains");
- }
-
- @Test
- public void versionValidation_sameDomainAllowed() {
-
- RuntimeVersion.RuntimeDomain gencodeDomain = RuntimeVersion.RuntimeDomain.PUBLIC;
- RuntimeVersion.validateProtobufGencodeDomain(gencodeDomain);
+ () ->
+ RuntimeVersion.validateProtobufLiteGencodeVersion(
+ gencodeDomain, 1, 2, 3, "", "testing.Foo"));
+ assertThat(thrown)
+ .hasMessageThat()
+ .contains("Detected mismatched Protobuf Gencode/Runtime domains when loading testing.Foo");
}
@Test
@@ -53,36 +51,40 @@ public final class RuntimeVersionTest {
assertThrows(
RuntimeVersion.ProtobufRuntimeVersionException.class,
() ->
- RuntimeVersion.validateProtobufGencodeVersion(
+ RuntimeVersion.validateProtobufLiteGencodeVersion(
RuntimeVersion.DOMAIN,
gencodeMajor,
RuntimeVersion.MINOR,
RuntimeVersion.PATCH,
- RuntimeVersion.SUFFIX));
+ RuntimeVersion.SUFFIX,
+ "testing.Foo"));
assertThat(thrown)
.hasMessageThat()
- .contains("Mismatched Protobuf Gencode/Runtime major versions");
+ .contains(
+ "Detected mismatched Protobuf Gencode/Runtime major versions when loading testing.Foo");
}
@Test
public void versionValidation_versionNumbersAllTheSameAllowed() {
- RuntimeVersion.validateProtobufGencodeVersion(
+ RuntimeVersion.validateProtobufLiteGencodeVersion(
RuntimeVersion.DOMAIN,
RuntimeVersion.MAJOR,
RuntimeVersion.MINOR,
RuntimeVersion.PATCH,
- RuntimeVersion.SUFFIX);
+ RuntimeVersion.SUFFIX,
+ "dummy");
}
@Test
public void versionValidation_newerRuntimeVersionAllowed() {
int gencodeMinor = RuntimeVersion.MINOR - 1;
- RuntimeVersion.validateProtobufGencodeVersion(
+ RuntimeVersion.validateProtobufLiteGencodeVersion(
RuntimeVersion.DOMAIN,
RuntimeVersion.MAJOR,
gencodeMinor,
RuntimeVersion.PATCH,
- RuntimeVersion.SUFFIX);
+ RuntimeVersion.SUFFIX,
+ "dummy");
}
@Test
@@ -92,35 +94,67 @@ public final class RuntimeVersionTest {
assertThrows(
RuntimeVersion.ProtobufRuntimeVersionException.class,
() ->
- RuntimeVersion.validateProtobufGencodeVersion(
+ RuntimeVersion.validateProtobufLiteGencodeVersion(
RuntimeVersion.DOMAIN,
RuntimeVersion.MAJOR,
gencodeMinor,
RuntimeVersion.PATCH,
- RuntimeVersion.SUFFIX));
+ RuntimeVersion.SUFFIX,
+ "testing.Foo"));
assertThat(thrown)
.hasMessageThat()
- .contains("Protobuf Java runtime version cannot be older than the gencode version");
+ .contains(
+ "Detected incompatible Protobuf Gencode/Runtime versions when loading testing.Foo");
int gencodePatch = RuntimeVersion.PATCH + 1;
thrown =
assertThrows(
RuntimeVersion.ProtobufRuntimeVersionException.class,
() ->
- RuntimeVersion.validateProtobufGencodeVersion(
+ RuntimeVersion.validateProtobufLiteGencodeVersion(
RuntimeVersion.DOMAIN,
RuntimeVersion.MAJOR,
RuntimeVersion.MINOR,
gencodePatch,
- RuntimeVersion.SUFFIX));
+ RuntimeVersion.SUFFIX,
+ "testing.Bar"));
assertThat(thrown)
.hasMessageThat()
- .contains("Protobuf Java runtime version cannot be older than the gencode version");
+ .contains(
+ "Detected incompatible Protobuf Gencode/Runtime versions when loading testing.Bar");
}
@Test
public void versionValidation_differentVesionSuffixDisallowed() {
String gencodeSuffix = "-test";
+ RuntimeVersion.ProtobufRuntimeVersionException thrown =
+ assertThrows(
+ RuntimeVersion.ProtobufRuntimeVersionException.class,
+ () ->
+ RuntimeVersion.validateProtobufLiteGencodeVersion(
+ RuntimeVersion.DOMAIN,
+ RuntimeVersion.MAJOR,
+ RuntimeVersion.MINOR,
+ RuntimeVersion.PATCH,
+ gencodeSuffix,
+ "testing.Foo"));
+ assertThat(thrown)
+ .hasMessageThat()
+ .contains(
+ "Detected mismatched Protobuf Gencode/Runtime version suffixes when loading"
+ + " testing.Foo");
+ }
+
+ @Test
+ public void versionValidation_illegalLiteAndThenFullLinkage() {
+ RuntimeVersion.prevFullness = RuntimeVersion.Fullness.UNSPECIFIED;
+ RuntimeVersion.validateProtobufLiteGencodeVersion(
+ RuntimeVersion.DOMAIN,
+ RuntimeVersion.MAJOR,
+ RuntimeVersion.MINOR,
+ RuntimeVersion.PATCH,
+ RuntimeVersion.SUFFIX,
+ "testing.Foo");
RuntimeVersion.ProtobufRuntimeVersionException thrown =
assertThrows(
RuntimeVersion.ProtobufRuntimeVersionException.class,
@@ -130,9 +164,42 @@ public final class RuntimeVersionTest {
RuntimeVersion.MAJOR,
RuntimeVersion.MINOR,
RuntimeVersion.PATCH,
- gencodeSuffix));
+ RuntimeVersion.SUFFIX,
+ "testing.Bar"));
+ assertThat(thrown)
+ .hasMessageThat()
+ .contains(
+ "Protobuf Java version checker saw both Lite and Full linkages during runtime, which is"
+ + " disallowed. Full gencode @testing.Bar; Lite gencode @testing.Foo");
+ RuntimeVersion.prevFullness = RuntimeVersion.Fullness.UNSPECIFIED;
+ }
+
+ @Test
+ public void versionValidation_illegalFullAndThenLiteLinkage_warning() {
+ RuntimeVersion.prevFullness = RuntimeVersion.Fullness.UNSPECIFIED;
+ RuntimeVersion.validateProtobufGencodeVersion(
+ RuntimeVersion.DOMAIN,
+ RuntimeVersion.MAJOR,
+ RuntimeVersion.MINOR,
+ RuntimeVersion.PATCH,
+ RuntimeVersion.SUFFIX,
+ "testing.Foo");
+ RuntimeVersion.ProtobufRuntimeVersionException thrown =
+ assertThrows(
+ RuntimeVersion.ProtobufRuntimeVersionException.class,
+ () ->
+ RuntimeVersion.validateProtobufLiteGencodeVersion(
+ RuntimeVersion.DOMAIN,
+ RuntimeVersion.MAJOR,
+ RuntimeVersion.MINOR,
+ RuntimeVersion.PATCH,
+ RuntimeVersion.SUFFIX,
+ "testing.Bar"));
assertThat(thrown)
.hasMessageThat()
- .contains("Mismatched Protobuf Gencode/Runtime version suffixes");
+ .contains(
+ "Protobuf Java version checker saw both Lite and Full linkages during runtime, which is"
+ + " disallowed. Full gencode @testing.Foo; Lite gencode @testing.Bar");
+ RuntimeVersion.prevFullness = RuntimeVersion.Fullness.UNSPECIFIED;
}
}
diff --git a/src/google/protobuf/compiler/java/enum.cc b/src/google/protobuf/compiler/java/enum.cc
index 96dc02f091..da906420db 100644
--- a/src/google/protobuf/compiler/java/enum.cc
+++ b/src/google/protobuf/compiler/java/enum.cc
@@ -113,7 +113,8 @@ void EnumGenerator::Generate(io::Printer* printer) {
printer->Print("static {\n");
printer->Indent();
- PrintGencodeVersionValidator(printer, context_->options().opensource_runtime);
+ PrintGencodeVersionValidator(printer, context_->options().opensource_runtime,
+ context_->EnforceLite(), descriptor_->name());
printer->Outdent();
printer->Print("}\n");
diff --git a/src/google/protobuf/compiler/java/file.cc b/src/google/protobuf/compiler/java/file.cc
index 49d1438e8a..0ea3e12cd2 100644
--- a/src/google/protobuf/compiler/java/file.cc
+++ b/src/google/protobuf/compiler/java/file.cc
@@ -275,7 +275,8 @@ void FileGenerator::Generate(io::Printer* printer) {
printer->Print("static {\n");
printer->Indent();
- PrintGencodeVersionValidator(printer, options_.opensource_runtime);
+ PrintGencodeVersionValidator(printer, options_.opensource_runtime,
+ context_->EnforceLite(), classname_);
printer->Outdent();
printer->Print("}\n");
diff --git a/src/google/protobuf/compiler/java/helpers.cc b/src/google/protobuf/compiler/java/helpers.cc
index 7f44422124..e4c3fc473f 100644
--- a/src/google/protobuf/compiler/java/helpers.cc
+++ b/src/google/protobuf/compiler/java/helpers.cc
@@ -85,20 +85,27 @@ void PrintEnumVerifierLogic(
absl::StrCat(enum_verifier_string, terminating_string));
}
-void PrintGencodeVersionValidator(io::Printer* printer, bool oss_runtime) {
+void PrintGencodeVersionValidator(io::Printer* printer, bool oss_runtime,
+ bool enforce_lite,
+ absl::string_view java_class_name) {
if (oss_runtime) {
const auto& version = GetProtobufJavaVersion();
printer->Print(
- "com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion(\n"
+ "com.google.protobuf.RuntimeVersion.validateProtobuf$lite$"
+ "GencodeVersion("
+ "\n"
" com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC,\n"
" $major$,\n"
" $minor$,\n"
" $patch$,\n"
- " $suffix$);\n",
- "major", absl::StrCat("/* major= */ ", version.major()), "minor",
+ " $suffix$,\n"
+ " $location$);\n",
+ "lite", enforce_lite ? "Lite" : "", "major",
+ absl::StrCat("/* major= */ ", version.major()), "minor",
absl::StrCat("/* minor= */ ", version.minor()), "patch",
absl::StrCat("/* patch= */ ", version.patch()), "suffix",
- absl::StrCat("/* suffix= */ \"", version.suffix(), "\""));
+ absl::StrCat("/* suffix= */ \"", version.suffix(), "\""), "location",
+ absl::StrCat(java_class_name, ".class.getName()"));
} else {
printer->Print(
"com.google.protobuf.RuntimeVersion.validateProtobufGencodeDomain(\n"
diff --git a/src/google/protobuf/compiler/java/helpers.h b/src/google/protobuf/compiler/java/helpers.h
index 33fc9675ba..74de26f8bc 100644
--- a/src/google/protobuf/compiler/java/helpers.h
+++ b/src/google/protobuf/compiler/java/helpers.h
@@ -61,7 +61,9 @@ void PrintEnumVerifierLogic(
// Prints the Protobuf Java Version validator checking that the runtime and
// gencode versions are compatible.
-void PrintGencodeVersionValidator(io::Printer* printer, bool oss_runtime);
+void PrintGencodeVersionValidator(io::Printer* printer, bool oss_runtime,
+ bool enforce_lite,
+ absl::string_view java_class_name);
// Converts a name to camel-case. If cap_first_letter is true, capitalize the
// first letter.
diff --git a/src/google/protobuf/compiler/java/message.cc b/src/google/protobuf/compiler/java/message.cc
index 01ec4a6063..3958a46650 100644
--- a/src/google/protobuf/compiler/java/message.cc
+++ b/src/google/protobuf/compiler/java/message.cc
@@ -335,7 +335,8 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) {
printer->Print("static {\n");
printer->Indent();
- PrintGencodeVersionValidator(printer, context_->options().opensource_runtime);
+ PrintGencodeVersionValidator(printer, context_->options().opensource_runtime,
+ context_->EnforceLite(), descriptor_->name());
printer->Outdent();
printer->Print("}\n");
diff --git a/src/google/protobuf/compiler/java/message_lite.cc b/src/google/protobuf/compiler/java/message_lite.cc
index 0eb672d09b..2c23d9cb33 100644
--- a/src/google/protobuf/compiler/java/message_lite.cc
+++ b/src/google/protobuf/compiler/java/message_lite.cc
@@ -181,6 +181,16 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) {
printer->Annotate("{", "}", descriptor_);
printer->Indent();
+ if (context_->options().opensource_runtime) {
+ printer->Print("static {\n");
+ printer->Indent();
+ PrintGencodeVersionValidator(printer,
+ context_->options().opensource_runtime,
+ context_->EnforceLite(), descriptor_->name());
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+
GenerateConstructor(printer);
// Nested types
diff --git a/src/google/protobuf/compiler/java/shared_code_generator.cc b/src/google/protobuf/compiler/java/shared_code_generator.cc
index 6015f3b542..5270e697e9 100644
--- a/src/google/protobuf/compiler/java/shared_code_generator.cc
+++ b/src/google/protobuf/compiler/java/shared_code_generator.cc
@@ -12,6 +12,7 @@
#include