Skip to content

Commit 48db33c

Browse files
Add LegacyProtoTypeAdapterFactory. (#3014)
* Add `LegacyProtoTypeAdapterFactory`. This is a migration aid for code that is currently accidentally relying on `ReflectiveTypeAdapterFactory` to serialize and/or deserialize protobuf messages. Such code depends on the internal details of how protobuf messages are represented as Java objects, and can break if those details change. This adapter freezes a particular representation and allows code to become independent of future changes. We do not recommend this for anything other than managing legacy code that may have come to rely on a particular JSON format. * Add copyright notices. * Fix a warning about exhaustive enum switches. * Turn off Android compatibility check for proto subproject. * Fix formatting errors. * Fix another warning. * Address a potential overflow problem. This is pretty theoretical, but github-advanced-security flagged it.
1 parent 53d703e commit 48db33c

7 files changed

Lines changed: 1585 additions & 1 deletion

File tree

.github/workflows/check-android-compatibility.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,4 @@ jobs:
3535

3636
- name: Check Android compatibility
3737
run: |
38-
mvn compile animal-sniffer:check@check-android-compatibility -Dmaven.test.skip --projects '!metrics,!test-graal-native-image,!test-jpms,!test-shrinker'
38+
mvn compile animal-sniffer:check@check-android-compatibility -Dmaven.test.skip --projects '!metrics,!proto,!test-graal-native-image,!test-jpms,!test-shrinker'

proto/pom.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,18 @@
7070
<artifactId>truth</artifactId>
7171
<scope>test</scope>
7272
</dependency>
73+
<dependency>
74+
<groupId>com.google.truth.extensions</groupId>
75+
<artifactId>truth-proto-extension</artifactId>
76+
<version>1.4.5</version>
77+
<scope>test</scope>
78+
</dependency>
79+
<dependency>
80+
<groupId>com.google.testparameterinjector</groupId>
81+
<artifactId>test-parameter-injector</artifactId>
82+
<version>1.22</version>
83+
<scope>test</scope>
84+
</dependency>
7385
</dependencies>
7486

7587
<build>

proto/src/main/java/com/google/gson/protobuf/LegacyProtoTypeAdapterFactory.java

Lines changed: 691 additions & 0 deletions
Large diffs are not rendered by default.

proto/src/test/java/com/google/gson/protobuf/functional/LegacyProtoTypeAdapterFactoryTest.java

Lines changed: 469 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright (C) 2026 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.google.gson.protobuf.functional;
17+
18+
import com.google.gson.protobuf.TestAllTypes;
19+
import com.google.gson.protobuf.TestAllTypes.NestedEnum;
20+
import com.google.gson.protobuf.TestRecursive;
21+
import com.google.protobuf.ByteString;
22+
23+
/** Helper class for creating test messages. */
24+
final class TestMessages {
25+
26+
static TestAllTypes testAllTypes() {
27+
TestAllTypes.Builder builder = TestAllTypes.newBuilder();
28+
builder.setOptionalInt32(1234);
29+
builder.setOptionalInt64(1234567890123456789L);
30+
builder.setOptionalUint32(-1);
31+
builder.setOptionalUint64(-1L);
32+
builder.setOptionalSint32(9012);
33+
builder.setOptionalSint64(3456789012345678901L);
34+
builder.setOptionalFixed32(3456);
35+
builder.setOptionalFixed64(4567890123456789012L);
36+
builder.setOptionalSfixed32(7890);
37+
builder.setOptionalSfixed64(5678901234567890123L);
38+
builder.setOptionalFloat(1.5f);
39+
builder.setOptionalDouble(1.25);
40+
builder.setOptionalBool(true);
41+
builder.setOptionalString("Hello world!");
42+
builder.setOptionalBytes(ByteString.copyFrom(new byte[] {0, 1, -2}));
43+
builder.setOptionalNestedEnum(NestedEnum.BAR);
44+
builder.setOptionalRecursive(
45+
TestRecursive.newBuilder()
46+
.setValue(100)
47+
.setNested(TestRecursive.newBuilder().setValue(200)));
48+
builder.getOptionalNestedMessageBuilder().setValue(100);
49+
50+
builder.addRepeatedInt32(1234);
51+
builder.addRepeatedInt64(1234567890123456789L);
52+
builder.addRepeatedUint32(5678);
53+
builder.addRepeatedUint64(2345678901234567890L);
54+
builder.addRepeatedSint32(9012);
55+
builder.addRepeatedSint64(3456789012345678901L);
56+
builder.addRepeatedFixed32(3456);
57+
builder.addRepeatedFixed64(4567890123456789012L);
58+
builder.addRepeatedSfixed32(7890);
59+
builder.addRepeatedSfixed64(5678901234567890123L);
60+
builder.addRepeatedFloat(1.5f);
61+
builder.addRepeatedDouble(1.25);
62+
builder.addRepeatedBool(true);
63+
builder.addRepeatedString("Hello world!");
64+
builder.addRepeatedBytes(ByteString.copyFrom(new byte[] {0, 1, 2}));
65+
builder.addRepeatedNestedEnum(NestedEnum.BAR);
66+
builder.addRepeatedNestedMessageBuilder().setValue(100);
67+
68+
builder.addRepeatedInt32(234);
69+
builder.addRepeatedInt64(234567890123456789L);
70+
builder.addRepeatedUint32(678);
71+
builder.addRepeatedUint64(345678901234567890L);
72+
builder.addRepeatedSint32(012);
73+
builder.addRepeatedSint64(456789012345678901L);
74+
builder.addRepeatedFixed32(456);
75+
builder.addRepeatedFixed64(567890123456789012L);
76+
builder.addRepeatedSfixed32(890);
77+
builder.addRepeatedSfixed64(678901234567890123L);
78+
builder.addRepeatedFloat(11.5f);
79+
builder.addRepeatedDouble(11.25);
80+
builder.addRepeatedBool(true);
81+
builder.addRepeatedString("ello world!");
82+
builder.addRepeatedBytes(ByteString.copyFrom(new byte[] {1, 2}));
83+
builder.addRepeatedNestedEnum(NestedEnum.BAZ);
84+
builder.addRepeatedNestedMessageBuilder().setValue(200);
85+
86+
return builder.build();
87+
}
88+
89+
private TestMessages() {}
90+
}
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
/*
2+
* Copyright (C) 2026 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
syntax = "proto3";
18+
19+
package com.google.gson.protobuf;
20+
21+
import "google/protobuf/any.proto";
22+
import "google/protobuf/duration.proto";
23+
import "google/protobuf/field_mask.proto";
24+
import "google/protobuf/struct.proto";
25+
import "google/protobuf/timestamp.proto";
26+
import "google/protobuf/wrappers.proto";
27+
28+
option java_package = "com.google.gson.protobuf";
29+
option java_outer_classname = "JsonTestProto";
30+
option java_multiple_files = true;
31+
32+
message TestAllTypes {
33+
enum NestedEnum {
34+
FOO = 0;
35+
BAR = 1;
36+
BAZ = 2;
37+
}
38+
39+
enum AliasedEnum {
40+
option allow_alias = true;
41+
42+
ALIAS_FOO = 0;
43+
ALIAS_BAR = 1;
44+
ALIAS_BAZ = 2;
45+
QUX = 2;
46+
qux = 2;
47+
bAz = 2;
48+
}
49+
message NestedMessage {
50+
int32 value = 1;
51+
}
52+
53+
int32 optional_int32 = 1;
54+
int64 optional_int64 = 2;
55+
uint32 optional_uint32 = 3;
56+
uint64 optional_uint64 = 4;
57+
sint32 optional_sint32 = 5;
58+
sint64 optional_sint64 = 6;
59+
fixed32 optional_fixed32 = 7;
60+
fixed64 optional_fixed64 = 8;
61+
sfixed32 optional_sfixed32 = 9;
62+
sfixed64 optional_sfixed64 = 10;
63+
float optional_float = 11;
64+
double optional_double = 12;
65+
bool optional_bool = 13;
66+
string optional_string = 14;
67+
bytes optional_bytes = 15;
68+
NestedMessage optional_nested_message = 18;
69+
NestedEnum optional_nested_enum = 21;
70+
AliasedEnum optional_aliased_enum = 52;
71+
TestRecursive optional_recursive = 53;
72+
73+
optional int32 explicit_presence_int32 = 54;
74+
75+
// Repeated
76+
repeated int32 repeated_int32 = 31;
77+
repeated int64 repeated_int64 = 32;
78+
repeated uint32 repeated_uint32 = 33;
79+
repeated uint64 repeated_uint64 = 34;
80+
repeated sint32 repeated_sint32 = 35;
81+
repeated sint64 repeated_sint64 = 36;
82+
repeated fixed32 repeated_fixed32 = 37;
83+
repeated fixed64 repeated_fixed64 = 38;
84+
repeated sfixed32 repeated_sfixed32 = 39;
85+
repeated sfixed64 repeated_sfixed64 = 40;
86+
repeated float repeated_float = 41;
87+
repeated double repeated_double = 42;
88+
repeated bool repeated_bool = 43;
89+
repeated string repeated_string = 44;
90+
repeated bytes repeated_bytes = 45;
91+
repeated NestedMessage repeated_nested_message = 48;
92+
repeated NestedEnum repeated_nested_enum = 51;
93+
repeated TestRecursive repeated_recursive = 55;
94+
}
95+
96+
message TestOneof {
97+
oneof oneof_field {
98+
int32 oneof_int32 = 1;
99+
TestAllTypes.NestedMessage oneof_nested_message = 2;
100+
.google.protobuf.NullValue oneof_null_value = 3;
101+
string oneof_string = 4;
102+
}
103+
}
104+
105+
message TestMap {
106+
// Instead of testing all combinations (too many), we only make sure all
107+
// valid types have been used at least in one field as key and in one
108+
// field as value.
109+
map<int32, int32> int32_to_int32_map = 1;
110+
map<int64, int32> int64_to_int32_map = 2;
111+
map<uint32, int32> uint32_to_int32_map = 3;
112+
map<uint64, int32> uint64_to_int32_map = 4;
113+
map<sint32, int32> sint32_to_int32_map = 5;
114+
map<sint64, int32> sint64_to_int32_map = 6;
115+
map<fixed32, int32> fixed32_to_int32_map = 7;
116+
map<fixed64, int32> fixed64_to_int32_map = 8;
117+
map<sfixed32, int32> sfixed32_to_int32_map = 9;
118+
map<sfixed64, int32> sfixed64_to_int32_map = 10;
119+
map<bool, int32> bool_to_int32_map = 11;
120+
map<string, int32> string_to_int32_map = 12;
121+
122+
map<int32, int64> int32_to_int64_map = 101;
123+
map<int32, uint32> int32_to_uint32_map = 102;
124+
map<int32, uint64> int32_to_uint64_map = 103;
125+
map<int32, sint32> int32_to_sint32_map = 104;
126+
map<int32, sint64> int32_to_sint64_map = 105;
127+
map<int32, fixed32> int32_to_fixed32_map = 106;
128+
map<int32, fixed64> int32_to_fixed64_map = 107;
129+
map<int32, sfixed32> int32_to_sfixed32_map = 108;
130+
map<int32, sfixed64> int32_to_sfixed64_map = 109;
131+
map<int32, float> int32_to_float_map = 110;
132+
map<int32, double> int32_to_double_map = 111;
133+
map<int32, bool> int32_to_bool_map = 112;
134+
map<int32, string> int32_to_string_map = 113;
135+
map<int32, bytes> int32_to_bytes_map = 114;
136+
map<int32, TestAllTypes.NestedMessage> int32_to_message_map = 115;
137+
map<int32, TestAllTypes.NestedEnum> int32_to_enum_map = 116;
138+
}
139+
140+
message TestWrappers {
141+
.google.protobuf.Int32Value int32_value = 1;
142+
.google.protobuf.UInt32Value uint32_value = 2;
143+
.google.protobuf.Int64Value int64_value = 3;
144+
.google.protobuf.UInt64Value uint64_value = 4;
145+
.google.protobuf.FloatValue float_value = 5;
146+
.google.protobuf.DoubleValue double_value = 6;
147+
.google.protobuf.BoolValue bool_value = 7;
148+
.google.protobuf.StringValue string_value = 8;
149+
.google.protobuf.BytesValue bytes_value = 9;
150+
}
151+
152+
message TestTimestamp {
153+
.google.protobuf.Timestamp timestamp_value = 1;
154+
}
155+
156+
message TestDuration {
157+
.google.protobuf.Duration duration_value = 1;
158+
}
159+
160+
message TestFieldMask {
161+
.google.protobuf.FieldMask field_mask_value = 1;
162+
}
163+
164+
message TestStruct {
165+
.google.protobuf.Struct struct_value = 1;
166+
.google.protobuf.Value value = 2;
167+
.google.protobuf.ListValue list_value = 3;
168+
}
169+
170+
message TestAny {
171+
.google.protobuf.Any any_value = 1;
172+
map<string, .google.protobuf.Any> any_map = 2;
173+
}
174+
175+
message TestCustomJsonName {
176+
int32 value = 1 [json_name = "@value"];
177+
}
178+
179+
message TestRecursive {
180+
int32 value = 1;
181+
TestRecursive nested = 2;
182+
}

0 commit comments

Comments
 (0)