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 ac712c94296be1fe92370c1d7a0323ac3bf60b99..76f3437a6b7a4e628e33269e9cbf7e73756deb88 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,7 +49,6 @@ 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; |
@@ -61,13 +60,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; |
@@ -93,17 +92,18 @@ 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, false); |
+ return new Printer(TypeRegistry.getEmptyTypeRegistry(), false, false); |
} |
- |
+ |
/** |
* A Printer converts protobuf message to JSON format. |
*/ |
@@ -111,34 +111,27 @@ 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 omittingInsignificantWhitespace) { |
+ boolean preservingProtoFieldNames) { |
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, |
- omittingInsignificantWhitespace); |
+ return new Printer(registry, includingDefaultValueFields, preservingProtoFieldNames); |
} |
/** |
@@ -148,8 +141,7 @@ public class JsonFormat { |
* {@link Printer}. |
*/ |
public Printer includingDefaultValueFields() { |
- return new Printer( |
- registry, true, preservingProtoFieldNames, omittingInsignificantWhitespace); |
+ return new Printer(registry, true, preservingProtoFieldNames); |
} |
/** |
@@ -159,54 +151,30 @@ public class JsonFormat { |
* current {@link Printer}. |
*/ |
public Printer preservingProtoFieldNames() { |
- 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); |
+ return new Printer(registry, includingDefaultValueFields, 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, |
- omittingInsignificantWhitespace) |
+ new PrinterImpl(registry, includingDefaultValueFields, preservingProtoFieldNames, output) |
.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); |
@@ -224,75 +192,57 @@ public class JsonFormat { |
* Creates a {@link Parser} with default configuration. |
*/ |
public static Parser parser() { |
- return new Parser(TypeRegistry.getEmptyTypeRegistry(), false, Parser.DEFAULT_RECURSION_LIMIT); |
+ return new Parser(TypeRegistry.getEmptyTypeRegistry()); |
} |
- |
+ |
/** |
* A Parser parses JSON to protobuf message. |
*/ |
public static class Parser { |
private final TypeRegistry 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; |
+ |
+ private Parser(TypeRegistry registry) { |
+ this.registry = registry; |
} |
- |
+ |
/** |
* 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, 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); |
+ return new Parser(registry); |
} |
- |
+ |
/** |
* 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, ignoringUnknownFields, recursionLimit).merge(json, builder); |
+ new ParserImpl(registry).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, ignoringUnknownFields, recursionLimit).merge(json, builder); |
- } |
- |
- // For testing only. |
- Parser usingRecursionLimit(int recursionLimit) { |
- return new Parser(registry, ignoringUnknownFields, recursionLimit); |
+ new ParserImpl(registry).merge(json, builder); |
} |
} |
@@ -305,8 +255,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() { |
@@ -343,7 +293,8 @@ 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; |
@@ -355,7 +306,8 @@ 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()); |
@@ -393,7 +345,8 @@ 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; |
} |
@@ -401,58 +354,20 @@ 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 PrettyTextGenerator implements TextGenerator { |
+ private static final class TextGenerator { |
private final Appendable output; |
private final StringBuilder indent = new StringBuilder(); |
private boolean atStartOfLine = true; |
- private PrettyTextGenerator(final Appendable output) { |
+ private TextGenerator(final Appendable output) { |
this.output = output; |
} |
@@ -472,7 +387,8 @@ 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); |
} |
@@ -516,8 +432,6 @@ 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(); |
@@ -527,60 +441,54 @@ public class JsonFormat { |
TypeRegistry registry, |
boolean includingDefaultValueFields, |
boolean preservingProtoFieldNames, |
- Appendable jsonOutput, |
- boolean omittingInsignificantWhitespace) { |
+ Appendable jsonOutput) { |
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); |
@@ -591,75 +499,70 @@ 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."); |
@@ -668,21 +571,22 @@ 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("{" + blankOrNewLine); |
+ generator.print("{\n"); |
generator.indent(); |
- generator.print("\"@type\":" + blankOrSpace + gson.toJson(typeUrl) + "," + blankOrNewLine); |
- generator.print("\"value\":" + blankOrSpace); |
+ generator.print("\"@type\": " + gson.toJson(typeUrl) + ",\n"); |
+ generator.print("\"value\": "); |
printer.print(this, contentMessage); |
- generator.print(blankOrNewLine); |
+ generator.print("\n"); |
generator.outdent(); |
generator.print("}"); |
} else { |
@@ -690,7 +594,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(); |
@@ -702,7 +606,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(); |
@@ -710,25 +614,26 @@ 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("\"" + Timestamps.toString(value) + "\""); |
+ generator.print("\"" + TimeUtil.toString(value) + "\""); |
} |
- |
+ |
/** Prints google.protobuf.Duration */ |
private void printDuration(MessageOrBuilder message) throws IOException { |
Duration value = Duration.parseFrom(toByteString(message)); |
- generator.print("\"" + Durations.toString(value) + "\""); |
+ generator.print("\"" + TimeUtil.toString(value) + "\""); |
+ |
} |
- |
+ |
/** Prints google.protobuf.FieldMask */ |
private void printFieldMask(MessageOrBuilder message) throws IOException { |
FieldMask value = FieldMask.parseFrom(toByteString(message)); |
- generator.print("\"" + FieldMaskUtil.toJsonString(value) + "\""); |
+ generator.print("\"" + FieldMaskUtil.toString(value) + "\""); |
} |
- |
+ |
/** Prints google.protobuf.Struct */ |
private void printStruct(MessageOrBuilder message) throws IOException { |
Descriptor descriptor = message.getDescriptorForType(); |
@@ -739,7 +644,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. |
@@ -758,7 +663,7 @@ public class JsonFormat { |
printSingleFieldValue(entry.getKey(), entry.getValue()); |
} |
} |
- |
+ |
/** Prints google.protobuf.ListValue */ |
private void printListValue(MessageOrBuilder message) throws IOException { |
Descriptor descriptor = message.getDescriptorForType(); |
@@ -770,31 +675,26 @@ public class JsonFormat { |
} |
/** Prints a regular message with an optional type URL. */ |
- private void print(MessageOrBuilder message, String typeUrl) throws IOException { |
- generator.print("{" + blankOrNewLine); |
+ private void print(MessageOrBuilder message, String typeUrl) |
+ throws IOException { |
+ generator.print("{\n"); |
generator.indent(); |
boolean printedField = false; |
if (typeUrl != null) { |
- generator.print("\"@type\":" + blankOrSpace + gson.toJson(typeUrl)); |
+ generator.print("\"@type\": " + 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()) { |
- 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; |
- } |
+ 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; |
} |
fieldsToPrint.put(field, message.getField(field)); |
} |
@@ -804,26 +704,27 @@ public class JsonFormat { |
for (Map.Entry<FieldDescriptor, Object> field : fieldsToPrint.entrySet()) { |
if (printedField) { |
// Add line-endings for the previous field. |
- generator.print("," + blankOrNewLine); |
+ generator.print(",\n"); |
} else { |
printedField = true; |
} |
printField(field.getKey(), field.getValue()); |
} |
- |
+ |
// Add line-endings for the last field. |
if (printedField) { |
- generator.print(blankOrNewLine); |
+ generator.print("\n"); |
} |
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() + "\":" + blankOrSpace); |
+ generator.print("\"" + field.getName() + "\": "); |
} else { |
- generator.print("\"" + field.getJsonName() + "\":" + blankOrSpace); |
+ generator.print("\"" + field.getJsonName() + "\": "); |
} |
if (field.isMapField()) { |
printMapFieldValue(field, value); |
@@ -833,14 +734,15 @@ 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("," + blankOrSpace); |
+ generator.print(", "); |
} else { |
printedElement = true; |
} |
@@ -848,16 +750,17 @@ 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("{" + blankOrNewLine); |
+ generator.print("{\n"); |
generator.indent(); |
boolean printedElement = false; |
for (Object element : (List) value) { |
@@ -865,35 +768,36 @@ public class JsonFormat { |
Object entryKey = entry.getField(keyField); |
Object entryValue = entry.getField(valueField); |
if (printedElement) { |
- generator.print("," + blankOrNewLine); |
+ generator.print(",\n"); |
} else { |
printedElement = true; |
} |
// Key fields are always double-quoted. |
printSingleFieldValue(keyField, entryKey, true); |
- generator.print(":" + blankOrSpace); |
+ generator.print(": "); |
printSingleFieldValue(valueField, entryValue); |
} |
if (printedElement) { |
- generator.print(blankOrNewLine); |
+ generator.print("\n"); |
} |
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: |
@@ -947,7 +851,7 @@ public class JsonFormat { |
} |
} |
break; |
- |
+ |
case DOUBLE: |
Double doubleValue = (Double) value; |
if (doubleValue.isNaN()) { |
@@ -991,13 +895,15 @@ 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("\""); |
@@ -1008,9 +914,11 @@ 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; |
@@ -1039,40 +947,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; |
- private final boolean ignoringUnknownFields; |
- private final int recursionLimit; |
- private int currentDepth; |
- |
- ParserImpl(TypeRegistry registry, boolean ignoreUnknownFields, int recursionLimit) { |
+ |
+ ParserImpl(TypeRegistry registry) { |
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); |
@@ -1084,36 +992,35 @@ 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); |
@@ -1124,86 +1031,82 @@ 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); |
@@ -1213,67 +1116,64 @@ 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) { |
@@ -1284,33 +1184,35 @@ public class JsonFormat { |
} |
builder.setField(valueField, contentBuilder.build().toByteString()); |
} |
- |
+ |
private void mergeFieldMask(JsonElement json, Message.Builder builder) |
throws InvalidProtocolBufferException { |
- FieldMask value = FieldMaskUtil.fromJsonString(json.getAsString()); |
+ FieldMask value = FieldMaskUtil.fromString(json.getAsString()); |
builder.mergeFrom(value.toByteString()); |
} |
- |
+ |
private void mergeTimestamp(JsonElement json, Message.Builder builder) |
throws InvalidProtocolBufferException { |
try { |
- Timestamp value = Timestamps.parse(json.getAsString()); |
+ Timestamp value = TimeUtil.parseTimestamp(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 = Durations.parse(json.getAsString()); |
+ Duration value = TimeUtil.parseDuration(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(); |
@@ -1330,18 +1232,21 @@ 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"); |
@@ -1353,26 +1258,24 @@ 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( |
@@ -1387,11 +1290,8 @@ 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) { |
@@ -1410,38 +1310,44 @@ 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: |
@@ -1471,27 +1377,30 @@ 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) { |
@@ -1507,8 +1416,9 @@ 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) { |
@@ -1524,12 +1434,14 @@ 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) { |
@@ -1550,28 +1462,35 @@ 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; |
} |
@@ -1580,10 +1499,11 @@ 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")) { |
@@ -1601,7 +1521,8 @@ 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) { |
@@ -1610,17 +1531,19 @@ 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")) { |
@@ -1633,27 +1556,36 @@ 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 { |
- return ByteString.copyFrom(BaseEncoding.base64().decode(json.getAsString())); |
+ 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())); |
} |
- |
- 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) { |
@@ -1670,28 +1602,27 @@ 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(); |
- } 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 builder.newBuilderForField(field).mergeFrom( |
+ value.toByteString()).build(); |
} |
return null; |
} |
@@ -1711,7 +1642,7 @@ public class JsonFormat { |
case FLOAT: |
return parseFloat(json); |
- |
+ |
case DOUBLE: |
return parseDouble(json); |
@@ -1734,18 +1665,14 @@ 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()); |
+ } |
} |
} |
} |