Skip to content

Commit 5768acd

Browse files
Remove protobuf-util usages of guava except annotations.
The annotations will be handled in a subsequent change. The change to use java.lang.String.split() instead of Guava's Splitter does introduce behavior changes in the case of handling of degenerate/malformed FieldMask paths (paths like `a///`). The handling of malformed paths shape are already arbitrary and inconsistent between the different methods in this file, and callers should not construct such paths. In a future change we may consider validating and throwing an IllegalArgumentException on such malformed paths more explicitly. #21173 PiperOrigin-RevId: 795126095
1 parent 38ca2d3 commit 5768acd

File tree

5 files changed

+91
-54
lines changed

5 files changed

+91
-54
lines changed

java/util/src/main/java/com/google/protobuf/util/Durations.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
package com.google.protobuf.util;
99

10-
import static com.google.common.base.Preconditions.checkArgument;
1110
import static com.google.protobuf.util.Timestamps.MICROS_PER_SECOND;
1211
import static com.google.protobuf.util.Timestamps.MILLIS_PER_SECOND;
1312
import static com.google.protobuf.util.Timestamps.NANOS_PER_MICROSECOND;
@@ -19,7 +18,6 @@
1918

2019
import com.google.common.annotations.GwtIncompatible;
2120
import com.google.common.annotations.J2ktIncompatible;
22-
import com.google.common.base.Strings;
2321
import com.google.errorprone.annotations.CanIgnoreReturnValue;
2422
import com.google.errorprone.annotations.CompileTimeConstant;
2523
import com.google.j2objc.annotations.J2ObjCIncompatible;
@@ -146,7 +144,10 @@ public static boolean isPositive(Duration duration) {
146144
@J2ktIncompatible
147145
@J2ObjCIncompatible
148146
public static Duration checkNotNegative(Duration duration) {
149-
checkArgument(!isNegative(duration), "duration (%s) must not be negative", toString(duration));
147+
if (isNegative(duration)) {
148+
throw new IllegalArgumentException(
149+
"duration (" + toString(duration) + ") must not be negative");
150+
}
150151
return duration;
151152
}
152153

@@ -161,7 +162,9 @@ public static Duration checkNotNegative(Duration duration) {
161162
@J2ktIncompatible
162163
@J2ObjCIncompatible
163164
public static Duration checkPositive(Duration duration) {
164-
checkArgument(isPositive(duration), "duration (%s) must be positive", toString(duration));
165+
if (!isPositive(duration)) {
166+
throw new IllegalArgumentException("duration (" + toString(duration) + ") must be positive");
167+
}
165168
return duration;
166169
}
167170

@@ -172,12 +175,14 @@ public static Duration checkValid(Duration duration) {
172175
int nanos = duration.getNanos();
173176
if (!isValid(seconds, nanos)) {
174177
throw new IllegalArgumentException(
175-
Strings.lenientFormat(
176-
"Duration is not valid. See proto definition for valid values. "
177-
+ "Seconds (%s) must be in range [-315,576,000,000, +315,576,000,000]. "
178-
+ "Nanos (%s) must be in range [-999,999,999, +999,999,999]. "
179-
+ "Nanos must have the same sign as seconds",
180-
seconds, nanos));
178+
"Duration is not valid. See proto definition for valid values. "
179+
+ "Seconds ("
180+
+ seconds
181+
+ ") must be in range [-315,576,000,000, +315,576,000,000]. "
182+
+ "Nanos ("
183+
+ nanos
184+
+ ") must be in range [-999,999,999, +999,999,999]. "
185+
+ "Nanos must have the same sign as seconds");
181186
}
182187
return duration;
183188
}

java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77

88
package com.google.protobuf.util;
99

10-
import com.google.common.base.Splitter;
1110
import com.google.errorprone.annotations.CanIgnoreReturnValue;
1211
import com.google.protobuf.Descriptors.Descriptor;
1312
import com.google.protobuf.Descriptors.FieldDescriptor;
1413
import com.google.protobuf.FieldMask;
1514
import com.google.protobuf.GeneratedMessage;
1615
import com.google.protobuf.Message;
1716
import java.util.ArrayList;
17+
import java.util.Arrays;
1818
import java.util.List;
1919
import java.util.Map.Entry;
2020
import java.util.SortedMap;
@@ -125,8 +125,12 @@ FieldMaskTree mergeFromFieldMask(FieldMask mask) {
125125
* </ul>
126126
*/
127127
@CanIgnoreReturnValue
128+
@SuppressWarnings("StringSplitter")
128129
FieldMaskTree removeFieldPath(String path) {
129-
List<String> parts = Splitter.onPattern(FIELD_PATH_SEPARATOR_REGEX).splitToList(path);
130+
if (path.isEmpty()) {
131+
return this;
132+
}
133+
List<String> parts = Arrays.asList(path.split(FIELD_PATH_SEPARATOR_REGEX));
130134
if (parts.isEmpty()) {
131135
return this;
132136
}
@@ -191,6 +195,7 @@ private static void getFieldPaths(Node node, String path, List<String> paths) {
191195
}
192196

193197
/** Adds the intersection of this tree with the given {@code path} to {@code output}. */
198+
@SuppressWarnings("StringSplitter")
194199
void intersectFieldPath(String path, FieldMaskTree output) {
195200
if (root.children.isEmpty()) {
196201
return;

java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,6 @@
77

88
package com.google.protobuf.util;
99

10-
import static com.google.common.base.Preconditions.checkArgument;
11-
12-
import com.google.common.base.CaseFormat;
13-
import com.google.common.base.Joiner;
14-
import com.google.common.base.Optional;
15-
import com.google.common.base.Splitter;
16-
import com.google.common.primitives.Ints;
1710
import com.google.errorprone.annotations.CanIgnoreReturnValue;
1811
import com.google.protobuf.Descriptors.Descriptor;
1912
import com.google.protobuf.Descriptors.FieldDescriptor;
@@ -23,6 +16,8 @@
2316
import java.util.ArrayList;
2417
import java.util.Arrays;
2518
import java.util.List;
19+
import java.util.Optional;
20+
import java.util.stream.Collectors;
2621
import javax.annotation.Nullable;
2722

2823
/** Utility helper functions to work with {@link com.google.protobuf.FieldMask}. */
@@ -35,7 +30,6 @@ private FieldMaskUtil() {}
3530

3631
/** Converts a FieldMask to a string. */
3732
public static String toString(FieldMask fieldMask) {
38-
// TODO: Consider using com.google.common.base.Joiner here instead.
3933
StringBuilder result = new StringBuilder();
4034
boolean first = true;
4135
for (String value : fieldMask.getPathsList()) {
@@ -55,7 +49,6 @@ public static String toString(FieldMask fieldMask) {
5549

5650
/** Parses from a string to a FieldMask. */
5751
public static FieldMask fromString(String value) {
58-
// TODO: Consider using com.google.common.base.Splitter here instead.
5952
return fromStringList(Arrays.asList(value.split(FIELD_PATH_SEPARATOR_REGEX)));
6053
}
6154

@@ -65,7 +58,6 @@ public static FieldMask fromString(String value) {
6558
* @throws IllegalArgumentException if any of the field path is invalid.
6659
*/
6760
public static FieldMask fromString(Class<? extends Message> type, String value) {
68-
// TODO: Consider using com.google.common.base.Splitter here instead.
6961
return fromStringList(type, Arrays.asList(value.split(FIELD_PATH_SEPARATOR_REGEX)));
7062
}
7163

@@ -92,7 +84,7 @@ public static FieldMask fromStringList(Descriptor descriptor, Iterable<String> p
9284
* paths.
9385
*/
9486
public static FieldMask fromStringList(Iterable<String> paths) {
95-
return fromStringList(Optional.<Descriptor>absent(), paths);
87+
return fromStringList(Optional.<Descriptor>empty(), paths);
9688
}
9789

9890
private static FieldMask fromStringList(Optional<Descriptor> descriptor, Iterable<String> paths) {
@@ -117,7 +109,7 @@ private static FieldMask fromStringList(Optional<Descriptor> descriptor, Iterabl
117109
* @throws IllegalArgumentException if any of the fields are invalid for the message.
118110
*/
119111
public static FieldMask fromFieldNumbers(Class<? extends Message> type, int... fieldNumbers) {
120-
return fromFieldNumbers(type, Ints.asList(fieldNumbers));
112+
return fromFieldNumbers(type, Arrays.stream(fieldNumbers).boxed().collect(Collectors.toList()));
121113
}
122114

123115
/**
@@ -128,16 +120,50 @@ public static FieldMask fromFieldNumbers(Class<? extends Message> type, int... f
128120
public static FieldMask fromFieldNumbers(
129121
Class<? extends Message> type, Iterable<Integer> fieldNumbers) {
130122
Descriptor descriptor = Internal.getDefaultInstance(type).getDescriptorForType();
131-
132123
FieldMask.Builder builder = FieldMask.newBuilder();
133124
for (Integer fieldNumber : fieldNumbers) {
134125
FieldDescriptor field = descriptor.findFieldByNumber(fieldNumber);
135-
checkArgument(field != null, "%s is not a valid field number for %s.", fieldNumber, type);
126+
if (field == null) {
127+
throw new IllegalArgumentException(
128+
String.format(
129+
"%s is not a valid field number for %s.", fieldNumber, descriptor.getFullName()));
130+
}
136131
builder.addPaths(field.getName());
137132
}
138133
return builder.build();
139134
}
140135

136+
/** Converts a lower_underscore to lowerCamelCase style. */
137+
private static String lowerUnderscoreToLowerCamel(String str) {
138+
StringBuilder sb = new StringBuilder();
139+
boolean capitalizeNext = false;
140+
for (int i = 0; i < str.length(); i++) {
141+
char c = str.charAt(i);
142+
if (c == '_') {
143+
capitalizeNext = true;
144+
} else if (capitalizeNext) {
145+
sb.append(Character.toUpperCase(c));
146+
capitalizeNext = false;
147+
} else {
148+
sb.append(Character.toLowerCase(c));
149+
}
150+
}
151+
return sb.toString();
152+
}
153+
154+
/** Converts a lowerCamelCase string to lower_underscore style. */
155+
private static String lowerCamelToLowerUnderscore(String str) {
156+
StringBuilder sb = new StringBuilder();
157+
for (int i = 0; i < str.length(); i++) {
158+
char c = str.charAt(i);
159+
if (c >= 'A' && c <= 'Z') {
160+
sb.append('_');
161+
}
162+
sb.append(Character.toLowerCase(c));
163+
}
164+
return sb.toString();
165+
}
166+
141167
/**
142168
* Converts a field mask to a Proto3 JSON string, that is converting from snake case to camel case
143169
* and joining all paths into one string with commas.
@@ -148,23 +174,24 @@ public static String toJsonString(FieldMask fieldMask) {
148174
if (path.isEmpty()) {
149175
continue;
150176
}
151-
paths.add(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, path));
177+
paths.add(lowerUnderscoreToLowerCamel(path));
152178
}
153-
return Joiner.on(FIELD_PATH_SEPARATOR).join(paths);
179+
return String.join(FIELD_PATH_SEPARATOR, paths);
154180
}
155181

156182
/**
157183
* Converts a field mask from a Proto3 JSON string, that is splitting the paths along commas and
158184
* converting from camel case to snake case.
159185
*/
186+
@SuppressWarnings("StringSplitter")
160187
public static FieldMask fromJsonString(String value) {
161-
Iterable<String> paths = Splitter.on(FIELD_PATH_SEPARATOR).split(value);
188+
String[] paths = value.split(FIELD_PATH_SEPARATOR);
162189
FieldMask.Builder builder = FieldMask.newBuilder();
163190
for (String path : paths) {
164191
if (path.isEmpty()) {
165192
continue;
166193
}
167-
builder.addPaths(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, path));
194+
builder.addPaths(lowerCamelToLowerUnderscore(path));
168195
}
169196
return builder.build();
170197
}

java/util/src/main/java/com/google/protobuf/util/JsonFormat.java

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77

88
package com.google.protobuf.util;
99

10-
import com.google.common.base.Preconditions;
11-
import com.google.common.collect.ImmutableSet;
12-
import com.google.common.io.BaseEncoding;
1310
import com.google.errorprone.annotations.CanIgnoreReturnValue;
1411
import com.google.gson.Gson;
1512
import com.google.gson.GsonBuilder;
@@ -54,6 +51,7 @@
5451
import java.math.BigDecimal;
5552
import java.math.BigInteger;
5653
import java.text.ParseException;
54+
import java.util.Base64;
5755
import java.util.Collection;
5856
import java.util.Collections;
5957
import java.util.Comparator;
@@ -83,7 +81,7 @@ public static Printer printer() {
8381
com.google.protobuf.TypeRegistry.getEmptyTypeRegistry(),
8482
TypeRegistry.getEmptyTypeRegistry(),
8583
ShouldPrintDefaults.ONLY_IF_PRESENT,
86-
/* includingDefaultValueFields */ ImmutableSet.of(),
84+
/* includingDefaultValueFields */ Collections.emptySet(),
8785
/* preservingProtoFieldNames */ false,
8886
/* omittingInsignificantWhitespace */ false,
8987
/* printingEnumsAsInts */ false,
@@ -196,7 +194,7 @@ public Printer includingDefaultValueFields() {
196194
registry,
197195
oldRegistry,
198196
ShouldPrintDefaults.ALWAYS_PRINT_EXCEPT_MESSAGES_AND_ONEOFS,
199-
ImmutableSet.of(),
197+
Collections.emptySet(),
200198
preservingProtoFieldNames,
201199
omittingInsignificantWhitespace,
202200
printingEnumsAsInts,
@@ -213,9 +211,10 @@ public Printer includingDefaultValueFields() {
213211
* here.
214212
*/
215213
public Printer includingDefaultValueFields(Set<FieldDescriptor> fieldsToAlwaysOutput) {
216-
Preconditions.checkArgument(
217-
null != fieldsToAlwaysOutput && !fieldsToAlwaysOutput.isEmpty(),
218-
"Non-empty Set must be supplied for includingDefaultValueFields.");
214+
if (fieldsToAlwaysOutput == null || fieldsToAlwaysOutput.isEmpty()) {
215+
throw new IllegalArgumentException(
216+
"Non-empty Set must be supplied for includingDefaultValueFields.");
217+
}
219218
if (shouldPrintDefaults != ShouldPrintDefaults.ONLY_IF_PRESENT) {
220219
throw new IllegalStateException(
221220
"JsonFormat includingDefaultValueFields has already been set.");
@@ -224,7 +223,7 @@ public Printer includingDefaultValueFields(Set<FieldDescriptor> fieldsToAlwaysOu
224223
registry,
225224
oldRegistry,
226225
ShouldPrintDefaults.ALWAYS_PRINT_SPECIFIED_FIELDS,
227-
ImmutableSet.copyOf(fieldsToAlwaysOutput),
226+
Collections.unmodifiableSet(new HashSet<>(fieldsToAlwaysOutput)),
228227
preservingProtoFieldNames,
229228
omittingInsignificantWhitespace,
230229
printingEnumsAsInts,
@@ -245,7 +244,7 @@ public Printer alwaysPrintFieldsWithNoPresence() {
245244
registry,
246245
oldRegistry,
247246
ShouldPrintDefaults.ALWAYS_PRINT_WITHOUT_PRESENCE_FIELDS,
248-
ImmutableSet.of(),
247+
Collections.emptySet(),
249248
preservingProtoFieldNames,
250249
omittingInsignificantWhitespace,
251250
printingEnumsAsInts,
@@ -1251,7 +1250,7 @@ private void printSingleFieldValue(
12511250

12521251
case BYTES:
12531252
generator.print("\"");
1254-
generator.print(BaseEncoding.base64().encode(((ByteString) value).toByteArray()));
1253+
generator.print(Base64.getEncoder().encodeToString(((ByteString) value).toByteArray()));
12551254
generator.print("\"");
12561255
break;
12571256

@@ -1906,9 +1905,9 @@ private String parseString(JsonElement json) {
19061905

19071906
private ByteString parseBytes(JsonElement json) {
19081907
try {
1909-
return ByteString.copyFrom(BaseEncoding.base64().decode(json.getAsString()));
1908+
return ByteString.copyFrom(Base64.getDecoder().decode(json.getAsString()));
19101909
} catch (IllegalArgumentException e) {
1911-
return ByteString.copyFrom(BaseEncoding.base64Url().decode(json.getAsString()));
1910+
return ByteString.copyFrom(Base64.getUrlDecoder().decode(json.getAsString()));
19121911
}
19131912
}
19141913

@@ -1964,7 +1963,7 @@ private Object parseFieldValue(FieldDescriptor field, JsonElement json, Message.
19641963
// If the field type is primitive, but the json type is JsonObject rather than
19651964
// JsonElement, throw a type mismatch error.
19661965
throw new InvalidProtocolBufferException(
1967-
String.format("Invalid value: %s for expected type: %s", json, field.getType()));
1966+
"Invalid value: " + json + " for expected type: " + field.getType());
19681967
}
19691968
}
19701969
switch (field.getType()) {

java/util/src/main/java/com/google/protobuf/util/Timestamps.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
import com.google.common.annotations.GwtIncompatible;
1515
import com.google.common.annotations.J2ktIncompatible;
16-
import com.google.common.base.Strings;
1716
import com.google.errorprone.annotations.CanIgnoreReturnValue;
1817
import com.google.errorprone.annotations.CompileTimeConstant;
1918
import com.google.j2objc.annotations.J2ObjCIncompatible;
@@ -170,11 +169,13 @@ public static Timestamp checkValid(Timestamp timestamp) {
170169
int nanos = timestamp.getNanos();
171170
if (!isValid(seconds, nanos)) {
172171
throw new IllegalArgumentException(
173-
Strings.lenientFormat(
174-
"Timestamp is not valid. See proto definition for valid values. "
175-
+ "Seconds (%s) must be in range [-62,135,596,800, +253,402,300,799]. "
176-
+ "Nanos (%s) must be in range [0, +999,999,999].",
177-
seconds, nanos));
172+
"Timestamp is not valid. See proto definition for valid values. "
173+
+ "Seconds ("
174+
+ seconds
175+
+ ") must be in range [-62,135,596,800, +253,402,300,799]. "
176+
+ "Nanos ("
177+
+ nanos
178+
+ ") must be in range [0, +999,999,999].");
178179
}
179180
return timestamp;
180181
}
@@ -504,10 +505,10 @@ static Timestamp normalizedTimestamp(long seconds, int nanos) {
504505
// when normalized.
505506
if (!isValidSeconds(seconds)) {
506507
throw new IllegalArgumentException(
507-
Strings.lenientFormat(
508-
"Timestamp is not valid. Input seconds is too large. "
509-
+ "Seconds (%s) must be in range [-62,135,596,800, +253,402,300,799]. ",
510-
seconds));
508+
"Timestamp is not valid. Input seconds is too large. "
509+
+ "Seconds ("
510+
+ seconds
511+
+ ") must be in range [-62,135,596,800, +253,402,300,799]. ");
511512
}
512513
if (nanos <= -NANOS_PER_SECOND || nanos >= NANOS_PER_SECOND) {
513514
seconds = addExact(seconds, nanos / NANOS_PER_SECOND);

0 commit comments

Comments
 (0)