Skip to content

Commit

Permalink
Breaking Change: Use Editions features in Java full runtimes.
Browse files Browse the repository at this point in the history
This change breaks compatibility with old generated code from previous major versions per the Cross Version Runtime policy: https://protobuf.dev/support/cross-version-runtime-guarantee. This includes old gencode from <4.26.x, which does not resolve features.

See https://protobuf.dev/news/2023-12-05/

PiperOrigin-RevId: 600487923
  • Loading branch information
zhangskz authored and copybara-github committed Jan 22, 2024
1 parent 040dde7 commit 65c65c2
Show file tree
Hide file tree
Showing 22 changed files with 1,263 additions and 152 deletions.
6 changes: 6 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,12 @@ alias(
visibility = ["//:__subpackages__"],
)

alias(
name = "test_proto_editions_srcs",
actual = "//src/google/protobuf:test_proto_editions_srcs", # filegroup
visibility = ["//:__subpackages__"],
)

alias(
name = "test_protos",
actual = "//src/google/protobuf:test_protos", # proto_library
Expand Down
2 changes: 2 additions & 0 deletions conformance/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,8 @@ java_binary(
"//:protobuf_java_util",
"//:test_messages_proto2_java_proto",
"//:test_messages_proto3_java_proto",
"//src/google/protobuf/editions:test_messages_proto2_editions_java_proto",
"//src/google/protobuf/editions:test_messages_proto3_editions_java_proto",
],
)

Expand Down
134 changes: 70 additions & 64 deletions conformance/ConformanceJava.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import com.google.protobuf.conformance.Conformance;
import com.google.protobuf.util.JsonFormat;
import com.google.protobuf.util.JsonFormat.TypeRegistry;
import com.google.protobuf_test_messages.editions.proto2.TestMessagesProto2Editions;
import com.google.protobuf_test_messages.editions.proto3.TestMessagesProto3Editions;
import com.google.protobuf_test_messages.proto2.TestMessagesProto2;
import com.google.protobuf_test_messages.proto2.TestMessagesProto2.TestAllTypesProto2;
import com.google.protobuf_test_messages.proto3.TestMessagesProto3;
Expand Down Expand Up @@ -205,42 +207,63 @@ private <T extends AbstractMessage> T parseBinary(
return messages.get(0);
}

private Class<? extends AbstractMessage> createTestMessage(String messageType) {
switch (messageType) {
case "protobuf_test_messages.proto3.TestAllTypesProto3":
return TestAllTypesProto3.class;
case "protobuf_test_messages.proto2.TestAllTypesProto2":
return TestAllTypesProto2.class;
case "protobuf_test_messages.editions.proto3.TestAllTypesProto3":
return TestMessagesProto3Editions.TestAllTypesProto3.class;
case "protobuf_test_messages.editions.proto2.TestAllTypesProto2":
return TestMessagesProto2Editions.TestAllTypesProto2.class;
default:
throw new IllegalArgumentException(
"Protobuf request has unexpected payload type: " + messageType);
}
}

private Class<?> createTestFile(String messageType) {
switch (messageType) {
case "protobuf_test_messages.proto3.TestAllTypesProto3":
return TestMessagesProto3.class;
case "protobuf_test_messages.proto2.TestAllTypesProto2":
return TestMessagesProto2.class;
case "protobuf_test_messages.editions.proto3.TestAllTypesProto3":
return TestMessagesProto3Editions.class;
case "protobuf_test_messages.editions.proto2.TestAllTypesProto2":
return TestMessagesProto2Editions.class;
default:
throw new IllegalArgumentException(
"Protobuf request has unexpected payload type: " + messageType);
}
}

@SuppressWarnings("unchecked")
private Conformance.ConformanceResponse doTest(Conformance.ConformanceRequest request) {
AbstractMessage testMessage;
String messageType = request.getMessageType();
boolean isProto3 = messageType.equals("protobuf_test_messages.proto3.TestAllTypesProto3");
boolean isProto2 = messageType.equals("protobuf_test_messages.proto2.TestAllTypesProto2");

switch (request.getPayloadCase()) {
case PROTOBUF_PAYLOAD:
{
if (isProto3) {
try {
ExtensionRegistry extensions = ExtensionRegistry.newInstance();
TestMessagesProto3.registerAllExtensions(extensions);
testMessage =
parseBinary(
request.getProtobufPayload(), TestAllTypesProto3.parser(), extensions);
} catch (InvalidProtocolBufferException e) {
return Conformance.ConformanceResponse.newBuilder()
.setParseError(e.getMessage())
.build();
}
} else if (isProto2) {
try {
ExtensionRegistry extensions = ExtensionRegistry.newInstance();
TestMessagesProto2.registerAllExtensions(extensions);
testMessage =
parseBinary(
request.getProtobufPayload(), TestAllTypesProto2.parser(), extensions);
} catch (InvalidProtocolBufferException e) {
return Conformance.ConformanceResponse.newBuilder()
.setParseError(e.getMessage())
.build();
}
} else {
throw new IllegalArgumentException(
"Protobuf request has unexpected payload type: " + messageType);
try {
ExtensionRegistry extensions = ExtensionRegistry.newInstance();
createTestFile(messageType)
.getMethod("registerAllExtensions", ExtensionRegistry.class)
.invoke(null, extensions);
testMessage =
parseBinary(
request.getProtobufPayload(),
(Parser<AbstractMessage>)
createTestMessage(messageType).getMethod("parser").invoke(null),
extensions);
} catch (InvalidProtocolBufferException e) {
return Conformance.ConformanceResponse.newBuilder()
.setParseError(e.getMessage())
.build();
} catch (Exception e) {
throw new RuntimeException(e);
}
break;
}
Expand All @@ -252,54 +275,34 @@ private Conformance.ConformanceResponse doTest(Conformance.ConformanceRequest re
== Conformance.TestCategory.JSON_IGNORE_UNKNOWN_PARSING_TEST) {
parser = parser.ignoringUnknownFields();
}
if (isProto3) {
TestMessagesProto3.TestAllTypesProto3.Builder builder =
TestMessagesProto3.TestAllTypesProto3.newBuilder();
parser.merge(request.getJsonPayload(), builder);
testMessage = builder.build();
} else if (isProto2) {
TestMessagesProto2.TestAllTypesProto2.Builder builder =
TestMessagesProto2.TestAllTypesProto2.newBuilder();
parser.merge(request.getJsonPayload(), builder);
testMessage = builder.build();
} else {
throw new IllegalArgumentException(
"Protobuf request has unexpected payload type: " + messageType);
}
AbstractMessage.Builder<?> builder =
(AbstractMessage.Builder<?>)
createTestMessage(messageType).getMethod("newBuilder").invoke(null);
parser.merge(request.getJsonPayload(), builder);
testMessage = (AbstractMessage) builder.build();
} catch (InvalidProtocolBufferException e) {
return Conformance.ConformanceResponse.newBuilder()
.setParseError(e.getMessage())
.build();
} catch (Exception e) {
throw new RuntimeException(e);
}
break;
}
case TEXT_PAYLOAD:
{
if (isProto3) {
try {
TestMessagesProto3.TestAllTypesProto3.Builder builder =
TestMessagesProto3.TestAllTypesProto3.newBuilder();
TextFormat.merge(request.getTextPayload(), builder);
testMessage = builder.build();
} catch (TextFormat.ParseException e) {
return Conformance.ConformanceResponse.newBuilder()
.setParseError(e.getMessage())
.build();
}
} else if (isProto2) {
try {
TestMessagesProto2.TestAllTypesProto2.Builder builder =
TestMessagesProto2.TestAllTypesProto2.newBuilder();
TextFormat.merge(request.getTextPayload(), builder);
testMessage = builder.build();
try {
AbstractMessage.Builder<?> builder =
(AbstractMessage.Builder<?>)
createTestMessage(messageType).getMethod("newBuilder").invoke(null);
TextFormat.merge(request.getTextPayload(), builder);
testMessage = (AbstractMessage) builder.build();
} catch (TextFormat.ParseException e) {
return Conformance.ConformanceResponse.newBuilder()
.setParseError(e.getMessage())
.build();
}
} else {
throw new IllegalArgumentException(
"Protobuf request has unexpected payload type: " + messageType);
} catch (Exception e) {
throw new RuntimeException(e);
}
break;
}
Expand Down Expand Up @@ -378,6 +381,9 @@ public void run() throws Exception {
typeRegistry =
TypeRegistry.newBuilder()
.add(TestMessagesProto3.TestAllTypesProto3.getDescriptor())
.add(
com.google.protobuf_test_messages.editions.proto3.TestMessagesProto3Editions
.TestAllTypesProto3.getDescriptor())
.build();
while (doTestIo()) {
this.testCount++;
Expand Down
73 changes: 72 additions & 1 deletion conformance/failure_list_java.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,75 @@ Required.Proto2.JsonInput.Int32FieldNegativeWithLeadingZero
Required.Proto2.JsonInput.Int32FieldPlusSign
Required.Proto2.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotBool
Required.Proto2.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
Required.Proto2.JsonInput.StringFieldNotAString
Required.Proto2.JsonInput.StringFieldNotAString
Recommended.Editions_Proto3.FieldMaskNumbersDontRoundTrip.JsonOutput
Recommended.Editions_Proto3.FieldMaskPathsDontRoundTrip.JsonOutput
Recommended.Editions_Proto3.FieldMaskTooManyUnderscore.JsonOutput
Recommended.Editions_Proto3.JsonInput.BoolFieldAllCapitalFalse
Recommended.Editions_Proto3.JsonInput.BoolFieldAllCapitalTrue
Recommended.Editions_Proto3.JsonInput.BoolFieldCamelCaseFalse
Recommended.Editions_Proto3.JsonInput.BoolFieldCamelCaseTrue
Recommended.Editions_Proto3.JsonInput.BoolFieldDoubleQuotedFalse
Recommended.Editions_Proto3.JsonInput.BoolFieldDoubleQuotedTrue
Recommended.Editions_Proto3.JsonInput.BoolMapFieldKeyNotQuoted
Recommended.Editions_Proto3.JsonInput.DoubleFieldInfinityNotQuoted
Recommended.Editions_Proto3.JsonInput.DoubleFieldNanNotQuoted
Recommended.Editions_Proto3.JsonInput.DoubleFieldNegativeInfinityNotQuoted
Recommended.Editions_Proto3.JsonInput.FieldMaskInvalidCharacter
Recommended.Editions_Proto3.JsonInput.FieldNameDuplicate
Recommended.Editions_Proto3.JsonInput.FieldNameNotQuoted
Recommended.Editions_Proto3.JsonInput.FloatFieldInfinityNotQuoted
Recommended.Editions_Proto3.JsonInput.FloatFieldNanNotQuoted
Recommended.Editions_Proto3.JsonInput.FloatFieldNegativeInfinityNotQuoted
Recommended.Editions_Proto3.JsonInput.Int32MapFieldKeyNotQuoted
Recommended.Editions_Proto3.JsonInput.Int64MapFieldKeyNotQuoted
Recommended.Editions_Proto3.JsonInput.JsonWithComments
Recommended.Editions_Proto3.JsonInput.StringFieldSingleQuoteBoth
Recommended.Editions_Proto3.JsonInput.StringFieldSingleQuoteKey
Recommended.Editions_Proto3.JsonInput.StringFieldSingleQuoteValue
Recommended.Editions_Proto3.JsonInput.StringFieldSurrogateInWrongOrder
Recommended.Editions_Proto3.JsonInput.StringFieldUnpairedHighSurrogate
Recommended.Editions_Proto3.JsonInput.StringFieldUnpairedLowSurrogate
Recommended.Editions_Proto3.JsonInput.Uint32MapFieldKeyNotQuoted
Recommended.Editions_Proto3.JsonInput.Uint64MapFieldKeyNotQuoted
Recommended.Editions_Proto2.JsonInput.FieldNameExtension.Validator
Required.Editions_Proto3.JsonInput.EnumFieldNotQuoted
Required.Editions_Proto3.JsonInput.Int32FieldLeadingZero
Required.Editions_Proto3.JsonInput.Int32FieldNegativeWithLeadingZero
Required.Editions_Proto3.JsonInput.Int32FieldPlusSign
Required.Editions_Proto3.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotBool
Required.Editions_Proto3.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
Required.Editions_Proto3.JsonInput.StringFieldNotAString
Recommended.Editions_Proto2.JsonInput.BoolFieldAllCapitalFalse
Recommended.Editions_Proto2.JsonInput.BoolFieldAllCapitalTrue
Recommended.Editions_Proto2.JsonInput.BoolFieldCamelCaseFalse
Recommended.Editions_Proto2.JsonInput.BoolFieldCamelCaseTrue
Recommended.Editions_Proto2.JsonInput.BoolFieldDoubleQuotedFalse
Recommended.Editions_Proto2.JsonInput.BoolFieldDoubleQuotedTrue
Recommended.Editions_Proto2.JsonInput.BoolMapFieldKeyNotQuoted
Recommended.Editions_Proto2.JsonInput.DoubleFieldInfinityNotQuoted
Recommended.Editions_Proto2.JsonInput.DoubleFieldNanNotQuoted
Recommended.Editions_Proto2.JsonInput.DoubleFieldNegativeInfinityNotQuoted
Recommended.Editions_Proto2.JsonInput.FieldNameDuplicate
Recommended.Editions_Proto2.JsonInput.FieldNameNotQuoted
Recommended.Editions_Proto2.JsonInput.FloatFieldInfinityNotQuoted
Recommended.Editions_Proto2.JsonInput.FloatFieldNanNotQuoted
Recommended.Editions_Proto2.JsonInput.FloatFieldNegativeInfinityNotQuoted
Recommended.Editions_Proto2.JsonInput.Int32MapFieldKeyNotQuoted
Recommended.Editions_Proto2.JsonInput.Int64MapFieldKeyNotQuoted
Recommended.Editions_Proto2.JsonInput.JsonWithComments
Recommended.Editions_Proto2.JsonInput.StringFieldSingleQuoteBoth
Recommended.Editions_Proto2.JsonInput.StringFieldSingleQuoteKey
Recommended.Editions_Proto2.JsonInput.StringFieldSingleQuoteValue
Recommended.Editions_Proto2.JsonInput.StringFieldSurrogateInWrongOrder
Recommended.Editions_Proto2.JsonInput.StringFieldUnpairedHighSurrogate
Recommended.Editions_Proto2.JsonInput.StringFieldUnpairedLowSurrogate
Recommended.Editions_Proto2.JsonInput.Uint32MapFieldKeyNotQuoted
Recommended.Editions_Proto2.JsonInput.Uint64MapFieldKeyNotQuoted
Required.Editions_Proto2.JsonInput.EnumFieldNotQuoted
Required.Editions_Proto2.JsonInput.Int32FieldLeadingZero
Required.Editions_Proto2.JsonInput.Int32FieldNegativeWithLeadingZero
Required.Editions_Proto2.JsonInput.Int32FieldPlusSign
Required.Editions_Proto2.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotBool
Required.Editions_Proto2.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
Required.Editions_Proto2.JsonInput.StringFieldNotAString
8 changes: 8 additions & 0 deletions conformance/text_format_failure_list_java.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ Recommended.Proto3.ProtobufInput.RepeatedUnknownFields_Drop.TextFormatOutput
Recommended.Proto3.ProtobufInput.ScalarUnknownFields_Drop.TextFormatOutput
Required.Proto3.TextFormatInput.AnyField.ProtobufOutput
Required.Proto3.TextFormatInput.AnyField.TextFormatOutput
Recommended.Editions_Proto3.ProtobufInput.GroupUnknownFields_Drop.TextFormatOutput
Recommended.Editions_Proto3.ProtobufInput.MessageUnknownFields_Drop.TextFormatOutput
Recommended.Editions_Proto3.ProtobufInput.RepeatedUnknownFields_Drop.TextFormatOutput
Recommended.Editions_Proto3.ProtobufInput.ScalarUnknownFields_Drop.TextFormatOutput
Required.Editions_Proto3.TextFormatInput.AnyField.ProtobufOutput
Required.Editions_Proto3.TextFormatInput.AnyField.TextFormatOutput

Required.Proto3.TextFormatInput.StringFieldBadUTF8Hex
Required.Proto3.TextFormatInput.StringFieldBadUTF8Octal
Required.Editions_Proto3.TextFormatInput.StringFieldBadUTF8Hex
Required.Editions_Proto3.TextFormatInput.StringFieldBadUTF8Octal
22 changes: 22 additions & 0 deletions java/core/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ load("//:protobuf_version.bzl", "PROTOBUF_JAVA_VERSION")
load("//build_defs:java_opts.bzl", "protobuf_java_export", "protobuf_java_library", "protobuf_versioned_java_library")
load("//conformance:defs.bzl", "conformance_test")
load("//java/internal:testing.bzl", "junit_tests")
load("//src/google/protobuf/editions:defaults.bzl", "compile_edition_defaults", "embed_edition_defaults")

LITE_SRCS = [
# Keep in sync with `//java/lite:pom.xml`.
Expand Down Expand Up @@ -168,13 +169,21 @@ protobuf_java_library(
proto_library(
name = "java_features_proto",
srcs = ["src/main/java/com/google/protobuf/java_features.proto"],
strip_import_prefix = "/java/core/src/main/java/com",
visibility = ["//pkg:__pkg__"],
deps = ["//:descriptor_proto"],
)

filegroup(
name = "java_features_proto_srcs",
srcs = ["src/main/java/com/google/protobuf/java_features.proto"],
visibility = ["//pkg:__pkg__"],
)

internal_gen_well_known_protos_java(
name = "gen_well_known_protos_java",
deps = [
":java_features_proto",
"//:any_proto",
"//:api_proto",
"//:compiler_plugin_proto",
Expand Down Expand Up @@ -240,6 +249,7 @@ protobuf_java_export(
maven_coordinates = "com.google.protobuf:protobuf-java:%s" % PROTOBUF_JAVA_VERSION,
pom_template = "pom_template.xml",
resources = [
":java_features_proto_srcs",
"//:well_known_type_protos",
"//src/google/protobuf:descriptor_proto_srcs",
],
Expand All @@ -266,6 +276,7 @@ proto_lang_toolchain(
name = "toolchain",
# keep this in sync w/ WELL_KNOWN_PROTO_MAP in //:BUILD
blacklisted_protos = [
":java_features_proto",
"//:any_proto",
"//:api_proto",
"//:compiler_plugin_proto",
Expand Down Expand Up @@ -305,6 +316,14 @@ java_proto_library(
deps = ["//src/google/protobuf:generic_test_protos"],
)

java_proto_library(
name = "generic_test_protos_editions_java_proto",
visibility = [
"//java:__subpackages__",
],
deps = ["//src/google/protobuf:generic_test_editions_protos"],
)

java_proto_library(
name = "lite_test_protos_java_proto",
visibility = [
Expand Down Expand Up @@ -355,6 +374,7 @@ build_test(
conformance_test(
name = "conformance_test",
failure_list = "//conformance:failure_list_java.txt",
maximum_edition = "2023",
testee = "//conformance:conformance_java",
text_format_failure_list = "//conformance:text_format_failure_list_java.txt",
)
Expand All @@ -374,6 +394,7 @@ junit_tests(
data = ["//src/google/protobuf:testdata"],
deps = [
":core",
":generic_test_protos_editions_java_proto",
":generic_test_protos_java_proto",
":java_test_protos_java_proto",
":lite_test_protos_java_proto",
Expand Down Expand Up @@ -531,6 +552,7 @@ pkg_files(
name = "dist_files",
srcs = glob([
"src/main/java/com/google/protobuf/*.java",
"src/main/java/com/google/protobuf/*.proto",
"src/test/java/**/*.java",
"src/test/proto/**/*.proto",
]) + [
Expand Down
2 changes: 2 additions & 0 deletions java/core/generate-sources-build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
<exec executable="${protoc}">
<arg value="--java_out=${generated.sources.dir}"/>
<arg value="--proto_path=${protobuf.source.dir}"/>
<arg value="--proto_path=${protobuf.java_source.dir}"/>
<arg value="${protobuf.java_source.dir}/main/java/com/google/protobuf/java_features.proto"/>
<arg value="${protobuf.source.dir}/google/protobuf/any.proto"/>
<arg value="${protobuf.source.dir}/google/protobuf/api.proto"/>
<arg value="${protobuf.source.dir}/google/protobuf/descriptor.proto"/>
Expand Down
Loading

0 comments on commit 65c65c2

Please sign in to comment.