Home | History | Annotate | Download | only in util
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // https://developers.google.com/protocol-buffers/
      4 //
      5 // Redistribution and use in source and binary forms, with or without
      6 // modification, are permitted provided that the following conditions are
      7 // met:
      8 //
      9 //     * Redistributions of source code must retain the above copyright
     10 // notice, this list of conditions and the following disclaimer.
     11 //     * Redistributions in binary form must reproduce the above
     12 // copyright notice, this list of conditions and the following disclaimer
     13 // in the documentation and/or other materials provided with the
     14 // distribution.
     15 //     * Neither the name of Google Inc. nor the names of its
     16 // contributors may be used to endorse or promote products derived from
     17 // this software without specific prior written permission.
     18 //
     19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 package com.google.protobuf.util;
     32 
     33 import com.google.common.io.BaseEncoding;
     34 import com.google.gson.Gson;
     35 import com.google.gson.GsonBuilder;
     36 import com.google.gson.JsonArray;
     37 import com.google.gson.JsonElement;
     38 import com.google.gson.JsonNull;
     39 import com.google.gson.JsonObject;
     40 import com.google.gson.JsonParser;
     41 import com.google.gson.JsonPrimitive;
     42 import com.google.gson.stream.JsonReader;
     43 import com.google.protobuf.Any;
     44 import com.google.protobuf.BoolValue;
     45 import com.google.protobuf.ByteString;
     46 import com.google.protobuf.BytesValue;
     47 import com.google.protobuf.Descriptors.Descriptor;
     48 import com.google.protobuf.Descriptors.EnumDescriptor;
     49 import com.google.protobuf.Descriptors.EnumValueDescriptor;
     50 import com.google.protobuf.Descriptors.FieldDescriptor;
     51 import com.google.protobuf.Descriptors.FileDescriptor;
     52 import com.google.protobuf.DoubleValue;
     53 import com.google.protobuf.Duration;
     54 import com.google.protobuf.DynamicMessage;
     55 import com.google.protobuf.FieldMask;
     56 import com.google.protobuf.FloatValue;
     57 import com.google.protobuf.Int32Value;
     58 import com.google.protobuf.Int64Value;
     59 import com.google.protobuf.InvalidProtocolBufferException;
     60 import com.google.protobuf.ListValue;
     61 import com.google.protobuf.Message;
     62 import com.google.protobuf.MessageOrBuilder;
     63 import com.google.protobuf.StringValue;
     64 import com.google.protobuf.Struct;
     65 import com.google.protobuf.Timestamp;
     66 import com.google.protobuf.UInt32Value;
     67 import com.google.protobuf.UInt64Value;
     68 import com.google.protobuf.Value;
     69 
     70 import java.io.IOException;
     71 import java.io.Reader;
     72 import java.io.StringReader;
     73 import java.math.BigDecimal;
     74 import java.math.BigInteger;
     75 import java.text.ParseException;
     76 import java.util.Collections;
     77 import java.util.HashMap;
     78 import java.util.HashSet;
     79 import java.util.List;
     80 import java.util.Map;
     81 import java.util.Set;
     82 import java.util.TreeMap;
     83 import java.util.logging.Logger;
     84 
     85 /**
     86  * Utility classes to convert protobuf messages to/from JSON format. The JSON
     87  * format follows Proto3 JSON specification and only proto3 features are
     88  * supported. Proto2 only features (e.g., extensions and unknown fields) will
     89  * be discarded in the conversion. That is, when converting proto2 messages
     90  * to JSON format, extensions and unknown fields will be treated as if they
     91  * do not exist. This applies to proto2 messages embedded in proto3 messages
     92  * as well.
     93  */
     94 public class JsonFormat {
     95   private static final Logger logger =
     96       Logger.getLogger(JsonFormat.class.getName());
     97 
     98   private JsonFormat() {}
     99 
    100   /**
    101    * Creates a {@link Printer} with default configurations.
    102    */
    103   public static Printer printer() {
    104     return new Printer(TypeRegistry.getEmptyTypeRegistry(), false, false);
    105   }
    106 
    107   /**
    108    * A Printer converts protobuf message to JSON format.
    109    */
    110   public static class Printer {
    111     private final TypeRegistry registry;
    112     private final boolean includingDefaultValueFields;
    113     private final boolean preservingProtoFieldNames;
    114 
    115     private Printer(
    116         TypeRegistry registry,
    117         boolean includingDefaultValueFields,
    118         boolean preservingProtoFieldNames) {
    119       this.registry = registry;
    120       this.includingDefaultValueFields = includingDefaultValueFields;
    121       this.preservingProtoFieldNames = preservingProtoFieldNames;
    122     }
    123 
    124     /**
    125      * Creates a new {@link Printer} using the given registry. The new Printer
    126      * clones all other configurations from the current {@link Printer}.
    127      *
    128      * @throws IllegalArgumentException if a registry is already set.
    129      */
    130     public Printer usingTypeRegistry(TypeRegistry registry) {
    131       if (this.registry != TypeRegistry.getEmptyTypeRegistry()) {
    132         throw new IllegalArgumentException("Only one registry is allowed.");
    133       }
    134       return new Printer(registry, includingDefaultValueFields, preservingProtoFieldNames);
    135     }
    136 
    137     /**
    138      * Creates a new {@link Printer} that will also print fields set to their
    139      * defaults. Empty repeated fields and map fields will be printed as well.
    140      * The new Printer clones all other configurations from the current
    141      * {@link Printer}.
    142      */
    143     public Printer includingDefaultValueFields() {
    144       return new Printer(registry, true, preservingProtoFieldNames);
    145     }
    146 
    147     /**
    148      * Creates a new {@link Printer} that is configured to use the original proto
    149      * field names as defined in the .proto file rather than converting them to
    150      * lowerCamelCase. The new Printer clones all other configurations from the
    151      * current {@link Printer}.
    152      */
    153     public Printer preservingProtoFieldNames() {
    154       return new Printer(registry, includingDefaultValueFields, true);
    155     }
    156 
    157     /**
    158      * Converts a protobuf message to JSON format.
    159      *
    160      * @throws InvalidProtocolBufferException if the message contains Any types
    161      *         that can't be resolved.
    162      * @throws IOException if writing to the output fails.
    163      */
    164     public void appendTo(MessageOrBuilder message, Appendable output)
    165         throws IOException {
    166       // TODO(xiaofeng): Investigate the allocation overhead and optimize for
    167       // mobile.
    168       new PrinterImpl(registry, includingDefaultValueFields, preservingProtoFieldNames, output)
    169           .print(message);
    170     }
    171 
    172     /**
    173      * Converts a protobuf message to JSON format. Throws exceptions if there
    174      * are unknown Any types in the message.
    175      */
    176     public String print(MessageOrBuilder message)
    177         throws InvalidProtocolBufferException {
    178       try {
    179         StringBuilder builder = new StringBuilder();
    180         appendTo(message, builder);
    181         return builder.toString();
    182       } catch (InvalidProtocolBufferException e) {
    183         throw e;
    184       } catch (IOException e) {
    185         // Unexpected IOException.
    186         throw new IllegalStateException(e);
    187       }
    188     }
    189   }
    190 
    191   /**
    192    * Creates a {@link Parser} with default configuration.
    193    */
    194   public static Parser parser() {
    195     return new Parser(TypeRegistry.getEmptyTypeRegistry());
    196   }
    197 
    198   /**
    199    * A Parser parses JSON to protobuf message.
    200    */
    201   public static class Parser {
    202     private final TypeRegistry registry;
    203 
    204     private Parser(TypeRegistry registry) {
    205       this.registry = registry;
    206     }
    207 
    208     /**
    209      * Creates a new {@link Parser} using the given registry. The new Parser
    210      * clones all other configurations from this Parser.
    211      *
    212      * @throws IllegalArgumentException if a registry is already set.
    213      */
    214     public Parser usingTypeRegistry(TypeRegistry registry) {
    215       if (this.registry != TypeRegistry.getEmptyTypeRegistry()) {
    216         throw new IllegalArgumentException("Only one registry is allowed.");
    217       }
    218       return new Parser(registry);
    219     }
    220 
    221     /**
    222      * Parses from JSON into a protobuf message.
    223      *
    224      * @throws InvalidProtocolBufferException if the input is not valid JSON
    225      *         format or there are unknown fields in the input.
    226      */
    227     public void merge(String json, Message.Builder builder)
    228         throws InvalidProtocolBufferException {
    229       // TODO(xiaofeng): Investigate the allocation overhead and optimize for
    230       // mobile.
    231       new ParserImpl(registry).merge(json, builder);
    232     }
    233 
    234     /**
    235      * Parses from JSON into a protobuf message.
    236      *
    237      * @throws InvalidProtocolBufferException if the input is not valid JSON
    238      *         format or there are unknown fields in the input.
    239      * @throws IOException if reading from the input throws.
    240      */
    241     public void merge(Reader json, Message.Builder builder)
    242         throws IOException {
    243       // TODO(xiaofeng): Investigate the allocation overhead and optimize for
    244       // mobile.
    245       new ParserImpl(registry).merge(json, builder);
    246     }
    247   }
    248 
    249   /**
    250    * A TypeRegistry is used to resolve Any messages in the JSON conversion.
    251    * You must provide a TypeRegistry containing all message types used in
    252    * Any message fields, or the JSON conversion will fail because data
    253    * in Any message fields is unrecognizable. You don't need to supply a
    254    * TypeRegistry if you don't use Any message fields.
    255    */
    256   public static class TypeRegistry {
    257     private static class EmptyTypeRegistryHolder {
    258       private static final TypeRegistry EMPTY = new TypeRegistry(
    259           Collections.<String, Descriptor>emptyMap());
    260     }
    261 
    262     public static TypeRegistry getEmptyTypeRegistry() {
    263       return EmptyTypeRegistryHolder.EMPTY;
    264     }
    265 
    266     public static Builder newBuilder() {
    267       return new Builder();
    268     }
    269 
    270     /**
    271      * Find a type by its full name. Returns null if it cannot be found in
    272      * this {@link TypeRegistry}.
    273      */
    274     public Descriptor find(String name) {
    275       return types.get(name);
    276     }
    277 
    278     private final Map<String, Descriptor> types;
    279 
    280     private TypeRegistry(Map<String, Descriptor> types) {
    281       this.types = types;
    282     }
    283 
    284     /**
    285      * A Builder is used to build {@link TypeRegistry}.
    286      */
    287     public static class Builder {
    288       private Builder() {}
    289 
    290       /**
    291        * Adds a message type and all types defined in the same .proto file as
    292        * well as all transitively imported .proto files to this {@link Builder}.
    293        */
    294       public Builder add(Descriptor messageType) {
    295         if (types == null) {
    296           throw new IllegalStateException(
    297               "A TypeRegistry.Builer can only be used once.");
    298         }
    299         addFile(messageType.getFile());
    300         return this;
    301       }
    302 
    303       /**
    304        * Adds message types and all types defined in the same .proto file as
    305        * well as all transitively imported .proto files to this {@link Builder}.
    306        */
    307       public Builder add(Iterable<Descriptor> messageTypes) {
    308         if (types == null) {
    309           throw new IllegalStateException(
    310               "A TypeRegistry.Builer can only be used once.");
    311         }
    312         for (Descriptor type : messageTypes) {
    313           addFile(type.getFile());
    314         }
    315         return this;
    316       }
    317 
    318       /**
    319        * Builds a {@link TypeRegistry}. This method can only be called once for
    320        * one Builder.
    321        */
    322       public TypeRegistry build() {
    323         TypeRegistry result = new TypeRegistry(types);
    324         // Make sure the built {@link TypeRegistry} is immutable.
    325         types = null;
    326         return result;
    327       }
    328 
    329       private void addFile(FileDescriptor file) {
    330         // Skip the file if it's already added.
    331         if (!files.add(file.getFullName())) {
    332           return;
    333         }
    334         for (FileDescriptor dependency : file.getDependencies()) {
    335           addFile(dependency);
    336         }
    337         for (Descriptor message : file.getMessageTypes()) {
    338           addMessage(message);
    339         }
    340       }
    341 
    342       private void addMessage(Descriptor message) {
    343         for (Descriptor nestedType : message.getNestedTypes()) {
    344           addMessage(nestedType);
    345         }
    346 
    347         if (types.containsKey(message.getFullName())) {
    348           logger.warning("Type " + message.getFullName()
    349               + " is added multiple times.");
    350           return;
    351         }
    352 
    353         types.put(message.getFullName(), message);
    354       }
    355 
    356       private final Set<String> files = new HashSet<String>();
    357       private Map<String, Descriptor> types =
    358           new HashMap<String, Descriptor>();
    359     }
    360   }
    361 
    362   /**
    363    * A TextGenerator adds indentation when writing formatted text.
    364    */
    365   private static final class TextGenerator {
    366     private final Appendable output;
    367     private final StringBuilder indent = new StringBuilder();
    368     private boolean atStartOfLine = true;
    369 
    370     private TextGenerator(final Appendable output) {
    371       this.output = output;
    372     }
    373 
    374     /**
    375      * Indent text by two spaces.  After calling Indent(), two spaces will be
    376      * inserted at the beginning of each line of text.  Indent() may be called
    377      * multiple times to produce deeper indents.
    378      */
    379     public void indent() {
    380       indent.append("  ");
    381     }
    382 
    383     /**
    384      * Reduces the current indent level by two spaces, or crashes if the indent
    385      * level is zero.
    386      */
    387     public void outdent() {
    388       final int length = indent.length();
    389       if (length < 2) {
    390         throw new IllegalArgumentException(
    391             " Outdent() without matching Indent().");
    392       }
    393       indent.delete(length - 2, length);
    394     }
    395 
    396     /**
    397      * Print text to the output stream.
    398      */
    399     public void print(final CharSequence text) throws IOException {
    400       final int size = text.length();
    401       int pos = 0;
    402 
    403       for (int i = 0; i < size; i++) {
    404         if (text.charAt(i) == '\n') {
    405           write(text.subSequence(pos, i + 1));
    406           pos = i + 1;
    407           atStartOfLine = true;
    408         }
    409       }
    410       write(text.subSequence(pos, size));
    411     }
    412 
    413     private void write(final CharSequence data) throws IOException {
    414       if (data.length() == 0) {
    415         return;
    416       }
    417       if (atStartOfLine) {
    418         atStartOfLine = false;
    419         output.append(indent);
    420       }
    421       output.append(data);
    422     }
    423   }
    424 
    425   /**
    426    * A Printer converts protobuf messages to JSON format.
    427    */
    428   private static final class PrinterImpl {
    429     private final TypeRegistry registry;
    430     private final boolean includingDefaultValueFields;
    431     private final boolean preservingProtoFieldNames;
    432     private final TextGenerator generator;
    433     // We use Gson to help handle string escapes.
    434     private final Gson gson;
    435 
    436     private static class GsonHolder {
    437       private static final Gson DEFAULT_GSON = new GsonBuilder().disableHtmlEscaping().create();
    438     }
    439 
    440     PrinterImpl(
    441         TypeRegistry registry,
    442         boolean includingDefaultValueFields,
    443         boolean preservingProtoFieldNames,
    444         Appendable jsonOutput) {
    445       this.registry = registry;
    446       this.includingDefaultValueFields = includingDefaultValueFields;
    447       this.preservingProtoFieldNames = preservingProtoFieldNames;
    448       this.generator = new TextGenerator(jsonOutput);
    449       this.gson = GsonHolder.DEFAULT_GSON;
    450     }
    451 
    452     void print(MessageOrBuilder message) throws IOException {
    453       WellKnownTypePrinter specialPrinter = wellKnownTypePrinters.get(
    454           message.getDescriptorForType().getFullName());
    455       if (specialPrinter != null) {
    456         specialPrinter.print(this, message);
    457         return;
    458       }
    459       print(message, null);
    460     }
    461 
    462     private interface WellKnownTypePrinter {
    463       void print(PrinterImpl printer, MessageOrBuilder message)
    464           throws IOException;
    465     }
    466 
    467     private static final Map<String, WellKnownTypePrinter>
    468     wellKnownTypePrinters = buildWellKnownTypePrinters();
    469 
    470     private static Map<String, WellKnownTypePrinter>
    471     buildWellKnownTypePrinters() {
    472       Map<String, WellKnownTypePrinter> printers =
    473           new HashMap<String, WellKnownTypePrinter>();
    474       // Special-case Any.
    475       printers.put(Any.getDescriptor().getFullName(),
    476           new WellKnownTypePrinter() {
    477         @Override
    478         public void print(PrinterImpl printer, MessageOrBuilder message)
    479             throws IOException {
    480           printer.printAny(message);
    481         }
    482       });
    483       // Special-case wrapper types.
    484       WellKnownTypePrinter wrappersPrinter = new WellKnownTypePrinter() {
    485         @Override
    486         public void print(PrinterImpl printer, MessageOrBuilder message)
    487             throws IOException {
    488           printer.printWrapper(message);
    489 
    490         }
    491       };
    492       printers.put(BoolValue.getDescriptor().getFullName(), wrappersPrinter);
    493       printers.put(Int32Value.getDescriptor().getFullName(), wrappersPrinter);
    494       printers.put(UInt32Value.getDescriptor().getFullName(), wrappersPrinter);
    495       printers.put(Int64Value.getDescriptor().getFullName(), wrappersPrinter);
    496       printers.put(UInt64Value.getDescriptor().getFullName(), wrappersPrinter);
    497       printers.put(StringValue.getDescriptor().getFullName(), wrappersPrinter);
    498       printers.put(BytesValue.getDescriptor().getFullName(), wrappersPrinter);
    499       printers.put(FloatValue.getDescriptor().getFullName(), wrappersPrinter);
    500       printers.put(DoubleValue.getDescriptor().getFullName(), wrappersPrinter);
    501       // Special-case Timestamp.
    502       printers.put(Timestamp.getDescriptor().getFullName(),
    503           new WellKnownTypePrinter() {
    504         @Override
    505         public void print(PrinterImpl printer, MessageOrBuilder message)
    506             throws IOException {
    507           printer.printTimestamp(message);
    508         }
    509       });
    510       // Special-case Duration.
    511       printers.put(Duration.getDescriptor().getFullName(),
    512           new WellKnownTypePrinter() {
    513         @Override
    514         public void print(PrinterImpl printer, MessageOrBuilder message)
    515             throws IOException {
    516           printer.printDuration(message);
    517         }
    518       });
    519       // Special-case FieldMask.
    520       printers.put(FieldMask.getDescriptor().getFullName(),
    521           new WellKnownTypePrinter() {
    522         @Override
    523         public void print(PrinterImpl printer, MessageOrBuilder message)
    524             throws IOException {
    525           printer.printFieldMask(message);
    526         }
    527       });
    528       // Special-case Struct.
    529       printers.put(Struct.getDescriptor().getFullName(),
    530           new WellKnownTypePrinter() {
    531         @Override
    532         public void print(PrinterImpl printer, MessageOrBuilder message)
    533             throws IOException {
    534           printer.printStruct(message);
    535         }
    536       });
    537       // Special-case Value.
    538       printers.put(Value.getDescriptor().getFullName(),
    539           new WellKnownTypePrinter() {
    540         @Override
    541         public void print(PrinterImpl printer, MessageOrBuilder message)
    542             throws IOException {
    543           printer.printValue(message);
    544         }
    545       });
    546       // Special-case ListValue.
    547       printers.put(ListValue.getDescriptor().getFullName(),
    548           new WellKnownTypePrinter() {
    549         @Override
    550         public void print(PrinterImpl printer, MessageOrBuilder message)
    551             throws IOException {
    552           printer.printListValue(message);
    553         }
    554       });
    555       return printers;
    556     }
    557 
    558     /** Prints google.protobuf.Any */
    559     private void printAny(MessageOrBuilder message) throws IOException {
    560       Descriptor descriptor = message.getDescriptorForType();
    561       FieldDescriptor typeUrlField = descriptor.findFieldByName("type_url");
    562       FieldDescriptor valueField = descriptor.findFieldByName("value");
    563       // Validates type of the message. Note that we can't just cast the message
    564       // to com.google.protobuf.Any because it might be a DynamicMessage.
    565       if (typeUrlField == null || valueField == null
    566           || typeUrlField.getType() != FieldDescriptor.Type.STRING
    567           || valueField.getType() != FieldDescriptor.Type.BYTES) {
    568         throw new InvalidProtocolBufferException("Invalid Any type.");
    569       }
    570       String typeUrl = (String) message.getField(typeUrlField);
    571       String typeName = getTypeName(typeUrl);
    572       Descriptor type = registry.find(typeName);
    573       if (type == null) {
    574         throw new InvalidProtocolBufferException(
    575             "Cannot find type for url: " + typeUrl);
    576       }
    577       ByteString content = (ByteString) message.getField(valueField);
    578       Message contentMessage = DynamicMessage.getDefaultInstance(type)
    579           .getParserForType().parseFrom(content);
    580       WellKnownTypePrinter printer = wellKnownTypePrinters.get(typeName);
    581       if (printer != null) {
    582         // If the type is one of the well-known types, we use a special
    583         // formatting.
    584         generator.print("{\n");
    585         generator.indent();
    586         generator.print("\"@type\": " + gson.toJson(typeUrl) + ",\n");
    587         generator.print("\"value\": ");
    588         printer.print(this, contentMessage);
    589         generator.print("\n");
    590         generator.outdent();
    591         generator.print("}");
    592       } else {
    593         // Print the content message instead (with a "@type" field added).
    594         print(contentMessage, typeUrl);
    595       }
    596     }
    597 
    598     /** Prints wrapper types (e.g., google.protobuf.Int32Value) */
    599     private void printWrapper(MessageOrBuilder message) throws IOException {
    600       Descriptor descriptor = message.getDescriptorForType();
    601       FieldDescriptor valueField = descriptor.findFieldByName("value");
    602       if (valueField == null) {
    603         throw new InvalidProtocolBufferException("Invalid Wrapper type.");
    604       }
    605       // When formatting wrapper types, we just print its value field instead of
    606       // the whole message.
    607       printSingleFieldValue(valueField, message.getField(valueField));
    608     }
    609 
    610     private ByteString toByteString(MessageOrBuilder message) {
    611       if (message instanceof Message) {
    612         return ((Message) message).toByteString();
    613       } else {
    614         return ((Message.Builder) message).build().toByteString();
    615       }
    616     }
    617 
    618     /** Prints google.protobuf.Timestamp */
    619     private void printTimestamp(MessageOrBuilder message) throws IOException {
    620       Timestamp value = Timestamp.parseFrom(toByteString(message));
    621       generator.print("\"" + TimeUtil.toString(value) + "\"");
    622     }
    623 
    624     /** Prints google.protobuf.Duration */
    625     private void printDuration(MessageOrBuilder message) throws IOException {
    626       Duration value = Duration.parseFrom(toByteString(message));
    627       generator.print("\"" + TimeUtil.toString(value) + "\"");
    628 
    629     }
    630 
    631     /** Prints google.protobuf.FieldMask */
    632     private void printFieldMask(MessageOrBuilder message) throws IOException {
    633       FieldMask value = FieldMask.parseFrom(toByteString(message));
    634       generator.print("\"" + FieldMaskUtil.toString(value) + "\"");
    635     }
    636 
    637     /** Prints google.protobuf.Struct */
    638     private void printStruct(MessageOrBuilder message) throws IOException {
    639       Descriptor descriptor = message.getDescriptorForType();
    640       FieldDescriptor field = descriptor.findFieldByName("fields");
    641       if (field == null) {
    642         throw new InvalidProtocolBufferException("Invalid Struct type.");
    643       }
    644       // Struct is formatted as a map object.
    645       printMapFieldValue(field, message.getField(field));
    646     }
    647 
    648     /** Prints google.protobuf.Value */
    649     private void printValue(MessageOrBuilder message) throws IOException {
    650       // For a Value message, only the value of the field is formatted.
    651       Map<FieldDescriptor, Object> fields = message.getAllFields();
    652       if (fields.isEmpty()) {
    653         // No value set.
    654         generator.print("null");
    655         return;
    656       }
    657       // A Value message can only have at most one field set (it only contains
    658       // an oneof).
    659       if (fields.size() != 1) {
    660         throw new InvalidProtocolBufferException("Invalid Value type.");
    661       }
    662       for (Map.Entry<FieldDescriptor, Object> entry : fields.entrySet()) {
    663         printSingleFieldValue(entry.getKey(), entry.getValue());
    664       }
    665     }
    666 
    667     /** Prints google.protobuf.ListValue */
    668     private void printListValue(MessageOrBuilder message) throws IOException {
    669       Descriptor descriptor = message.getDescriptorForType();
    670       FieldDescriptor field = descriptor.findFieldByName("values");
    671       if (field == null) {
    672         throw new InvalidProtocolBufferException("Invalid ListValue type.");
    673       }
    674       printRepeatedFieldValue(field, message.getField(field));
    675     }
    676 
    677     /** Prints a regular message with an optional type URL. */
    678     private void print(MessageOrBuilder message, String typeUrl)
    679         throws IOException {
    680       generator.print("{\n");
    681       generator.indent();
    682 
    683       boolean printedField = false;
    684       if (typeUrl != null) {
    685         generator.print("\"@type\": " + gson.toJson(typeUrl));
    686         printedField = true;
    687       }
    688       Map<FieldDescriptor, Object> fieldsToPrint = null;
    689       if (includingDefaultValueFields) {
    690         fieldsToPrint = new TreeMap<FieldDescriptor, Object>();
    691         for (FieldDescriptor field : message.getDescriptorForType().getFields()) {
    692           if (field.isOptional()
    693               && field.getJavaType() == FieldDescriptor.JavaType.MESSAGE
    694               && !message.hasField(field)) {
    695             // Always skip empty optional message fields. If not we will recurse indefinitely if
    696             // a message has itself as a sub-field.
    697             continue;
    698           }
    699           fieldsToPrint.put(field, message.getField(field));
    700         }
    701       } else {
    702         fieldsToPrint = message.getAllFields();
    703       }
    704       for (Map.Entry<FieldDescriptor, Object> field : fieldsToPrint.entrySet()) {
    705         if (printedField) {
    706           // Add line-endings for the previous field.
    707           generator.print(",\n");
    708         } else {
    709           printedField = true;
    710         }
    711         printField(field.getKey(), field.getValue());
    712       }
    713 
    714       // Add line-endings for the last field.
    715       if (printedField) {
    716         generator.print("\n");
    717       }
    718       generator.outdent();
    719       generator.print("}");
    720     }
    721 
    722     private void printField(FieldDescriptor field, Object value)
    723         throws IOException {
    724       if (preservingProtoFieldNames) {
    725         generator.print("\"" + field.getName() + "\": ");
    726       } else {
    727         generator.print("\"" + field.getJsonName() + "\": ");
    728       }
    729       if (field.isMapField()) {
    730         printMapFieldValue(field, value);
    731       } else if (field.isRepeated()) {
    732         printRepeatedFieldValue(field, value);
    733       } else {
    734         printSingleFieldValue(field, value);
    735       }
    736     }
    737 
    738     @SuppressWarnings("rawtypes")
    739     private void printRepeatedFieldValue(FieldDescriptor field, Object value)
    740         throws IOException {
    741       generator.print("[");
    742       boolean printedElement = false;
    743       for (Object element : (List) value) {
    744         if (printedElement) {
    745           generator.print(", ");
    746         } else {
    747           printedElement = true;
    748         }
    749         printSingleFieldValue(field, element);
    750       }
    751       generator.print("]");
    752     }
    753 
    754     @SuppressWarnings("rawtypes")
    755     private void printMapFieldValue(FieldDescriptor field, Object value)
    756         throws IOException {
    757       Descriptor type = field.getMessageType();
    758       FieldDescriptor keyField = type.findFieldByName("key");
    759       FieldDescriptor valueField = type.findFieldByName("value");
    760       if (keyField == null || valueField == null) {
    761         throw new InvalidProtocolBufferException("Invalid map field.");
    762       }
    763       generator.print("{\n");
    764       generator.indent();
    765       boolean printedElement = false;
    766       for (Object element : (List) value) {
    767         Message entry = (Message) element;
    768         Object entryKey = entry.getField(keyField);
    769         Object entryValue = entry.getField(valueField);
    770         if (printedElement) {
    771           generator.print(",\n");
    772         } else {
    773           printedElement = true;
    774         }
    775         // Key fields are always double-quoted.
    776         printSingleFieldValue(keyField, entryKey, true);
    777         generator.print(": ");
    778         printSingleFieldValue(valueField, entryValue);
    779       }
    780       if (printedElement) {
    781         generator.print("\n");
    782       }
    783       generator.outdent();
    784       generator.print("}");
    785     }
    786 
    787     private void printSingleFieldValue(FieldDescriptor field, Object value)
    788         throws IOException {
    789       printSingleFieldValue(field, value, false);
    790     }
    791 
    792     /**
    793      * Prints a field's value in JSON format.
    794      *
    795      * @param alwaysWithQuotes whether to always add double-quotes to primitive
    796      *        types.
    797      */
    798     private void printSingleFieldValue(
    799         final FieldDescriptor field, final Object value,
    800         boolean alwaysWithQuotes) throws IOException {
    801       switch (field.getType()) {
    802         case INT32:
    803         case SINT32:
    804         case SFIXED32:
    805           if (alwaysWithQuotes) {
    806             generator.print("\"");
    807           }
    808           generator.print(((Integer) value).toString());
    809           if (alwaysWithQuotes) {
    810             generator.print("\"");
    811           }
    812           break;
    813 
    814         case INT64:
    815         case SINT64:
    816         case SFIXED64:
    817           generator.print("\"" + ((Long) value).toString() + "\"");
    818           break;
    819 
    820         case BOOL:
    821           if (alwaysWithQuotes) {
    822             generator.print("\"");
    823           }
    824           if (((Boolean) value).booleanValue()) {
    825             generator.print("true");
    826           } else {
    827             generator.print("false");
    828           }
    829           if (alwaysWithQuotes) {
    830             generator.print("\"");
    831           }
    832           break;
    833 
    834         case FLOAT:
    835           Float floatValue = (Float) value;
    836           if (floatValue.isNaN()) {
    837             generator.print("\"NaN\"");
    838           } else if (floatValue.isInfinite()) {
    839             if (floatValue < 0) {
    840               generator.print("\"-Infinity\"");
    841             } else {
    842               generator.print("\"Infinity\"");
    843             }
    844           } else {
    845             if (alwaysWithQuotes) {
    846               generator.print("\"");
    847             }
    848             generator.print(floatValue.toString());
    849             if (alwaysWithQuotes) {
    850               generator.print("\"");
    851             }
    852           }
    853           break;
    854 
    855         case DOUBLE:
    856           Double doubleValue = (Double) value;
    857           if (doubleValue.isNaN()) {
    858             generator.print("\"NaN\"");
    859           } else if (doubleValue.isInfinite()) {
    860             if (doubleValue < 0) {
    861               generator.print("\"-Infinity\"");
    862             } else {
    863               generator.print("\"Infinity\"");
    864             }
    865           } else {
    866             if (alwaysWithQuotes) {
    867               generator.print("\"");
    868             }
    869             generator.print(doubleValue.toString());
    870             if (alwaysWithQuotes) {
    871               generator.print("\"");
    872             }
    873           }
    874           break;
    875 
    876         case UINT32:
    877         case FIXED32:
    878           if (alwaysWithQuotes) {
    879             generator.print("\"");
    880           }
    881           generator.print(unsignedToString((Integer) value));
    882           if (alwaysWithQuotes) {
    883             generator.print("\"");
    884           }
    885           break;
    886 
    887         case UINT64:
    888         case FIXED64:
    889           generator.print("\"" + unsignedToString((Long) value) + "\"");
    890           break;
    891 
    892         case STRING:
    893           generator.print(gson.toJson(value));
    894           break;
    895 
    896         case BYTES:
    897           generator.print("\"");
    898           generator.print(
    899               BaseEncoding.base64().encode(((ByteString) value).toByteArray()));
    900           generator.print("\"");
    901           break;
    902 
    903         case ENUM:
    904           // Special-case google.protobuf.NullValue (it's an Enum).
    905           if (field.getEnumType().getFullName().equals(
    906                   "google.protobuf.NullValue")) {
    907             // No matter what value it contains, we always print it as "null".
    908             if (alwaysWithQuotes) {
    909               generator.print("\"");
    910             }
    911             generator.print("null");
    912             if (alwaysWithQuotes) {
    913               generator.print("\"");
    914             }
    915           } else {
    916             if (((EnumValueDescriptor) value).getIndex() == -1) {
    917               generator.print(
    918                   String.valueOf(((EnumValueDescriptor) value).getNumber()));
    919             } else {
    920               generator.print(
    921                   "\"" + ((EnumValueDescriptor) value).getName() + "\"");
    922             }
    923           }
    924           break;
    925 
    926         case MESSAGE:
    927         case GROUP:
    928           print((Message) value);
    929           break;
    930       }
    931     }
    932   }
    933 
    934   /** Convert an unsigned 32-bit integer to a string. */
    935   private static String unsignedToString(final int value) {
    936     if (value >= 0) {
    937       return Integer.toString(value);
    938     } else {
    939       return Long.toString(value & 0x00000000FFFFFFFFL);
    940     }
    941   }
    942 
    943   /** Convert an unsigned 64-bit integer to a string. */
    944   private static String unsignedToString(final long value) {
    945     if (value >= 0) {
    946       return Long.toString(value);
    947     } else {
    948       // Pull off the most-significant bit so that BigInteger doesn't think
    949       // the number is negative, then set it again using setBit().
    950       return BigInteger.valueOf(value & Long.MAX_VALUE)
    951                        .setBit(Long.SIZE - 1).toString();
    952     }
    953   }
    954 
    955 
    956   private static String getTypeName(String typeUrl)
    957       throws InvalidProtocolBufferException {
    958     String[] parts = typeUrl.split("/");
    959     if (parts.length == 1) {
    960       throw new InvalidProtocolBufferException(
    961           "Invalid type url found: " + typeUrl);
    962     }
    963     return parts[parts.length - 1];
    964   }
    965 
    966   private static class ParserImpl {
    967     private final TypeRegistry registry;
    968     private final JsonParser jsonParser;
    969 
    970     ParserImpl(TypeRegistry registry) {
    971       this.registry = registry;
    972       this.jsonParser = new JsonParser();
    973     }
    974 
    975     void merge(Reader json, Message.Builder builder)
    976         throws IOException {
    977       JsonReader reader = new JsonReader(json);
    978       reader.setLenient(false);
    979       merge(jsonParser.parse(reader), builder);
    980     }
    981 
    982     void merge(String json, Message.Builder builder)
    983         throws InvalidProtocolBufferException {
    984       try {
    985         JsonReader reader = new JsonReader(new StringReader(json));
    986         reader.setLenient(false);
    987         merge(jsonParser.parse(reader), builder);
    988       } catch (InvalidProtocolBufferException e) {
    989         throw e;
    990       } catch (Exception e) {
    991         // We convert all exceptions from JSON parsing to our own exceptions.
    992         throw new InvalidProtocolBufferException(e.getMessage());
    993       }
    994     }
    995 
    996     private interface WellKnownTypeParser {
    997       void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
    998           throws InvalidProtocolBufferException;
    999     }
   1000 
   1001     private static final Map<String, WellKnownTypeParser> wellKnownTypeParsers =
   1002         buildWellKnownTypeParsers();
   1003 
   1004     private static Map<String, WellKnownTypeParser>
   1005     buildWellKnownTypeParsers() {
   1006       Map<String, WellKnownTypeParser> parsers =
   1007           new HashMap<String, WellKnownTypeParser>();
   1008       // Special-case Any.
   1009       parsers.put(Any.getDescriptor().getFullName(), new WellKnownTypeParser() {
   1010         @Override
   1011         public void merge(ParserImpl parser, JsonElement json,
   1012             Message.Builder builder) throws InvalidProtocolBufferException {
   1013           parser.mergeAny(json, builder);
   1014         }
   1015       });
   1016       // Special-case wrapper types.
   1017       WellKnownTypeParser wrappersPrinter = new WellKnownTypeParser() {
   1018         @Override
   1019         public void merge(ParserImpl parser, JsonElement json,
   1020             Message.Builder builder) throws InvalidProtocolBufferException {
   1021           parser.mergeWrapper(json, builder);
   1022         }
   1023       };
   1024       parsers.put(BoolValue.getDescriptor().getFullName(), wrappersPrinter);
   1025       parsers.put(Int32Value.getDescriptor().getFullName(), wrappersPrinter);
   1026       parsers.put(UInt32Value.getDescriptor().getFullName(), wrappersPrinter);
   1027       parsers.put(Int64Value.getDescriptor().getFullName(), wrappersPrinter);
   1028       parsers.put(UInt64Value.getDescriptor().getFullName(), wrappersPrinter);
   1029       parsers.put(StringValue.getDescriptor().getFullName(), wrappersPrinter);
   1030       parsers.put(BytesValue.getDescriptor().getFullName(), wrappersPrinter);
   1031       parsers.put(FloatValue.getDescriptor().getFullName(), wrappersPrinter);
   1032       parsers.put(DoubleValue.getDescriptor().getFullName(), wrappersPrinter);
   1033       // Special-case Timestamp.
   1034       parsers.put(Timestamp.getDescriptor().getFullName(),
   1035           new WellKnownTypeParser() {
   1036         @Override
   1037         public void merge(ParserImpl parser, JsonElement json,
   1038             Message.Builder builder) throws InvalidProtocolBufferException {
   1039           parser.mergeTimestamp(json, builder);
   1040         }
   1041       });
   1042       // Special-case Duration.
   1043       parsers.put(Duration.getDescriptor().getFullName(),
   1044           new WellKnownTypeParser() {
   1045         @Override
   1046         public void merge(ParserImpl parser, JsonElement json,
   1047             Message.Builder builder) throws InvalidProtocolBufferException {
   1048           parser.mergeDuration(json, builder);
   1049         }
   1050       });
   1051       // Special-case FieldMask.
   1052       parsers.put(FieldMask.getDescriptor().getFullName(),
   1053           new WellKnownTypeParser() {
   1054         @Override
   1055         public void merge(ParserImpl parser, JsonElement json,
   1056             Message.Builder builder) throws InvalidProtocolBufferException {
   1057           parser.mergeFieldMask(json, builder);
   1058         }
   1059       });
   1060       // Special-case Struct.
   1061       parsers.put(Struct.getDescriptor().getFullName(),
   1062           new WellKnownTypeParser() {
   1063         @Override
   1064         public void merge(ParserImpl parser, JsonElement json,
   1065             Message.Builder builder) throws InvalidProtocolBufferException {
   1066           parser.mergeStruct(json, builder);
   1067         }
   1068       });
   1069       // Special-case ListValue.
   1070       parsers.put(ListValue.getDescriptor().getFullName(),
   1071           new WellKnownTypeParser() {
   1072         @Override
   1073         public void merge(ParserImpl parser, JsonElement json,
   1074             Message.Builder builder) throws InvalidProtocolBufferException {
   1075           parser.mergeListValue(json, builder);
   1076         }
   1077       });
   1078       // Special-case Value.
   1079       parsers.put(Value.getDescriptor().getFullName(),
   1080           new WellKnownTypeParser() {
   1081         @Override
   1082         public void merge(ParserImpl parser, JsonElement json,
   1083             Message.Builder builder) throws InvalidProtocolBufferException {
   1084           parser.mergeValue(json, builder);
   1085         }
   1086       });
   1087       return parsers;
   1088     }
   1089 
   1090     private void merge(JsonElement json, Message.Builder builder)
   1091         throws InvalidProtocolBufferException {
   1092       WellKnownTypeParser specialParser = wellKnownTypeParsers.get(
   1093           builder.getDescriptorForType().getFullName());
   1094       if (specialParser != null) {
   1095         specialParser.merge(this, json, builder);
   1096         return;
   1097       }
   1098       mergeMessage(json, builder, false);
   1099     }
   1100 
   1101     // Maps from camel-case field names to FieldDescriptor.
   1102     private final Map<Descriptor, Map<String, FieldDescriptor>> fieldNameMaps =
   1103         new HashMap<Descriptor, Map<String, FieldDescriptor>>();
   1104 
   1105     private Map<String, FieldDescriptor> getFieldNameMap(
   1106         Descriptor descriptor) {
   1107       if (!fieldNameMaps.containsKey(descriptor)) {
   1108         Map<String, FieldDescriptor> fieldNameMap =
   1109             new HashMap<String, FieldDescriptor>();
   1110         for (FieldDescriptor field : descriptor.getFields()) {
   1111           fieldNameMap.put(field.getName(), field);
   1112           fieldNameMap.put(field.getJsonName(), field);
   1113         }
   1114         fieldNameMaps.put(descriptor, fieldNameMap);
   1115         return fieldNameMap;
   1116       }
   1117       return fieldNameMaps.get(descriptor);
   1118     }
   1119 
   1120     private void mergeMessage(JsonElement json, Message.Builder builder,
   1121         boolean skipTypeUrl) throws InvalidProtocolBufferException {
   1122       if (!(json instanceof JsonObject)) {
   1123         throw new InvalidProtocolBufferException(
   1124             "Expect message object but got: " + json);
   1125       }
   1126       JsonObject object = (JsonObject) json;
   1127       Map<String, FieldDescriptor> fieldNameMap =
   1128           getFieldNameMap(builder.getDescriptorForType());
   1129       for (Map.Entry<String, JsonElement> entry : object.entrySet()) {
   1130         if (skipTypeUrl && entry.getKey().equals("@type")) {
   1131           continue;
   1132         }
   1133         FieldDescriptor field = fieldNameMap.get(entry.getKey());
   1134         if (field == null) {
   1135           throw new InvalidProtocolBufferException(
   1136               "Cannot find field: " + entry.getKey() + " in message "
   1137               + builder.getDescriptorForType().getFullName());
   1138         }
   1139         mergeField(field, entry.getValue(), builder);
   1140       }
   1141     }
   1142 
   1143     private void mergeAny(JsonElement json, Message.Builder builder)
   1144         throws InvalidProtocolBufferException {
   1145       Descriptor descriptor = builder.getDescriptorForType();
   1146       FieldDescriptor typeUrlField = descriptor.findFieldByName("type_url");
   1147       FieldDescriptor valueField = descriptor.findFieldByName("value");
   1148       // Validates type of the message. Note that we can't just cast the message
   1149       // to com.google.protobuf.Any because it might be a DynamicMessage.
   1150       if (typeUrlField == null || valueField == null
   1151           || typeUrlField.getType() != FieldDescriptor.Type.STRING
   1152           || valueField.getType() != FieldDescriptor.Type.BYTES) {
   1153         throw new InvalidProtocolBufferException("Invalid Any type.");
   1154       }
   1155 
   1156       if (!(json instanceof JsonObject)) {
   1157         throw new InvalidProtocolBufferException(
   1158             "Expect message object but got: " + json);
   1159       }
   1160       JsonObject object = (JsonObject) json;
   1161       JsonElement typeUrlElement = object.get("@type");
   1162       if (typeUrlElement == null) {
   1163         throw new InvalidProtocolBufferException(
   1164             "Missing type url when parsing: " + json);
   1165       }
   1166       String typeUrl = typeUrlElement.getAsString();
   1167       Descriptor contentType = registry.find(getTypeName(typeUrl));
   1168       if (contentType == null) {
   1169         throw new InvalidProtocolBufferException(
   1170             "Cannot resolve type: " + typeUrl);
   1171       }
   1172       builder.setField(typeUrlField, typeUrl);
   1173       Message.Builder contentBuilder =
   1174           DynamicMessage.getDefaultInstance(contentType).newBuilderForType();
   1175       WellKnownTypeParser specialParser =
   1176           wellKnownTypeParsers.get(contentType.getFullName());
   1177       if (specialParser != null) {
   1178         JsonElement value = object.get("value");
   1179         if (value != null) {
   1180           specialParser.merge(this, value, contentBuilder);
   1181         }
   1182       } else {
   1183         mergeMessage(json, contentBuilder, true);
   1184       }
   1185       builder.setField(valueField, contentBuilder.build().toByteString());
   1186     }
   1187 
   1188     private void mergeFieldMask(JsonElement json, Message.Builder builder)
   1189         throws InvalidProtocolBufferException {
   1190       FieldMask value = FieldMaskUtil.fromString(json.getAsString());
   1191       builder.mergeFrom(value.toByteString());
   1192     }
   1193 
   1194     private void mergeTimestamp(JsonElement json, Message.Builder builder)
   1195         throws InvalidProtocolBufferException {
   1196       try {
   1197         Timestamp value = TimeUtil.parseTimestamp(json.getAsString());
   1198         builder.mergeFrom(value.toByteString());
   1199       } catch (ParseException e) {
   1200         throw new InvalidProtocolBufferException(
   1201             "Failed to parse timestamp: " + json);
   1202       }
   1203     }
   1204 
   1205     private void mergeDuration(JsonElement json, Message.Builder builder)
   1206         throws InvalidProtocolBufferException {
   1207       try {
   1208         Duration value = TimeUtil.parseDuration(json.getAsString());
   1209         builder.mergeFrom(value.toByteString());
   1210       } catch (ParseException e) {
   1211         throw new InvalidProtocolBufferException(
   1212             "Failed to parse duration: " + json);
   1213       }
   1214     }
   1215 
   1216     private void mergeStruct(JsonElement json, Message.Builder builder)
   1217         throws InvalidProtocolBufferException {
   1218       Descriptor descriptor = builder.getDescriptorForType();
   1219       FieldDescriptor field = descriptor.findFieldByName("fields");
   1220       if (field == null) {
   1221         throw new InvalidProtocolBufferException("Invalid Struct type.");
   1222       }
   1223       mergeMapField(field, json, builder);
   1224     }
   1225 
   1226     private void mergeListValue(JsonElement json, Message.Builder builder)
   1227         throws InvalidProtocolBufferException {
   1228       Descriptor descriptor = builder.getDescriptorForType();
   1229       FieldDescriptor field = descriptor.findFieldByName("values");
   1230       if (field == null) {
   1231         throw new InvalidProtocolBufferException("Invalid ListValue type.");
   1232       }
   1233       mergeRepeatedField(field, json, builder);
   1234     }
   1235 
   1236     private void mergeValue(JsonElement json, Message.Builder builder)
   1237         throws InvalidProtocolBufferException {
   1238       Descriptor type = builder.getDescriptorForType();
   1239       if (json instanceof JsonPrimitive) {
   1240         JsonPrimitive primitive = (JsonPrimitive) json;
   1241         if (primitive.isBoolean()) {
   1242           builder.setField(type.findFieldByName("bool_value"),
   1243               primitive.getAsBoolean());
   1244         } else if (primitive.isNumber()) {
   1245           builder.setField(type.findFieldByName("number_value"),
   1246               primitive.getAsDouble());
   1247         } else {
   1248           builder.setField(type.findFieldByName("string_value"),
   1249               primitive.getAsString());
   1250         }
   1251       } else if (json instanceof JsonObject) {
   1252         FieldDescriptor field = type.findFieldByName("struct_value");
   1253         Message.Builder structBuilder = builder.newBuilderForField(field);
   1254         merge(json, structBuilder);
   1255         builder.setField(field, structBuilder.build());
   1256       } else if (json instanceof JsonArray) {
   1257         FieldDescriptor field = type.findFieldByName("list_value");
   1258         Message.Builder listBuilder = builder.newBuilderForField(field);
   1259         merge(json, listBuilder);
   1260         builder.setField(field, listBuilder.build());
   1261       } else {
   1262         throw new IllegalStateException("Unexpected json data: " + json);
   1263       }
   1264     }
   1265 
   1266     private void mergeWrapper(JsonElement json, Message.Builder builder)
   1267         throws InvalidProtocolBufferException {
   1268       Descriptor type = builder.getDescriptorForType();
   1269       FieldDescriptor field = type.findFieldByName("value");
   1270       if (field == null) {
   1271         throw new InvalidProtocolBufferException(
   1272             "Invalid wrapper type: " + type.getFullName());
   1273       }
   1274       builder.setField(field, parseFieldValue(field, json, builder));
   1275     }
   1276 
   1277     private void mergeField(FieldDescriptor field, JsonElement json,
   1278         Message.Builder builder) throws InvalidProtocolBufferException {
   1279       if (field.isRepeated()) {
   1280         if (builder.getRepeatedFieldCount(field) > 0) {
   1281           throw new InvalidProtocolBufferException(
   1282               "Field " + field.getFullName() + " has already been set.");
   1283         }
   1284       } else {
   1285         if (builder.hasField(field)) {
   1286           throw new InvalidProtocolBufferException(
   1287               "Field " + field.getFullName() + " has already been set.");
   1288         }
   1289         if (field.getContainingOneof() != null
   1290             && builder.getOneofFieldDescriptor(field.getContainingOneof()) != null) {
   1291           FieldDescriptor other = builder.getOneofFieldDescriptor(field.getContainingOneof());
   1292           throw new InvalidProtocolBufferException(
   1293               "Cannot set field " + field.getFullName() + " because another field "
   1294               + other.getFullName() + " belonging to the same oneof has already been set ");
   1295         }
   1296       }
   1297       if (field.isRepeated() && json instanceof JsonNull) {
   1298         // We allow "null" as value for all field types and treat it as if the
   1299         // field is not present.
   1300         return;
   1301       }
   1302       if (field.isMapField()) {
   1303         mergeMapField(field, json, builder);
   1304       } else if (field.isRepeated()) {
   1305         mergeRepeatedField(field, json, builder);
   1306       } else {
   1307         Object value = parseFieldValue(field, json, builder);
   1308         if (value != null) {
   1309           builder.setField(field, value);
   1310         }
   1311       }
   1312     }
   1313 
   1314     private void mergeMapField(FieldDescriptor field, JsonElement json,
   1315         Message.Builder builder) throws InvalidProtocolBufferException {
   1316       if (!(json instanceof JsonObject)) {
   1317         throw new InvalidProtocolBufferException(
   1318             "Expect a map object but found: " + json);
   1319       }
   1320       Descriptor type = field.getMessageType();
   1321       FieldDescriptor keyField = type.findFieldByName("key");
   1322       FieldDescriptor valueField = type.findFieldByName("value");
   1323       if (keyField == null || valueField == null) {
   1324         throw new InvalidProtocolBufferException(
   1325             "Invalid map field: " + field.getFullName());
   1326       }
   1327       JsonObject object = (JsonObject) json;
   1328       for (Map.Entry<String, JsonElement> entry : object.entrySet()) {
   1329         Message.Builder entryBuilder = builder.newBuilderForField(field);
   1330         Object key = parseFieldValue(
   1331             keyField, new JsonPrimitive(entry.getKey()), entryBuilder);
   1332         Object value = parseFieldValue(
   1333             valueField, entry.getValue(), entryBuilder);
   1334         if (value == null) {
   1335           throw new InvalidProtocolBufferException(
   1336               "Map value cannot be null.");
   1337         }
   1338         entryBuilder.setField(keyField, key);
   1339         entryBuilder.setField(valueField, value);
   1340         builder.addRepeatedField(field, entryBuilder.build());
   1341       }
   1342     }
   1343 
   1344     /**
   1345      * Gets the default value for a field type. Note that we use proto3
   1346      * language defaults and ignore any default values set through the
   1347      * proto "default" option.
   1348      */
   1349     private Object getDefaultValue(FieldDescriptor field,
   1350         Message.Builder builder) {
   1351       switch (field.getType()) {
   1352         case INT32:
   1353         case SINT32:
   1354         case SFIXED32:
   1355         case UINT32:
   1356         case FIXED32:
   1357           return 0;
   1358         case INT64:
   1359         case SINT64:
   1360         case SFIXED64:
   1361         case UINT64:
   1362         case FIXED64:
   1363           return 0L;
   1364         case FLOAT:
   1365           return 0.0f;
   1366         case DOUBLE:
   1367           return 0.0;
   1368         case BOOL:
   1369           return false;
   1370         case STRING:
   1371           return "";
   1372         case BYTES:
   1373           return ByteString.EMPTY;
   1374         case ENUM:
   1375           return field.getEnumType().getValues().get(0);
   1376         case MESSAGE:
   1377         case GROUP:
   1378           return builder.newBuilderForField(field).getDefaultInstanceForType();
   1379         default:
   1380           throw new IllegalStateException(
   1381               "Invalid field type: " + field.getType());
   1382       }
   1383     }
   1384 
   1385     private void mergeRepeatedField(FieldDescriptor field, JsonElement json,
   1386         Message.Builder builder) throws InvalidProtocolBufferException {
   1387       if (!(json instanceof JsonArray)) {
   1388         throw new InvalidProtocolBufferException(
   1389             "Expect an array but found: " + json);
   1390       }
   1391       JsonArray array = (JsonArray) json;
   1392       for (int i = 0; i < array.size(); ++i) {
   1393         Object value = parseFieldValue(field, array.get(i), builder);
   1394         if (value == null) {
   1395           throw new InvalidProtocolBufferException(
   1396               "Repeated field elements cannot be null");
   1397         }
   1398         builder.addRepeatedField(field, value);
   1399       }
   1400     }
   1401 
   1402     private int parseInt32(JsonElement json)
   1403         throws InvalidProtocolBufferException {
   1404       try {
   1405         return Integer.parseInt(json.getAsString());
   1406       } catch (Exception e) {
   1407         // Fall through.
   1408       }
   1409       // JSON doesn't distinguish between integer values and floating point values so "1" and
   1410       // "1.000" are treated as equal in JSON. For this reason we accept floating point values for
   1411       // integer fields as well as long as it actually is an integer (i.e., round(value) == value).
   1412       try {
   1413         BigDecimal value = new BigDecimal(json.getAsString());
   1414         return value.intValueExact();
   1415       } catch (Exception e) {
   1416         throw new InvalidProtocolBufferException("Not an int32 value: " + json);
   1417       }
   1418     }
   1419 
   1420     private long parseInt64(JsonElement json)
   1421         throws InvalidProtocolBufferException {
   1422       try {
   1423         return Long.parseLong(json.getAsString());
   1424       } catch (Exception e) {
   1425         // Fall through.
   1426       }
   1427       // JSON doesn't distinguish between integer values and floating point values so "1" and
   1428       // "1.000" are treated as equal in JSON. For this reason we accept floating point values for
   1429       // integer fields as well as long as it actually is an integer (i.e., round(value) == value).
   1430       try {
   1431         BigDecimal value = new BigDecimal(json.getAsString());
   1432         return value.longValueExact();
   1433       } catch (Exception e) {
   1434         throw new InvalidProtocolBufferException("Not an int32 value: " + json);
   1435       }
   1436     }
   1437 
   1438     private int parseUint32(JsonElement json)
   1439         throws InvalidProtocolBufferException {
   1440       try {
   1441         long result = Long.parseLong(json.getAsString());
   1442         if (result < 0 || result > 0xFFFFFFFFL) {
   1443           throw new InvalidProtocolBufferException(
   1444               "Out of range uint32 value: " + json);
   1445         }
   1446         return (int) result;
   1447       } catch (InvalidProtocolBufferException e) {
   1448         throw e;
   1449       } catch (Exception e) {
   1450         // Fall through.
   1451       }
   1452       // JSON doesn't distinguish between integer values and floating point values so "1" and
   1453       // "1.000" are treated as equal in JSON. For this reason we accept floating point values for
   1454       // integer fields as well as long as it actually is an integer (i.e., round(value) == value).
   1455       try {
   1456         BigDecimal decimalValue = new BigDecimal(json.getAsString());
   1457         BigInteger value = decimalValue.toBigIntegerExact();
   1458         if (value.signum() < 0 || value.compareTo(new BigInteger("FFFFFFFF", 16)) > 0) {
   1459           throw new InvalidProtocolBufferException("Out of range uint32 value: " + json);
   1460         }
   1461         return value.intValue();
   1462       } catch (InvalidProtocolBufferException e) {
   1463         throw e;
   1464       } catch (Exception e) {
   1465         throw new InvalidProtocolBufferException(
   1466             "Not an uint32 value: " + json);
   1467       }
   1468     }
   1469 
   1470     private static final BigInteger MAX_UINT64 =
   1471         new BigInteger("FFFFFFFFFFFFFFFF", 16);
   1472 
   1473     private long parseUint64(JsonElement json)
   1474         throws InvalidProtocolBufferException {
   1475       try {
   1476         BigDecimal decimalValue = new BigDecimal(json.getAsString());
   1477         BigInteger value = decimalValue.toBigIntegerExact();
   1478         if (value.compareTo(BigInteger.ZERO) < 0
   1479             || value.compareTo(MAX_UINT64) > 0) {
   1480           throw new InvalidProtocolBufferException(
   1481               "Out of range uint64 value: " + json);
   1482         }
   1483         return value.longValue();
   1484       } catch (InvalidProtocolBufferException e) {
   1485         throw e;
   1486       } catch (Exception e) {
   1487         throw new InvalidProtocolBufferException(
   1488             "Not an uint64 value: " + json);
   1489       }
   1490     }
   1491 
   1492     private boolean parseBool(JsonElement json)
   1493         throws InvalidProtocolBufferException {
   1494       if (json.getAsString().equals("true")) {
   1495         return true;
   1496       }
   1497       if (json.getAsString().equals("false")) {
   1498         return false;
   1499       }
   1500       throw new InvalidProtocolBufferException("Invalid bool value: " + json);
   1501     }
   1502 
   1503     private static final double EPSILON = 1e-6;
   1504 
   1505     private float parseFloat(JsonElement json)
   1506         throws InvalidProtocolBufferException {
   1507       if (json.getAsString().equals("NaN")) {
   1508         return Float.NaN;
   1509       } else if (json.getAsString().equals("Infinity")) {
   1510         return Float.POSITIVE_INFINITY;
   1511       } else if (json.getAsString().equals("-Infinity")) {
   1512         return Float.NEGATIVE_INFINITY;
   1513       }
   1514       try {
   1515         // We don't use Float.parseFloat() here because that function simply
   1516         // accepts all double values. Here we parse the value into a Double
   1517         // and do explicit range check on it.
   1518         double value = Double.parseDouble(json.getAsString());
   1519         // When a float value is printed, the printed value might be a little
   1520         // larger or smaller due to precision loss. Here we need to add a bit
   1521         // of tolerance when checking whether the float value is in range.
   1522         if (value > Float.MAX_VALUE * (1.0 + EPSILON)
   1523             || value < -Float.MAX_VALUE * (1.0 + EPSILON)) {
   1524           throw new InvalidProtocolBufferException(
   1525               "Out of range float value: " + json);
   1526         }
   1527         return (float) value;
   1528       } catch (InvalidProtocolBufferException e) {
   1529         throw e;
   1530       } catch (Exception e) {
   1531         throw new InvalidProtocolBufferException("Not a float value: " + json);
   1532       }
   1533     }
   1534 
   1535     private static final BigDecimal MORE_THAN_ONE = new BigDecimal(
   1536         String.valueOf(1.0 + EPSILON));
   1537     // When a float value is printed, the printed value might be a little
   1538     // larger or smaller due to precision loss. Here we need to add a bit
   1539     // of tolerance when checking whether the float value is in range.
   1540     private static final BigDecimal MAX_DOUBLE = new BigDecimal(
   1541         String.valueOf(Double.MAX_VALUE)).multiply(MORE_THAN_ONE);
   1542     private static final BigDecimal MIN_DOUBLE = new BigDecimal(
   1543         String.valueOf(-Double.MAX_VALUE)).multiply(MORE_THAN_ONE);
   1544 
   1545     private double parseDouble(JsonElement json)
   1546         throws InvalidProtocolBufferException {
   1547       if (json.getAsString().equals("NaN")) {
   1548         return Double.NaN;
   1549       } else if (json.getAsString().equals("Infinity")) {
   1550         return Double.POSITIVE_INFINITY;
   1551       } else if (json.getAsString().equals("-Infinity")) {
   1552         return Double.NEGATIVE_INFINITY;
   1553       }
   1554       try {
   1555         // We don't use Double.parseDouble() here because that function simply
   1556         // accepts all values. Here we parse the value into a BigDecimal and do
   1557         // explicit range check on it.
   1558         BigDecimal value = new BigDecimal(json.getAsString());
   1559         if (value.compareTo(MAX_DOUBLE) > 0
   1560             || value.compareTo(MIN_DOUBLE) < 0) {
   1561           throw new InvalidProtocolBufferException(
   1562               "Out of range double value: " + json);
   1563         }
   1564         return value.doubleValue();
   1565       } catch (InvalidProtocolBufferException e) {
   1566         throw e;
   1567       } catch (Exception e) {
   1568         throw new InvalidProtocolBufferException(
   1569             "Not an double value: " + json);
   1570       }
   1571     }
   1572 
   1573     private String parseString(JsonElement json) {
   1574       return json.getAsString();
   1575     }
   1576 
   1577     private ByteString parseBytes(JsonElement json) throws InvalidProtocolBufferException {
   1578       String encoded = json.getAsString();
   1579       if (encoded.length() % 4 != 0) {
   1580         throw new InvalidProtocolBufferException(
   1581             "Bytes field is not encoded in standard BASE64 with paddings: " + encoded);
   1582       }
   1583       return ByteString.copyFrom(
   1584           BaseEncoding.base64().decode(json.getAsString()));
   1585     }
   1586 
   1587     private EnumValueDescriptor parseEnum(EnumDescriptor enumDescriptor,
   1588         JsonElement json) throws InvalidProtocolBufferException {
   1589       String value = json.getAsString();
   1590       EnumValueDescriptor result = enumDescriptor.findValueByName(value);
   1591       if (result == null) {
   1592         // Try to interpret the value as a number.
   1593         try {
   1594           int numericValue = parseInt32(json);
   1595           if (enumDescriptor.getFile().getSyntax() == FileDescriptor.Syntax.PROTO3) {
   1596             result = enumDescriptor.findValueByNumberCreatingIfUnknown(numericValue);
   1597           } else {
   1598             result = enumDescriptor.findValueByNumber(numericValue);
   1599           }
   1600         } catch (InvalidProtocolBufferException e) {
   1601           // Fall through. This exception is about invalid int32 value we get from parseInt32() but
   1602           // that's not the exception we want the user to see. Since result == null, we will throw
   1603           // an exception later.
   1604         }
   1605 
   1606         if (result == null) {
   1607           throw new InvalidProtocolBufferException(
   1608               "Invalid enum value: " + value + " for enum type: "
   1609               + enumDescriptor.getFullName());
   1610         }
   1611       }
   1612       return result;
   1613     }
   1614 
   1615     private Object parseFieldValue(FieldDescriptor field, JsonElement json,
   1616         Message.Builder builder) throws InvalidProtocolBufferException {
   1617       if (json instanceof JsonNull) {
   1618         if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE
   1619             && field.getMessageType().getFullName().equals(
   1620                    Value.getDescriptor().getFullName())) {
   1621           // For every other type, "null" means absence, but for the special
   1622           // Value message, it means the "null_value" field has been set.
   1623           Value value = Value.newBuilder().setNullValueValue(0).build();
   1624           return builder.newBuilderForField(field).mergeFrom(
   1625               value.toByteString()).build();
   1626         }
   1627         return null;
   1628       }
   1629       switch (field.getType()) {
   1630         case INT32:
   1631         case SINT32:
   1632         case SFIXED32:
   1633           return parseInt32(json);
   1634 
   1635         case INT64:
   1636         case SINT64:
   1637         case SFIXED64:
   1638           return parseInt64(json);
   1639 
   1640         case BOOL:
   1641           return parseBool(json);
   1642 
   1643         case FLOAT:
   1644           return parseFloat(json);
   1645 
   1646         case DOUBLE:
   1647           return parseDouble(json);
   1648 
   1649         case UINT32:
   1650         case FIXED32:
   1651           return parseUint32(json);
   1652 
   1653         case UINT64:
   1654         case FIXED64:
   1655           return parseUint64(json);
   1656 
   1657         case STRING:
   1658           return parseString(json);
   1659 
   1660         case BYTES:
   1661           return parseBytes(json);
   1662 
   1663         case ENUM:
   1664           return parseEnum(field.getEnumType(), json);
   1665 
   1666         case MESSAGE:
   1667         case GROUP:
   1668           Message.Builder subBuilder = builder.newBuilderForField(field);
   1669           merge(json, subBuilder);
   1670           return subBuilder.build();
   1671 
   1672         default:
   1673           throw new InvalidProtocolBufferException(
   1674               "Invalid field type: " + field.getType());
   1675       }
   1676     }
   1677   }
   1678 }
   1679