Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(248)

Unified Diff: third_party/protobuf/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java

Issue 2495533002: third_party/protobuf: Update to HEAD (83d681ee2c) (Closed)
Patch Set: Make chrome settings proto generated file a component Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/protobuf/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
diff --git a/third_party/protobuf/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java b/third_party/protobuf/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
index 76f3437a6b7a4e628e33269e9cbf7e73756deb88..ac712c94296be1fe92370c1d7a0323ac3bf60b99 100644
--- a/third_party/protobuf/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
+++ b/third_party/protobuf/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
@@ -49,6 +49,7 @@ import com.google.protobuf.Descriptors.EnumDescriptor;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.FileDescriptor;
+import com.google.protobuf.Descriptors.OneofDescriptor;
import com.google.protobuf.DoubleValue;
import com.google.protobuf.Duration;
import com.google.protobuf.DynamicMessage;
@@ -60,13 +61,13 @@ import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.ListValue;
import com.google.protobuf.Message;
import com.google.protobuf.MessageOrBuilder;
+import com.google.protobuf.NullValue;
import com.google.protobuf.StringValue;
import com.google.protobuf.Struct;
import com.google.protobuf.Timestamp;
import com.google.protobuf.UInt32Value;
import com.google.protobuf.UInt64Value;
import com.google.protobuf.Value;
-
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
@@ -92,18 +93,17 @@ import java.util.logging.Logger;
* as well.
*/
public class JsonFormat {
- private static final Logger logger =
- Logger.getLogger(JsonFormat.class.getName());
+ private static final Logger logger = Logger.getLogger(JsonFormat.class.getName());
private JsonFormat() {}
-
+
/**
* Creates a {@link Printer} with default configurations.
*/
public static Printer printer() {
- return new Printer(TypeRegistry.getEmptyTypeRegistry(), false, false);
+ return new Printer(TypeRegistry.getEmptyTypeRegistry(), false, false, false);
}
-
+
/**
* A Printer converts protobuf message to JSON format.
*/
@@ -111,27 +111,34 @@ public class JsonFormat {
private final TypeRegistry registry;
private final boolean includingDefaultValueFields;
private final boolean preservingProtoFieldNames;
+ private final boolean omittingInsignificantWhitespace;
private Printer(
TypeRegistry registry,
boolean includingDefaultValueFields,
- boolean preservingProtoFieldNames) {
+ boolean preservingProtoFieldNames,
+ boolean omittingInsignificantWhitespace) {
this.registry = registry;
this.includingDefaultValueFields = includingDefaultValueFields;
this.preservingProtoFieldNames = preservingProtoFieldNames;
+ this.omittingInsignificantWhitespace = omittingInsignificantWhitespace;
}
-
+
/**
* Creates a new {@link Printer} using the given registry. The new Printer
* clones all other configurations from the current {@link Printer}.
- *
+ *
* @throws IllegalArgumentException if a registry is already set.
*/
public Printer usingTypeRegistry(TypeRegistry registry) {
if (this.registry != TypeRegistry.getEmptyTypeRegistry()) {
throw new IllegalArgumentException("Only one registry is allowed.");
}
- return new Printer(registry, includingDefaultValueFields, preservingProtoFieldNames);
+ return new Printer(
+ registry,
+ includingDefaultValueFields,
+ preservingProtoFieldNames,
+ omittingInsignificantWhitespace);
}
/**
@@ -141,7 +148,8 @@ public class JsonFormat {
* {@link Printer}.
*/
public Printer includingDefaultValueFields() {
- return new Printer(registry, true, preservingProtoFieldNames);
+ return new Printer(
+ registry, true, preservingProtoFieldNames, omittingInsignificantWhitespace);
}
/**
@@ -151,30 +159,54 @@ public class JsonFormat {
* current {@link Printer}.
*/
public Printer preservingProtoFieldNames() {
- return new Printer(registry, includingDefaultValueFields, true);
+ return new Printer(
+ registry, includingDefaultValueFields, true, omittingInsignificantWhitespace);
+ }
+
+
+ /**
+ * Create a new {@link Printer} that will omit all insignificant whitespace
+ * in the JSON output. This new Printer clones all other configurations from the
+ * current Printer. Insignificant whitespace is defined by the JSON spec as whitespace
+ * that appear between JSON structural elements:
+ * <pre>
+ * ws = *(
+ * %x20 / ; Space
+ * %x09 / ; Horizontal tab
+ * %x0A / ; Line feed or New line
+ * %x0D ) ; Carriage return
+ * </pre>
+ * See <a href="https://tools.ietf.org/html/rfc7159">https://tools.ietf.org/html/rfc7159</a>
+ * current {@link Printer}.
+ */
+ public Printer omittingInsignificantWhitespace() {
+ return new Printer(registry, includingDefaultValueFields, preservingProtoFieldNames, true);
}
-
+
/**
* Converts a protobuf message to JSON format.
- *
+ *
* @throws InvalidProtocolBufferException if the message contains Any types
* that can't be resolved.
* @throws IOException if writing to the output fails.
*/
- public void appendTo(MessageOrBuilder message, Appendable output)
- throws IOException {
+ public void appendTo(MessageOrBuilder message, Appendable output) throws IOException {
// TODO(xiaofeng): Investigate the allocation overhead and optimize for
// mobile.
- new PrinterImpl(registry, includingDefaultValueFields, preservingProtoFieldNames, output)
+ new PrinterImpl(
+ registry,
+ includingDefaultValueFields,
+ preservingProtoFieldNames,
+ output,
+ omittingInsignificantWhitespace)
.print(message);
}
/**
* Converts a protobuf message to JSON format. Throws exceptions if there
- * are unknown Any types in the message.
+ * are unknown Any types in the message.
*/
- public String print(MessageOrBuilder message)
- throws InvalidProtocolBufferException {
+ public String print(MessageOrBuilder message) throws InvalidProtocolBufferException {
try {
StringBuilder builder = new StringBuilder();
appendTo(message, builder);
@@ -192,57 +224,75 @@ public class JsonFormat {
* Creates a {@link Parser} with default configuration.
*/
public static Parser parser() {
- return new Parser(TypeRegistry.getEmptyTypeRegistry());
+ return new Parser(TypeRegistry.getEmptyTypeRegistry(), false, Parser.DEFAULT_RECURSION_LIMIT);
}
-
+
/**
* A Parser parses JSON to protobuf message.
*/
public static class Parser {
private final TypeRegistry registry;
-
- private Parser(TypeRegistry registry) {
- this.registry = registry;
+ private final boolean ignoringUnknownFields;
+ private final int recursionLimit;
+
+ // The default parsing recursion limit is aligned with the proto binary parser.
+ private static final int DEFAULT_RECURSION_LIMIT = 100;
+
+ private Parser(TypeRegistry registry, boolean ignoreUnknownFields, int recursionLimit) {
+ this.registry = registry;
+ this.ignoringUnknownFields = ignoreUnknownFields;
+ this.recursionLimit = recursionLimit;
}
-
+
/**
* Creates a new {@link Parser} using the given registry. The new Parser
* clones all other configurations from this Parser.
- *
+ *
* @throws IllegalArgumentException if a registry is already set.
*/
public Parser usingTypeRegistry(TypeRegistry registry) {
if (this.registry != TypeRegistry.getEmptyTypeRegistry()) {
throw new IllegalArgumentException("Only one registry is allowed.");
}
- return new Parser(registry);
+ return new Parser(registry, ignoringUnknownFields, recursionLimit);
+ }
+
+ /**
+ * Creates a new {@link Parser} configured to not throw an exception when an unknown field is
+ * encountered. The new Parser clones all other configurations from this Parser.
+ */
+ public Parser ignoringUnknownFields() {
+ return new Parser(this.registry, true, recursionLimit);
}
-
+
/**
* Parses from JSON into a protobuf message.
- *
+ *
* @throws InvalidProtocolBufferException if the input is not valid JSON
* format or there are unknown fields in the input.
*/
- public void merge(String json, Message.Builder builder)
- throws InvalidProtocolBufferException {
+ public void merge(String json, Message.Builder builder) throws InvalidProtocolBufferException {
// TODO(xiaofeng): Investigate the allocation overhead and optimize for
// mobile.
- new ParserImpl(registry).merge(json, builder);
+ new ParserImpl(registry, ignoringUnknownFields, recursionLimit).merge(json, builder);
}
-
+
/**
* Parses from JSON into a protobuf message.
- *
+ *
* @throws InvalidProtocolBufferException if the input is not valid JSON
* format or there are unknown fields in the input.
* @throws IOException if reading from the input throws.
*/
- public void merge(Reader json, Message.Builder builder)
- throws IOException {
+ public void merge(Reader json, Message.Builder builder) throws IOException {
// TODO(xiaofeng): Investigate the allocation overhead and optimize for
// mobile.
- new ParserImpl(registry).merge(json, builder);
+ new ParserImpl(registry, ignoringUnknownFields, recursionLimit).merge(json, builder);
+ }
+
+ // For testing only.
+ Parser usingRecursionLimit(int recursionLimit) {
+ return new Parser(registry, ignoringUnknownFields, recursionLimit);
}
}
@@ -255,8 +305,8 @@ public class JsonFormat {
*/
public static class TypeRegistry {
private static class EmptyTypeRegistryHolder {
- private static final TypeRegistry EMPTY = new TypeRegistry(
- Collections.<String, Descriptor>emptyMap());
+ private static final TypeRegistry EMPTY =
+ new TypeRegistry(Collections.<String, Descriptor>emptyMap());
}
public static TypeRegistry getEmptyTypeRegistry() {
@@ -293,8 +343,7 @@ public class JsonFormat {
*/
public Builder add(Descriptor messageType) {
if (types == null) {
- throw new IllegalStateException(
- "A TypeRegistry.Builer can only be used once.");
+ throw new IllegalStateException("A TypeRegistry.Builer can only be used once.");
}
addFile(messageType.getFile());
return this;
@@ -306,8 +355,7 @@ public class JsonFormat {
*/
public Builder add(Iterable<Descriptor> messageTypes) {
if (types == null) {
- throw new IllegalStateException(
- "A TypeRegistry.Builer can only be used once.");
+ throw new IllegalStateException("A TypeRegistry.Builer can only be used once.");
}
for (Descriptor type : messageTypes) {
addFile(type.getFile());
@@ -345,8 +393,7 @@ public class JsonFormat {
}
if (types.containsKey(message.getFullName())) {
- logger.warning("Type " + message.getFullName()
- + " is added multiple times.");
+ logger.warning("Type " + message.getFullName() + " is added multiple times.");
return;
}
@@ -354,20 +401,58 @@ public class JsonFormat {
}
private final Set<String> files = new HashSet<String>();
- private Map<String, Descriptor> types =
- new HashMap<String, Descriptor>();
+ private Map<String, Descriptor> types = new HashMap<String, Descriptor>();
}
}
/**
+ * An interface for json formatting that can be used in
+ * combination with the omittingInsignificantWhitespace() method
+ */
+ interface TextGenerator {
+ void indent();
+
+ void outdent();
+
+ void print(final CharSequence text) throws IOException;
+ }
+
+ /**
+ * Format the json without indentation
+ */
+ private static final class CompactTextGenerator implements TextGenerator {
+ private final Appendable output;
+
+ private CompactTextGenerator(final Appendable output) {
+ this.output = output;
+ }
+
+ /**
+ * ignored by compact printer
+ */
+ public void indent() {}
+
+ /**
+ * ignored by compact printer
+ */
+ public void outdent() {}
+
+ /**
+ * Print text to the output stream.
+ */
+ public void print(final CharSequence text) throws IOException {
+ output.append(text);
+ }
+ }
+ /**
* A TextGenerator adds indentation when writing formatted text.
*/
- private static final class TextGenerator {
+ private static final class PrettyTextGenerator implements TextGenerator {
private final Appendable output;
private final StringBuilder indent = new StringBuilder();
private boolean atStartOfLine = true;
- private TextGenerator(final Appendable output) {
+ private PrettyTextGenerator(final Appendable output) {
this.output = output;
}
@@ -387,8 +472,7 @@ public class JsonFormat {
public void outdent() {
final int length = indent.length();
if (length < 2) {
- throw new IllegalArgumentException(
- " Outdent() without matching Indent().");
+ throw new IllegalArgumentException(" Outdent() without matching Indent().");
}
indent.delete(length - 2, length);
}
@@ -432,6 +516,8 @@ public class JsonFormat {
private final TextGenerator generator;
// We use Gson to help handle string escapes.
private final Gson gson;
+ private final CharSequence blankOrSpace;
+ private final CharSequence blankOrNewLine;
private static class GsonHolder {
private static final Gson DEFAULT_GSON = new GsonBuilder().disableHtmlEscaping().create();
@@ -441,54 +527,60 @@ public class JsonFormat {
TypeRegistry registry,
boolean includingDefaultValueFields,
boolean preservingProtoFieldNames,
- Appendable jsonOutput) {
+ Appendable jsonOutput,
+ boolean omittingInsignificantWhitespace) {
this.registry = registry;
this.includingDefaultValueFields = includingDefaultValueFields;
this.preservingProtoFieldNames = preservingProtoFieldNames;
- this.generator = new TextGenerator(jsonOutput);
this.gson = GsonHolder.DEFAULT_GSON;
+ // json format related properties, determined by printerType
+ if (omittingInsignificantWhitespace) {
+ this.generator = new CompactTextGenerator(jsonOutput);
+ this.blankOrSpace = "";
+ this.blankOrNewLine = "";
+ } else {
+ this.generator = new PrettyTextGenerator(jsonOutput);
+ this.blankOrSpace = " ";
+ this.blankOrNewLine = "\n";
+ }
}
void print(MessageOrBuilder message) throws IOException {
- WellKnownTypePrinter specialPrinter = wellKnownTypePrinters.get(
- message.getDescriptorForType().getFullName());
+ WellKnownTypePrinter specialPrinter =
+ wellKnownTypePrinters.get(message.getDescriptorForType().getFullName());
if (specialPrinter != null) {
specialPrinter.print(this, message);
return;
}
print(message, null);
}
-
+
private interface WellKnownTypePrinter {
- void print(PrinterImpl printer, MessageOrBuilder message)
- throws IOException;
- }
-
- private static final Map<String, WellKnownTypePrinter>
- wellKnownTypePrinters = buildWellKnownTypePrinters();
-
- private static Map<String, WellKnownTypePrinter>
- buildWellKnownTypePrinters() {
- Map<String, WellKnownTypePrinter> printers =
- new HashMap<String, WellKnownTypePrinter>();
+ void print(PrinterImpl printer, MessageOrBuilder message) throws IOException;
+ }
+
+ private static final Map<String, WellKnownTypePrinter> wellKnownTypePrinters =
+ buildWellKnownTypePrinters();
+
+ private static Map<String, WellKnownTypePrinter> buildWellKnownTypePrinters() {
+ Map<String, WellKnownTypePrinter> printers = new HashMap<String, WellKnownTypePrinter>();
// Special-case Any.
- printers.put(Any.getDescriptor().getFullName(),
+ printers.put(
+ Any.getDescriptor().getFullName(),
new WellKnownTypePrinter() {
- @Override
- public void print(PrinterImpl printer, MessageOrBuilder message)
- throws IOException {
- printer.printAny(message);
- }
- });
+ @Override
+ public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+ printer.printAny(message);
+ }
+ });
// Special-case wrapper types.
- WellKnownTypePrinter wrappersPrinter = new WellKnownTypePrinter() {
- @Override
- public void print(PrinterImpl printer, MessageOrBuilder message)
- throws IOException {
- printer.printWrapper(message);
-
- }
- };
+ WellKnownTypePrinter wrappersPrinter =
+ new WellKnownTypePrinter() {
+ @Override
+ public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+ printer.printWrapper(message);
+ }
+ };
printers.put(BoolValue.getDescriptor().getFullName(), wrappersPrinter);
printers.put(Int32Value.getDescriptor().getFullName(), wrappersPrinter);
printers.put(UInt32Value.getDescriptor().getFullName(), wrappersPrinter);
@@ -499,70 +591,75 @@ public class JsonFormat {
printers.put(FloatValue.getDescriptor().getFullName(), wrappersPrinter);
printers.put(DoubleValue.getDescriptor().getFullName(), wrappersPrinter);
// Special-case Timestamp.
- printers.put(Timestamp.getDescriptor().getFullName(),
+ printers.put(
+ Timestamp.getDescriptor().getFullName(),
new WellKnownTypePrinter() {
- @Override
- public void print(PrinterImpl printer, MessageOrBuilder message)
- throws IOException {
- printer.printTimestamp(message);
- }
- });
+ @Override
+ public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+ printer.printTimestamp(message);
+ }
+ });
// Special-case Duration.
- printers.put(Duration.getDescriptor().getFullName(),
+ printers.put(
+ Duration.getDescriptor().getFullName(),
new WellKnownTypePrinter() {
- @Override
- public void print(PrinterImpl printer, MessageOrBuilder message)
- throws IOException {
- printer.printDuration(message);
- }
- });
+ @Override
+ public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+ printer.printDuration(message);
+ }
+ });
// Special-case FieldMask.
- printers.put(FieldMask.getDescriptor().getFullName(),
+ printers.put(
+ FieldMask.getDescriptor().getFullName(),
new WellKnownTypePrinter() {
- @Override
- public void print(PrinterImpl printer, MessageOrBuilder message)
- throws IOException {
- printer.printFieldMask(message);
- }
- });
+ @Override
+ public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+ printer.printFieldMask(message);
+ }
+ });
// Special-case Struct.
- printers.put(Struct.getDescriptor().getFullName(),
+ printers.put(
+ Struct.getDescriptor().getFullName(),
new WellKnownTypePrinter() {
- @Override
- public void print(PrinterImpl printer, MessageOrBuilder message)
- throws IOException {
- printer.printStruct(message);
- }
- });
+ @Override
+ public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+ printer.printStruct(message);
+ }
+ });
// Special-case Value.
- printers.put(Value.getDescriptor().getFullName(),
+ printers.put(
+ Value.getDescriptor().getFullName(),
new WellKnownTypePrinter() {
- @Override
- public void print(PrinterImpl printer, MessageOrBuilder message)
- throws IOException {
- printer.printValue(message);
- }
- });
+ @Override
+ public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+ printer.printValue(message);
+ }
+ });
// Special-case ListValue.
- printers.put(ListValue.getDescriptor().getFullName(),
+ printers.put(
+ ListValue.getDescriptor().getFullName(),
new WellKnownTypePrinter() {
- @Override
- public void print(PrinterImpl printer, MessageOrBuilder message)
- throws IOException {
- printer.printListValue(message);
- }
- });
+ @Override
+ public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+ printer.printListValue(message);
+ }
+ });
return printers;
}
-
+
/** Prints google.protobuf.Any */
private void printAny(MessageOrBuilder message) throws IOException {
+ if (Any.getDefaultInstance().equals(message)) {
+ generator.print("{}");
+ return;
+ }
Descriptor descriptor = message.getDescriptorForType();
FieldDescriptor typeUrlField = descriptor.findFieldByName("type_url");
FieldDescriptor valueField = descriptor.findFieldByName("value");
// Validates type of the message. Note that we can't just cast the message
- // to com.google.protobuf.Any because it might be a DynamicMessage.
- if (typeUrlField == null || valueField == null
+ // to com.google.protobuf.Any because it might be a DynamicMessage.
+ if (typeUrlField == null
+ || valueField == null
|| typeUrlField.getType() != FieldDescriptor.Type.STRING
|| valueField.getType() != FieldDescriptor.Type.BYTES) {
throw new InvalidProtocolBufferException("Invalid Any type.");
@@ -571,22 +668,21 @@ public class JsonFormat {
String typeName = getTypeName(typeUrl);
Descriptor type = registry.find(typeName);
if (type == null) {
- throw new InvalidProtocolBufferException(
- "Cannot find type for url: " + typeUrl);
+ throw new InvalidProtocolBufferException("Cannot find type for url: " + typeUrl);
}
ByteString content = (ByteString) message.getField(valueField);
- Message contentMessage = DynamicMessage.getDefaultInstance(type)
- .getParserForType().parseFrom(content);
+ Message contentMessage =
+ DynamicMessage.getDefaultInstance(type).getParserForType().parseFrom(content);
WellKnownTypePrinter printer = wellKnownTypePrinters.get(typeName);
if (printer != null) {
// If the type is one of the well-known types, we use a special
// formatting.
- generator.print("{\n");
+ generator.print("{" + blankOrNewLine);
generator.indent();
- generator.print("\"@type\": " + gson.toJson(typeUrl) + ",\n");
- generator.print("\"value\": ");
+ generator.print("\"@type\":" + blankOrSpace + gson.toJson(typeUrl) + "," + blankOrNewLine);
+ generator.print("\"value\":" + blankOrSpace);
printer.print(this, contentMessage);
- generator.print("\n");
+ generator.print(blankOrNewLine);
generator.outdent();
generator.print("}");
} else {
@@ -594,7 +690,7 @@ public class JsonFormat {
print(contentMessage, typeUrl);
}
}
-
+
/** Prints wrapper types (e.g., google.protobuf.Int32Value) */
private void printWrapper(MessageOrBuilder message) throws IOException {
Descriptor descriptor = message.getDescriptorForType();
@@ -606,7 +702,7 @@ public class JsonFormat {
// the whole message.
printSingleFieldValue(valueField, message.getField(valueField));
}
-
+
private ByteString toByteString(MessageOrBuilder message) {
if (message instanceof Message) {
return ((Message) message).toByteString();
@@ -614,26 +710,25 @@ public class JsonFormat {
return ((Message.Builder) message).build().toByteString();
}
}
-
+
/** Prints google.protobuf.Timestamp */
private void printTimestamp(MessageOrBuilder message) throws IOException {
Timestamp value = Timestamp.parseFrom(toByteString(message));
- generator.print("\"" + TimeUtil.toString(value) + "\"");
+ generator.print("\"" + Timestamps.toString(value) + "\"");
}
-
+
/** Prints google.protobuf.Duration */
private void printDuration(MessageOrBuilder message) throws IOException {
Duration value = Duration.parseFrom(toByteString(message));
- generator.print("\"" + TimeUtil.toString(value) + "\"");
-
+ generator.print("\"" + Durations.toString(value) + "\"");
}
-
+
/** Prints google.protobuf.FieldMask */
private void printFieldMask(MessageOrBuilder message) throws IOException {
FieldMask value = FieldMask.parseFrom(toByteString(message));
- generator.print("\"" + FieldMaskUtil.toString(value) + "\"");
+ generator.print("\"" + FieldMaskUtil.toJsonString(value) + "\"");
}
-
+
/** Prints google.protobuf.Struct */
private void printStruct(MessageOrBuilder message) throws IOException {
Descriptor descriptor = message.getDescriptorForType();
@@ -644,7 +739,7 @@ public class JsonFormat {
// Struct is formatted as a map object.
printMapFieldValue(field, message.getField(field));
}
-
+
/** Prints google.protobuf.Value */
private void printValue(MessageOrBuilder message) throws IOException {
// For a Value message, only the value of the field is formatted.
@@ -663,7 +758,7 @@ public class JsonFormat {
printSingleFieldValue(entry.getKey(), entry.getValue());
}
}
-
+
/** Prints google.protobuf.ListValue */
private void printListValue(MessageOrBuilder message) throws IOException {
Descriptor descriptor = message.getDescriptorForType();
@@ -675,26 +770,31 @@ public class JsonFormat {
}
/** Prints a regular message with an optional type URL. */
- private void print(MessageOrBuilder message, String typeUrl)
- throws IOException {
- generator.print("{\n");
+ private void print(MessageOrBuilder message, String typeUrl) throws IOException {
+ generator.print("{" + blankOrNewLine);
generator.indent();
boolean printedField = false;
if (typeUrl != null) {
- generator.print("\"@type\": " + gson.toJson(typeUrl));
+ generator.print("\"@type\":" + blankOrSpace + gson.toJson(typeUrl));
printedField = true;
}
Map<FieldDescriptor, Object> fieldsToPrint = null;
if (includingDefaultValueFields) {
fieldsToPrint = new TreeMap<FieldDescriptor, Object>();
for (FieldDescriptor field : message.getDescriptorForType().getFields()) {
- if (field.isOptional()
- && field.getJavaType() == FieldDescriptor.JavaType.MESSAGE
- && !message.hasField(field)) {
- // Always skip empty optional message fields. If not we will recurse indefinitely if
- // a message has itself as a sub-field.
- continue;
+ if (field.isOptional()) {
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE
+ && !message.hasField(field)){
+ // Always skip empty optional message fields. If not we will recurse indefinitely if
+ // a message has itself as a sub-field.
+ continue;
+ }
+ OneofDescriptor oneof = field.getContainingOneof();
+ if (oneof != null && !message.hasField(field)) {
+ // Skip all oneof fields except the one that is actually set
+ continue;
+ }
}
fieldsToPrint.put(field, message.getField(field));
}
@@ -704,27 +804,26 @@ public class JsonFormat {
for (Map.Entry<FieldDescriptor, Object> field : fieldsToPrint.entrySet()) {
if (printedField) {
// Add line-endings for the previous field.
- generator.print(",\n");
+ generator.print("," + blankOrNewLine);
} else {
printedField = true;
}
printField(field.getKey(), field.getValue());
}
-
+
// Add line-endings for the last field.
if (printedField) {
- generator.print("\n");
+ generator.print(blankOrNewLine);
}
generator.outdent();
generator.print("}");
}
- private void printField(FieldDescriptor field, Object value)
- throws IOException {
+ private void printField(FieldDescriptor field, Object value) throws IOException {
if (preservingProtoFieldNames) {
- generator.print("\"" + field.getName() + "\": ");
+ generator.print("\"" + field.getName() + "\":" + blankOrSpace);
} else {
- generator.print("\"" + field.getJsonName() + "\": ");
+ generator.print("\"" + field.getJsonName() + "\":" + blankOrSpace);
}
if (field.isMapField()) {
printMapFieldValue(field, value);
@@ -734,15 +833,14 @@ public class JsonFormat {
printSingleFieldValue(field, value);
}
}
-
+
@SuppressWarnings("rawtypes")
- private void printRepeatedFieldValue(FieldDescriptor field, Object value)
- throws IOException {
+ private void printRepeatedFieldValue(FieldDescriptor field, Object value) throws IOException {
generator.print("[");
boolean printedElement = false;
for (Object element : (List) value) {
if (printedElement) {
- generator.print(", ");
+ generator.print("," + blankOrSpace);
} else {
printedElement = true;
}
@@ -750,17 +848,16 @@ public class JsonFormat {
}
generator.print("]");
}
-
+
@SuppressWarnings("rawtypes")
- private void printMapFieldValue(FieldDescriptor field, Object value)
- throws IOException {
+ private void printMapFieldValue(FieldDescriptor field, Object value) throws IOException {
Descriptor type = field.getMessageType();
FieldDescriptor keyField = type.findFieldByName("key");
FieldDescriptor valueField = type.findFieldByName("value");
if (keyField == null || valueField == null) {
throw new InvalidProtocolBufferException("Invalid map field.");
}
- generator.print("{\n");
+ generator.print("{" + blankOrNewLine);
generator.indent();
boolean printedElement = false;
for (Object element : (List) value) {
@@ -768,36 +865,35 @@ public class JsonFormat {
Object entryKey = entry.getField(keyField);
Object entryValue = entry.getField(valueField);
if (printedElement) {
- generator.print(",\n");
+ generator.print("," + blankOrNewLine);
} else {
printedElement = true;
}
// Key fields are always double-quoted.
printSingleFieldValue(keyField, entryKey, true);
- generator.print(": ");
+ generator.print(":" + blankOrSpace);
printSingleFieldValue(valueField, entryValue);
}
if (printedElement) {
- generator.print("\n");
+ generator.print(blankOrNewLine);
}
generator.outdent();
generator.print("}");
}
-
- private void printSingleFieldValue(FieldDescriptor field, Object value)
- throws IOException {
+
+ private void printSingleFieldValue(FieldDescriptor field, Object value) throws IOException {
printSingleFieldValue(field, value, false);
}
/**
* Prints a field's value in JSON format.
- *
+ *
* @param alwaysWithQuotes whether to always add double-quotes to primitive
* types.
*/
private void printSingleFieldValue(
- final FieldDescriptor field, final Object value,
- boolean alwaysWithQuotes) throws IOException {
+ final FieldDescriptor field, final Object value, boolean alwaysWithQuotes)
+ throws IOException {
switch (field.getType()) {
case INT32:
case SINT32:
@@ -851,7 +947,7 @@ public class JsonFormat {
}
}
break;
-
+
case DOUBLE:
Double doubleValue = (Double) value;
if (doubleValue.isNaN()) {
@@ -895,15 +991,13 @@ public class JsonFormat {
case BYTES:
generator.print("\"");
- generator.print(
- BaseEncoding.base64().encode(((ByteString) value).toByteArray()));
+ generator.print(BaseEncoding.base64().encode(((ByteString) value).toByteArray()));
generator.print("\"");
break;
case ENUM:
// Special-case google.protobuf.NullValue (it's an Enum).
- if (field.getEnumType().getFullName().equals(
- "google.protobuf.NullValue")) {
+ if (field.getEnumType().getFullName().equals("google.protobuf.NullValue")) {
// No matter what value it contains, we always print it as "null".
if (alwaysWithQuotes) {
generator.print("\"");
@@ -914,11 +1008,9 @@ public class JsonFormat {
}
} else {
if (((EnumValueDescriptor) value).getIndex() == -1) {
- generator.print(
- String.valueOf(((EnumValueDescriptor) value).getNumber()));
+ generator.print(String.valueOf(((EnumValueDescriptor) value).getNumber()));
} else {
- generator.print(
- "\"" + ((EnumValueDescriptor) value).getName() + "\"");
+ generator.print("\"" + ((EnumValueDescriptor) value).getName() + "\"");
}
}
break;
@@ -947,40 +1039,40 @@ public class JsonFormat {
} else {
// Pull off the most-significant bit so that BigInteger doesn't think
// the number is negative, then set it again using setBit().
- return BigInteger.valueOf(value & Long.MAX_VALUE)
- .setBit(Long.SIZE - 1).toString();
+ return BigInteger.valueOf(value & Long.MAX_VALUE).setBit(Long.SIZE - 1).toString();
}
}
-
- private static String getTypeName(String typeUrl)
- throws InvalidProtocolBufferException {
+ private static String getTypeName(String typeUrl) throws InvalidProtocolBufferException {
String[] parts = typeUrl.split("/");
if (parts.length == 1) {
- throw new InvalidProtocolBufferException(
- "Invalid type url found: " + typeUrl);
+ throw new InvalidProtocolBufferException("Invalid type url found: " + typeUrl);
}
return parts[parts.length - 1];
}
-
+
private static class ParserImpl {
private final TypeRegistry registry;
private final JsonParser jsonParser;
-
- ParserImpl(TypeRegistry registry) {
+ private final boolean ignoringUnknownFields;
+ private final int recursionLimit;
+ private int currentDepth;
+
+ ParserImpl(TypeRegistry registry, boolean ignoreUnknownFields, int recursionLimit) {
this.registry = registry;
+ this.ignoringUnknownFields = ignoreUnknownFields;
this.jsonParser = new JsonParser();
+ this.recursionLimit = recursionLimit;
+ this.currentDepth = 0;
}
-
- void merge(Reader json, Message.Builder builder)
- throws IOException {
+
+ void merge(Reader json, Message.Builder builder) throws IOException {
JsonReader reader = new JsonReader(json);
reader.setLenient(false);
merge(jsonParser.parse(reader), builder);
}
-
- void merge(String json, Message.Builder builder)
- throws InvalidProtocolBufferException {
+
+ void merge(String json, Message.Builder builder) throws InvalidProtocolBufferException {
try {
JsonReader reader = new JsonReader(new StringReader(json));
reader.setLenient(false);
@@ -992,35 +1084,36 @@ public class JsonFormat {
throw new InvalidProtocolBufferException(e.getMessage());
}
}
-
+
private interface WellKnownTypeParser {
void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
throws InvalidProtocolBufferException;
}
-
+
private static final Map<String, WellKnownTypeParser> wellKnownTypeParsers =
buildWellKnownTypeParsers();
-
- private static Map<String, WellKnownTypeParser>
- buildWellKnownTypeParsers() {
- Map<String, WellKnownTypeParser> parsers =
- new HashMap<String, WellKnownTypeParser>();
+
+ private static Map<String, WellKnownTypeParser> buildWellKnownTypeParsers() {
+ Map<String, WellKnownTypeParser> parsers = new HashMap<String, WellKnownTypeParser>();
// Special-case Any.
- parsers.put(Any.getDescriptor().getFullName(), new WellKnownTypeParser() {
- @Override
- public void merge(ParserImpl parser, JsonElement json,
- Message.Builder builder) throws InvalidProtocolBufferException {
- parser.mergeAny(json, builder);
- }
- });
+ parsers.put(
+ Any.getDescriptor().getFullName(),
+ new WellKnownTypeParser() {
+ @Override
+ public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+ throws InvalidProtocolBufferException {
+ parser.mergeAny(json, builder);
+ }
+ });
// Special-case wrapper types.
- WellKnownTypeParser wrappersPrinter = new WellKnownTypeParser() {
- @Override
- public void merge(ParserImpl parser, JsonElement json,
- Message.Builder builder) throws InvalidProtocolBufferException {
- parser.mergeWrapper(json, builder);
- }
- };
+ WellKnownTypeParser wrappersPrinter =
+ new WellKnownTypeParser() {
+ @Override
+ public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+ throws InvalidProtocolBufferException {
+ parser.mergeWrapper(json, builder);
+ }
+ };
parsers.put(BoolValue.getDescriptor().getFullName(), wrappersPrinter);
parsers.put(Int32Value.getDescriptor().getFullName(), wrappersPrinter);
parsers.put(UInt32Value.getDescriptor().getFullName(), wrappersPrinter);
@@ -1031,82 +1124,86 @@ public class JsonFormat {
parsers.put(FloatValue.getDescriptor().getFullName(), wrappersPrinter);
parsers.put(DoubleValue.getDescriptor().getFullName(), wrappersPrinter);
// Special-case Timestamp.
- parsers.put(Timestamp.getDescriptor().getFullName(),
+ parsers.put(
+ Timestamp.getDescriptor().getFullName(),
new WellKnownTypeParser() {
- @Override
- public void merge(ParserImpl parser, JsonElement json,
- Message.Builder builder) throws InvalidProtocolBufferException {
- parser.mergeTimestamp(json, builder);
- }
- });
+ @Override
+ public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+ throws InvalidProtocolBufferException {
+ parser.mergeTimestamp(json, builder);
+ }
+ });
// Special-case Duration.
- parsers.put(Duration.getDescriptor().getFullName(),
+ parsers.put(
+ Duration.getDescriptor().getFullName(),
new WellKnownTypeParser() {
- @Override
- public void merge(ParserImpl parser, JsonElement json,
- Message.Builder builder) throws InvalidProtocolBufferException {
- parser.mergeDuration(json, builder);
- }
- });
+ @Override
+ public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+ throws InvalidProtocolBufferException {
+ parser.mergeDuration(json, builder);
+ }
+ });
// Special-case FieldMask.
- parsers.put(FieldMask.getDescriptor().getFullName(),
+ parsers.put(
+ FieldMask.getDescriptor().getFullName(),
new WellKnownTypeParser() {
- @Override
- public void merge(ParserImpl parser, JsonElement json,
- Message.Builder builder) throws InvalidProtocolBufferException {
- parser.mergeFieldMask(json, builder);
- }
- });
+ @Override
+ public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+ throws InvalidProtocolBufferException {
+ parser.mergeFieldMask(json, builder);
+ }
+ });
// Special-case Struct.
- parsers.put(Struct.getDescriptor().getFullName(),
+ parsers.put(
+ Struct.getDescriptor().getFullName(),
new WellKnownTypeParser() {
- @Override
- public void merge(ParserImpl parser, JsonElement json,
- Message.Builder builder) throws InvalidProtocolBufferException {
- parser.mergeStruct(json, builder);
- }
- });
+ @Override
+ public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+ throws InvalidProtocolBufferException {
+ parser.mergeStruct(json, builder);
+ }
+ });
// Special-case ListValue.
- parsers.put(ListValue.getDescriptor().getFullName(),
+ parsers.put(
+ ListValue.getDescriptor().getFullName(),
new WellKnownTypeParser() {
- @Override
- public void merge(ParserImpl parser, JsonElement json,
- Message.Builder builder) throws InvalidProtocolBufferException {
- parser.mergeListValue(json, builder);
- }
- });
+ @Override
+ public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+ throws InvalidProtocolBufferException {
+ parser.mergeListValue(json, builder);
+ }
+ });
// Special-case Value.
- parsers.put(Value.getDescriptor().getFullName(),
+ parsers.put(
+ Value.getDescriptor().getFullName(),
new WellKnownTypeParser() {
- @Override
- public void merge(ParserImpl parser, JsonElement json,
- Message.Builder builder) throws InvalidProtocolBufferException {
- parser.mergeValue(json, builder);
- }
- });
+ @Override
+ public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+ throws InvalidProtocolBufferException {
+ parser.mergeValue(json, builder);
+ }
+ });
return parsers;
}
-
+
private void merge(JsonElement json, Message.Builder builder)
throws InvalidProtocolBufferException {
- WellKnownTypeParser specialParser = wellKnownTypeParsers.get(
- builder.getDescriptorForType().getFullName());
+ WellKnownTypeParser specialParser =
+ wellKnownTypeParsers.get(builder.getDescriptorForType().getFullName());
if (specialParser != null) {
specialParser.merge(this, json, builder);
return;
}
mergeMessage(json, builder, false);
}
-
+
// Maps from camel-case field names to FieldDescriptor.
private final Map<Descriptor, Map<String, FieldDescriptor>> fieldNameMaps =
new HashMap<Descriptor, Map<String, FieldDescriptor>>();
-
- private Map<String, FieldDescriptor> getFieldNameMap(
- Descriptor descriptor) {
+
+ private Map<String, FieldDescriptor> getFieldNameMap(Descriptor descriptor) {
if (!fieldNameMaps.containsKey(descriptor)) {
- Map<String, FieldDescriptor> fieldNameMap =
- new HashMap<String, FieldDescriptor>();
+ Map<String, FieldDescriptor> fieldNameMap = new HashMap<String, FieldDescriptor>();
for (FieldDescriptor field : descriptor.getFields()) {
fieldNameMap.put(field.getName(), field);
fieldNameMap.put(field.getJsonName(), field);
@@ -1116,64 +1213,67 @@ public class JsonFormat {
}
return fieldNameMaps.get(descriptor);
}
-
- private void mergeMessage(JsonElement json, Message.Builder builder,
- boolean skipTypeUrl) throws InvalidProtocolBufferException {
+
+ private void mergeMessage(JsonElement json, Message.Builder builder, boolean skipTypeUrl)
+ throws InvalidProtocolBufferException {
if (!(json instanceof JsonObject)) {
- throw new InvalidProtocolBufferException(
- "Expect message object but got: " + json);
+ throw new InvalidProtocolBufferException("Expect message object but got: " + json);
}
JsonObject object = (JsonObject) json;
- Map<String, FieldDescriptor> fieldNameMap =
- getFieldNameMap(builder.getDescriptorForType());
+ Map<String, FieldDescriptor> fieldNameMap = getFieldNameMap(builder.getDescriptorForType());
for (Map.Entry<String, JsonElement> entry : object.entrySet()) {
if (skipTypeUrl && entry.getKey().equals("@type")) {
continue;
}
FieldDescriptor field = fieldNameMap.get(entry.getKey());
if (field == null) {
+ if (ignoringUnknownFields) {
+ continue;
+ }
throw new InvalidProtocolBufferException(
- "Cannot find field: " + entry.getKey() + " in message "
- + builder.getDescriptorForType().getFullName());
+ "Cannot find field: "
+ + entry.getKey()
+ + " in message "
+ + builder.getDescriptorForType().getFullName());
}
mergeField(field, entry.getValue(), builder);
}
}
-
+
private void mergeAny(JsonElement json, Message.Builder builder)
throws InvalidProtocolBufferException {
Descriptor descriptor = builder.getDescriptorForType();
FieldDescriptor typeUrlField = descriptor.findFieldByName("type_url");
FieldDescriptor valueField = descriptor.findFieldByName("value");
// Validates type of the message. Note that we can't just cast the message
- // to com.google.protobuf.Any because it might be a DynamicMessage.
- if (typeUrlField == null || valueField == null
+ // to com.google.protobuf.Any because it might be a DynamicMessage.
+ if (typeUrlField == null
+ || valueField == null
|| typeUrlField.getType() != FieldDescriptor.Type.STRING
|| valueField.getType() != FieldDescriptor.Type.BYTES) {
throw new InvalidProtocolBufferException("Invalid Any type.");
}
-
+
if (!(json instanceof JsonObject)) {
- throw new InvalidProtocolBufferException(
- "Expect message object but got: " + json);
+ throw new InvalidProtocolBufferException("Expect message object but got: " + json);
}
JsonObject object = (JsonObject) json;
+ if (object.entrySet().isEmpty()) {
+ return; // builder never modified, so it will end up building the default instance of Any
+ }
JsonElement typeUrlElement = object.get("@type");
if (typeUrlElement == null) {
- throw new InvalidProtocolBufferException(
- "Missing type url when parsing: " + json);
+ throw new InvalidProtocolBufferException("Missing type url when parsing: " + json);
}
String typeUrl = typeUrlElement.getAsString();
Descriptor contentType = registry.find(getTypeName(typeUrl));
if (contentType == null) {
- throw new InvalidProtocolBufferException(
- "Cannot resolve type: " + typeUrl);
+ throw new InvalidProtocolBufferException("Cannot resolve type: " + typeUrl);
}
builder.setField(typeUrlField, typeUrl);
Message.Builder contentBuilder =
DynamicMessage.getDefaultInstance(contentType).newBuilderForType();
- WellKnownTypeParser specialParser =
- wellKnownTypeParsers.get(contentType.getFullName());
+ WellKnownTypeParser specialParser = wellKnownTypeParsers.get(contentType.getFullName());
if (specialParser != null) {
JsonElement value = object.get("value");
if (value != null) {
@@ -1184,35 +1284,33 @@ public class JsonFormat {
}
builder.setField(valueField, contentBuilder.build().toByteString());
}
-
+
private void mergeFieldMask(JsonElement json, Message.Builder builder)
throws InvalidProtocolBufferException {
- FieldMask value = FieldMaskUtil.fromString(json.getAsString());
+ FieldMask value = FieldMaskUtil.fromJsonString(json.getAsString());
builder.mergeFrom(value.toByteString());
}
-
+
private void mergeTimestamp(JsonElement json, Message.Builder builder)
throws InvalidProtocolBufferException {
try {
- Timestamp value = TimeUtil.parseTimestamp(json.getAsString());
+ Timestamp value = Timestamps.parse(json.getAsString());
builder.mergeFrom(value.toByteString());
} catch (ParseException e) {
- throw new InvalidProtocolBufferException(
- "Failed to parse timestamp: " + json);
+ throw new InvalidProtocolBufferException("Failed to parse timestamp: " + json);
}
}
-
+
private void mergeDuration(JsonElement json, Message.Builder builder)
throws InvalidProtocolBufferException {
try {
- Duration value = TimeUtil.parseDuration(json.getAsString());
+ Duration value = Durations.parse(json.getAsString());
builder.mergeFrom(value.toByteString());
} catch (ParseException e) {
- throw new InvalidProtocolBufferException(
- "Failed to parse duration: " + json);
+ throw new InvalidProtocolBufferException("Failed to parse duration: " + json);
}
}
-
+
private void mergeStruct(JsonElement json, Message.Builder builder)
throws InvalidProtocolBufferException {
Descriptor descriptor = builder.getDescriptorForType();
@@ -1232,21 +1330,18 @@ public class JsonFormat {
}
mergeRepeatedField(field, json, builder);
}
-
+
private void mergeValue(JsonElement json, Message.Builder builder)
throws InvalidProtocolBufferException {
Descriptor type = builder.getDescriptorForType();
if (json instanceof JsonPrimitive) {
JsonPrimitive primitive = (JsonPrimitive) json;
if (primitive.isBoolean()) {
- builder.setField(type.findFieldByName("bool_value"),
- primitive.getAsBoolean());
+ builder.setField(type.findFieldByName("bool_value"), primitive.getAsBoolean());
} else if (primitive.isNumber()) {
- builder.setField(type.findFieldByName("number_value"),
- primitive.getAsDouble());
+ builder.setField(type.findFieldByName("number_value"), primitive.getAsDouble());
} else {
- builder.setField(type.findFieldByName("string_value"),
- primitive.getAsString());
+ builder.setField(type.findFieldByName("string_value"), primitive.getAsString());
}
} else if (json instanceof JsonObject) {
FieldDescriptor field = type.findFieldByName("struct_value");
@@ -1258,24 +1353,26 @@ public class JsonFormat {
Message.Builder listBuilder = builder.newBuilderForField(field);
merge(json, listBuilder);
builder.setField(field, listBuilder.build());
+ } else if (json instanceof JsonNull) {
+ builder.setField(
+ type.findFieldByName("null_value"), NullValue.NULL_VALUE.getValueDescriptor());
} else {
throw new IllegalStateException("Unexpected json data: " + json);
}
}
-
+
private void mergeWrapper(JsonElement json, Message.Builder builder)
throws InvalidProtocolBufferException {
Descriptor type = builder.getDescriptorForType();
FieldDescriptor field = type.findFieldByName("value");
if (field == null) {
- throw new InvalidProtocolBufferException(
- "Invalid wrapper type: " + type.getFullName());
+ throw new InvalidProtocolBufferException("Invalid wrapper type: " + type.getFullName());
}
builder.setField(field, parseFieldValue(field, json, builder));
}
-
- private void mergeField(FieldDescriptor field, JsonElement json,
- Message.Builder builder) throws InvalidProtocolBufferException {
+
+ private void mergeField(FieldDescriptor field, JsonElement json, Message.Builder builder)
+ throws InvalidProtocolBufferException {
if (field.isRepeated()) {
if (builder.getRepeatedFieldCount(field) > 0) {
throw new InvalidProtocolBufferException(
@@ -1290,8 +1387,11 @@ public class JsonFormat {
&& builder.getOneofFieldDescriptor(field.getContainingOneof()) != null) {
FieldDescriptor other = builder.getOneofFieldDescriptor(field.getContainingOneof());
throw new InvalidProtocolBufferException(
- "Cannot set field " + field.getFullName() + " because another field "
- + other.getFullName() + " belonging to the same oneof has already been set ");
+ "Cannot set field "
+ + field.getFullName()
+ + " because another field "
+ + other.getFullName()
+ + " belonging to the same oneof has already been set ");
}
}
if (field.isRepeated() && json instanceof JsonNull) {
@@ -1310,44 +1410,38 @@ public class JsonFormat {
}
}
}
-
- private void mergeMapField(FieldDescriptor field, JsonElement json,
- Message.Builder builder) throws InvalidProtocolBufferException {
+
+ private void mergeMapField(FieldDescriptor field, JsonElement json, Message.Builder builder)
+ throws InvalidProtocolBufferException {
if (!(json instanceof JsonObject)) {
- throw new InvalidProtocolBufferException(
- "Expect a map object but found: " + json);
+ throw new InvalidProtocolBufferException("Expect a map object but found: " + json);
}
Descriptor type = field.getMessageType();
FieldDescriptor keyField = type.findFieldByName("key");
FieldDescriptor valueField = type.findFieldByName("value");
if (keyField == null || valueField == null) {
- throw new InvalidProtocolBufferException(
- "Invalid map field: " + field.getFullName());
+ throw new InvalidProtocolBufferException("Invalid map field: " + field.getFullName());
}
JsonObject object = (JsonObject) json;
for (Map.Entry<String, JsonElement> entry : object.entrySet()) {
Message.Builder entryBuilder = builder.newBuilderForField(field);
- Object key = parseFieldValue(
- keyField, new JsonPrimitive(entry.getKey()), entryBuilder);
- Object value = parseFieldValue(
- valueField, entry.getValue(), entryBuilder);
+ Object key = parseFieldValue(keyField, new JsonPrimitive(entry.getKey()), entryBuilder);
+ Object value = parseFieldValue(valueField, entry.getValue(), entryBuilder);
if (value == null) {
- throw new InvalidProtocolBufferException(
- "Map value cannot be null.");
+ throw new InvalidProtocolBufferException("Map value cannot be null.");
}
entryBuilder.setField(keyField, key);
entryBuilder.setField(valueField, value);
builder.addRepeatedField(field, entryBuilder.build());
}
}
-
+
/**
* Gets the default value for a field type. Note that we use proto3
* language defaults and ignore any default values set through the
- * proto "default" option.
+ * proto "default" option.
*/
- private Object getDefaultValue(FieldDescriptor field,
- Message.Builder builder) {
+ private Object getDefaultValue(FieldDescriptor field, Message.Builder builder) {
switch (field.getType()) {
case INT32:
case SINT32:
@@ -1377,30 +1471,27 @@ public class JsonFormat {
case GROUP:
return builder.newBuilderForField(field).getDefaultInstanceForType();
default:
- throw new IllegalStateException(
- "Invalid field type: " + field.getType());
+ throw new IllegalStateException("Invalid field type: " + field.getType());
}
}
-
- private void mergeRepeatedField(FieldDescriptor field, JsonElement json,
- Message.Builder builder) throws InvalidProtocolBufferException {
+
+ private void mergeRepeatedField(
+ FieldDescriptor field, JsonElement json, Message.Builder builder)
+ throws InvalidProtocolBufferException {
if (!(json instanceof JsonArray)) {
- throw new InvalidProtocolBufferException(
- "Expect an array but found: " + json);
+ throw new InvalidProtocolBufferException("Expect an array but found: " + json);
}
JsonArray array = (JsonArray) json;
for (int i = 0; i < array.size(); ++i) {
Object value = parseFieldValue(field, array.get(i), builder);
if (value == null) {
- throw new InvalidProtocolBufferException(
- "Repeated field elements cannot be null");
+ throw new InvalidProtocolBufferException("Repeated field elements cannot be null");
}
builder.addRepeatedField(field, value);
}
}
-
- private int parseInt32(JsonElement json)
- throws InvalidProtocolBufferException {
+
+ private int parseInt32(JsonElement json) throws InvalidProtocolBufferException {
try {
return Integer.parseInt(json.getAsString());
} catch (Exception e) {
@@ -1416,9 +1507,8 @@ public class JsonFormat {
throw new InvalidProtocolBufferException("Not an int32 value: " + json);
}
}
-
- private long parseInt64(JsonElement json)
- throws InvalidProtocolBufferException {
+
+ private long parseInt64(JsonElement json) throws InvalidProtocolBufferException {
try {
return Long.parseLong(json.getAsString());
} catch (Exception e) {
@@ -1434,14 +1524,12 @@ public class JsonFormat {
throw new InvalidProtocolBufferException("Not an int32 value: " + json);
}
}
-
- private int parseUint32(JsonElement json)
- throws InvalidProtocolBufferException {
+
+ private int parseUint32(JsonElement json) throws InvalidProtocolBufferException {
try {
long result = Long.parseLong(json.getAsString());
if (result < 0 || result > 0xFFFFFFFFL) {
- throw new InvalidProtocolBufferException(
- "Out of range uint32 value: " + json);
+ throw new InvalidProtocolBufferException("Out of range uint32 value: " + json);
}
return (int) result;
} catch (InvalidProtocolBufferException e) {
@@ -1462,35 +1550,28 @@ public class JsonFormat {
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (Exception e) {
- throw new InvalidProtocolBufferException(
- "Not an uint32 value: " + json);
+ throw new InvalidProtocolBufferException("Not an uint32 value: " + json);
}
}
-
- private static final BigInteger MAX_UINT64 =
- new BigInteger("FFFFFFFFFFFFFFFF", 16);
-
- private long parseUint64(JsonElement json)
- throws InvalidProtocolBufferException {
+
+ private static final BigInteger MAX_UINT64 = new BigInteger("FFFFFFFFFFFFFFFF", 16);
+
+ private long parseUint64(JsonElement json) throws InvalidProtocolBufferException {
try {
BigDecimal decimalValue = new BigDecimal(json.getAsString());
BigInteger value = decimalValue.toBigIntegerExact();
- if (value.compareTo(BigInteger.ZERO) < 0
- || value.compareTo(MAX_UINT64) > 0) {
- throw new InvalidProtocolBufferException(
- "Out of range uint64 value: " + json);
+ if (value.compareTo(BigInteger.ZERO) < 0 || value.compareTo(MAX_UINT64) > 0) {
+ throw new InvalidProtocolBufferException("Out of range uint64 value: " + json);
}
return value.longValue();
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (Exception e) {
- throw new InvalidProtocolBufferException(
- "Not an uint64 value: " + json);
+ throw new InvalidProtocolBufferException("Not an uint64 value: " + json);
}
}
-
- private boolean parseBool(JsonElement json)
- throws InvalidProtocolBufferException {
+
+ private boolean parseBool(JsonElement json) throws InvalidProtocolBufferException {
if (json.getAsString().equals("true")) {
return true;
}
@@ -1499,11 +1580,10 @@ public class JsonFormat {
}
throw new InvalidProtocolBufferException("Invalid bool value: " + json);
}
-
+
private static final double EPSILON = 1e-6;
-
- private float parseFloat(JsonElement json)
- throws InvalidProtocolBufferException {
+
+ private float parseFloat(JsonElement json) throws InvalidProtocolBufferException {
if (json.getAsString().equals("NaN")) {
return Float.NaN;
} else if (json.getAsString().equals("Infinity")) {
@@ -1521,8 +1601,7 @@ public class JsonFormat {
// of tolerance when checking whether the float value is in range.
if (value > Float.MAX_VALUE * (1.0 + EPSILON)
|| value < -Float.MAX_VALUE * (1.0 + EPSILON)) {
- throw new InvalidProtocolBufferException(
- "Out of range float value: " + json);
+ throw new InvalidProtocolBufferException("Out of range float value: " + json);
}
return (float) value;
} catch (InvalidProtocolBufferException e) {
@@ -1531,19 +1610,17 @@ public class JsonFormat {
throw new InvalidProtocolBufferException("Not a float value: " + json);
}
}
-
- private static final BigDecimal MORE_THAN_ONE = new BigDecimal(
- String.valueOf(1.0 + EPSILON));
+
+ private static final BigDecimal MORE_THAN_ONE = new BigDecimal(String.valueOf(1.0 + EPSILON));
// When a float value is printed, the printed value might be a little
// larger or smaller due to precision loss. Here we need to add a bit
// of tolerance when checking whether the float value is in range.
- private static final BigDecimal MAX_DOUBLE = new BigDecimal(
- String.valueOf(Double.MAX_VALUE)).multiply(MORE_THAN_ONE);
- private static final BigDecimal MIN_DOUBLE = new BigDecimal(
- String.valueOf(-Double.MAX_VALUE)).multiply(MORE_THAN_ONE);
-
- private double parseDouble(JsonElement json)
- throws InvalidProtocolBufferException {
+ private static final BigDecimal MAX_DOUBLE =
+ new BigDecimal(String.valueOf(Double.MAX_VALUE)).multiply(MORE_THAN_ONE);
+ private static final BigDecimal MIN_DOUBLE =
+ new BigDecimal(String.valueOf(-Double.MAX_VALUE)).multiply(MORE_THAN_ONE);
+
+ private double parseDouble(JsonElement json) throws InvalidProtocolBufferException {
if (json.getAsString().equals("NaN")) {
return Double.NaN;
} else if (json.getAsString().equals("Infinity")) {
@@ -1556,36 +1633,27 @@ public class JsonFormat {
// accepts all values. Here we parse the value into a BigDecimal and do
// explicit range check on it.
BigDecimal value = new BigDecimal(json.getAsString());
- if (value.compareTo(MAX_DOUBLE) > 0
- || value.compareTo(MIN_DOUBLE) < 0) {
- throw new InvalidProtocolBufferException(
- "Out of range double value: " + json);
+ if (value.compareTo(MAX_DOUBLE) > 0 || value.compareTo(MIN_DOUBLE) < 0) {
+ throw new InvalidProtocolBufferException("Out of range double value: " + json);
}
return value.doubleValue();
} catch (InvalidProtocolBufferException e) {
throw e;
} catch (Exception e) {
- throw new InvalidProtocolBufferException(
- "Not an double value: " + json);
+ throw new InvalidProtocolBufferException("Not an double value: " + json);
}
}
-
+
private String parseString(JsonElement json) {
return json.getAsString();
}
-
+
private ByteString parseBytes(JsonElement json) throws InvalidProtocolBufferException {
- String encoded = json.getAsString();
- if (encoded.length() % 4 != 0) {
- throw new InvalidProtocolBufferException(
- "Bytes field is not encoded in standard BASE64 with paddings: " + encoded);
- }
- return ByteString.copyFrom(
- BaseEncoding.base64().decode(json.getAsString()));
+ return ByteString.copyFrom(BaseEncoding.base64().decode(json.getAsString()));
}
-
- private EnumValueDescriptor parseEnum(EnumDescriptor enumDescriptor,
- JsonElement json) throws InvalidProtocolBufferException {
+
+ private EnumValueDescriptor parseEnum(EnumDescriptor enumDescriptor, JsonElement json)
+ throws InvalidProtocolBufferException {
String value = json.getAsString();
EnumValueDescriptor result = enumDescriptor.findValueByName(value);
if (result == null) {
@@ -1602,27 +1670,28 @@ public class JsonFormat {
// that's not the exception we want the user to see. Since result == null, we will throw
// an exception later.
}
-
+
if (result == null) {
throw new InvalidProtocolBufferException(
- "Invalid enum value: " + value + " for enum type: "
- + enumDescriptor.getFullName());
+ "Invalid enum value: " + value + " for enum type: " + enumDescriptor.getFullName());
}
}
return result;
}
-
- private Object parseFieldValue(FieldDescriptor field, JsonElement json,
- Message.Builder builder) throws InvalidProtocolBufferException {
+
+ private Object parseFieldValue(FieldDescriptor field, JsonElement json, Message.Builder builder)
+ throws InvalidProtocolBufferException {
if (json instanceof JsonNull) {
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE
- && field.getMessageType().getFullName().equals(
- Value.getDescriptor().getFullName())) {
+ && field.getMessageType().getFullName().equals(Value.getDescriptor().getFullName())) {
// For every other type, "null" means absence, but for the special
// Value message, it means the "null_value" field has been set.
Value value = Value.newBuilder().setNullValueValue(0).build();
- return builder.newBuilderForField(field).mergeFrom(
- value.toByteString()).build();
+ return builder.newBuilderForField(field).mergeFrom(value.toByteString()).build();
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM
+ && field.getEnumType().getFullName().equals(NullValue.getDescriptor().getFullName())) {
+ // If the type of the field is a NullValue, then the value should be explicitly set.
+ return field.getEnumType().findValueByNumber(0);
}
return null;
}
@@ -1642,7 +1711,7 @@ public class JsonFormat {
case FLOAT:
return parseFloat(json);
-
+
case DOUBLE:
return parseDouble(json);
@@ -1665,14 +1734,18 @@ public class JsonFormat {
case MESSAGE:
case GROUP:
+ if (currentDepth >= recursionLimit) {
+ throw new InvalidProtocolBufferException("Hit recursion limit.");
+ }
+ ++currentDepth;
Message.Builder subBuilder = builder.newBuilderForField(field);
merge(json, subBuilder);
+ --currentDepth;
return subBuilder.build();
-
+
default:
- throw new InvalidProtocolBufferException(
- "Invalid field type: " + field.getType());
- }
+ throw new InvalidProtocolBufferException("Invalid field type: " + field.getType());
+ }
}
}
}

Powered by Google App Engine
This is Rietveld 408576698