Home | History | Annotate | Download | only in protobuf
      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;
     32 
     33 import com.google.protobuf.DescriptorProtos.*;
     34 import com.google.protobuf.Descriptors.FileDescriptor.Syntax;
     35 
     36 import java.lang.ref.WeakReference;
     37 import java.util.ArrayList;
     38 import java.util.Arrays;
     39 import java.util.Collections;
     40 import java.util.HashMap;
     41 import java.util.HashSet;
     42 import java.util.List;
     43 import java.util.Map;
     44 import java.util.Set;
     45 import java.util.WeakHashMap;
     46 import java.util.logging.Logger;
     47 
     48 /**
     49  * Contains a collection of classes which describe protocol message types.
     50  *
     51  * Every message type has a {@link Descriptor}, which lists all
     52  * its fields and other information about a type.  You can get a message
     53  * type's descriptor by calling {@code MessageType.getDescriptor()}, or
     54  * (given a message object of the type) {@code message.getDescriptorForType()}.
     55  * Furthermore, each message is associated with a {@link FileDescriptor} for
     56  * a relevant {@code .proto} file. You can obtain it by calling
     57  * {@code Descriptor.getFile()}. A {@link FileDescriptor} contains descriptors
     58  * for all the messages defined in that file, and file descriptors for all the
     59  * imported {@code .proto} files.
     60  *
     61  * Descriptors are built from DescriptorProtos, as defined in
     62  * {@code google/protobuf/descriptor.proto}.
     63  *
     64  * @author kenton (at) google.com Kenton Varda
     65  */
     66 public final class Descriptors {
     67   private static final Logger logger =
     68       Logger.getLogger(Descriptors.class.getName());
     69   /**
     70    * Describes a {@code .proto} file, including everything defined within.
     71    * That includes, in particular, descriptors for all the messages and
     72    * file descriptors for all other imported {@code .proto} files
     73    * (dependencies).
     74    */
     75   public static final class FileDescriptor extends GenericDescriptor {
     76     /** Convert the descriptor to its protocol message representation. */
     77     @Override
     78     public FileDescriptorProto toProto() {
     79       return proto;
     80     }
     81 
     82     /** Get the file name. */
     83     @Override
     84     public String getName() {
     85       return proto.getName();
     86     }
     87 
     88     /** Returns this object. */
     89     @Override
     90     public FileDescriptor getFile() {
     91       return this;
     92     }
     93 
     94     /** Returns the same as getName(). */
     95     @Override
     96     public String getFullName() {
     97       return proto.getName();
     98     }
     99 
    100     /**
    101      * Get the proto package name.  This is the package name given by the
    102      * {@code package} statement in the {@code .proto} file, which differs
    103      * from the Java package.
    104      */
    105     public String getPackage() { return proto.getPackage(); }
    106 
    107     /** Get the {@code FileOptions}, defined in {@code descriptor.proto}. */
    108     public FileOptions getOptions() { return proto.getOptions(); }
    109 
    110     /** Get a list of top-level message types declared in this file. */
    111     public List<Descriptor> getMessageTypes() {
    112       return Collections.unmodifiableList(Arrays.asList(messageTypes));
    113     }
    114 
    115     /** Get a list of top-level enum types declared in this file. */
    116     public List<EnumDescriptor> getEnumTypes() {
    117       return Collections.unmodifiableList(Arrays.asList(enumTypes));
    118     }
    119 
    120     /** Get a list of top-level services declared in this file. */
    121     public List<ServiceDescriptor> getServices() {
    122       return Collections.unmodifiableList(Arrays.asList(services));
    123     }
    124 
    125     /** Get a list of top-level extensions declared in this file. */
    126     public List<FieldDescriptor> getExtensions() {
    127       return Collections.unmodifiableList(Arrays.asList(extensions));
    128     }
    129 
    130     /** Get a list of this file's dependencies (imports). */
    131     public List<FileDescriptor> getDependencies() {
    132       return Collections.unmodifiableList(Arrays.asList(dependencies));
    133     }
    134 
    135     /** Get a list of this file's public dependencies (public imports). */
    136     public List<FileDescriptor> getPublicDependencies() {
    137       return Collections.unmodifiableList(Arrays.asList(publicDependencies));
    138     }
    139 
    140     /** The syntax of the .proto file. */
    141     public enum Syntax {
    142       UNKNOWN("unknown"),
    143       PROTO2("proto2"),
    144       PROTO3("proto3");
    145 
    146       Syntax(String name) {
    147         this.name = name;
    148       }
    149       private final String name;
    150     }
    151 
    152     /** Get the syntax of the .proto file. */
    153     public Syntax getSyntax() {
    154       if (Syntax.PROTO3.name.equals(proto.getSyntax())) {
    155         return Syntax.PROTO3;
    156       }
    157       return Syntax.PROTO2;
    158     }
    159 
    160     /**
    161      * Find a message type in the file by name.  Does not find nested types.
    162      *
    163      * @param name The unqualified type name to look for.
    164      * @return The message type's descriptor, or {@code null} if not found.
    165      */
    166     public Descriptor findMessageTypeByName(String name) {
    167       // Don't allow looking up nested types.  This will make optimization
    168       // easier later.
    169       if (name.indexOf('.') != -1) {
    170         return null;
    171       }
    172       if (getPackage().length() > 0) {
    173         name = getPackage() + '.' + name;
    174       }
    175       final GenericDescriptor result = pool.findSymbol(name);
    176       if (result != null && result instanceof Descriptor &&
    177           result.getFile() == this) {
    178         return (Descriptor)result;
    179       } else {
    180         return null;
    181       }
    182     }
    183 
    184     /**
    185      * Find an enum type in the file by name.  Does not find nested types.
    186      *
    187      * @param name The unqualified type name to look for.
    188      * @return The enum type's descriptor, or {@code null} if not found.
    189      */
    190     public EnumDescriptor findEnumTypeByName(String name) {
    191       // Don't allow looking up nested types.  This will make optimization
    192       // easier later.
    193       if (name.indexOf('.') != -1) {
    194         return null;
    195       }
    196       if (getPackage().length() > 0) {
    197         name = getPackage() + '.' + name;
    198       }
    199       final GenericDescriptor result = pool.findSymbol(name);
    200       if (result != null && result instanceof EnumDescriptor &&
    201           result.getFile() == this) {
    202         return (EnumDescriptor)result;
    203       } else {
    204         return null;
    205       }
    206     }
    207 
    208     /**
    209      * Find a service type in the file by name.
    210      *
    211      * @param name The unqualified type name to look for.
    212      * @return The service type's descriptor, or {@code null} if not found.
    213      */
    214     public ServiceDescriptor findServiceByName(String name) {
    215       // Don't allow looking up nested types.  This will make optimization
    216       // easier later.
    217       if (name.indexOf('.') != -1) {
    218         return null;
    219       }
    220       if (getPackage().length() > 0) {
    221         name = getPackage() + '.' + name;
    222       }
    223       final GenericDescriptor result = pool.findSymbol(name);
    224       if (result != null && result instanceof ServiceDescriptor &&
    225           result.getFile() == this) {
    226         return (ServiceDescriptor)result;
    227       } else {
    228         return null;
    229       }
    230     }
    231 
    232     /**
    233      * Find an extension in the file by name.  Does not find extensions nested
    234      * inside message types.
    235      *
    236      * @param name The unqualified extension name to look for.
    237      * @return The extension's descriptor, or {@code null} if not found.
    238      */
    239     public FieldDescriptor findExtensionByName(String name) {
    240       if (name.indexOf('.') != -1) {
    241         return null;
    242       }
    243       if (getPackage().length() > 0) {
    244         name = getPackage() + '.' + name;
    245       }
    246       final GenericDescriptor result = pool.findSymbol(name);
    247       if (result != null && result instanceof FieldDescriptor &&
    248           result.getFile() == this) {
    249         return (FieldDescriptor)result;
    250       } else {
    251         return null;
    252       }
    253     }
    254 
    255     /**
    256      * Construct a {@code FileDescriptor}.
    257      *
    258      * @param proto The protocol message form of the FileDescriptor.
    259      * @param dependencies {@code FileDescriptor}s corresponding to all of
    260      *                     the file's dependencies.
    261      * @throws DescriptorValidationException {@code proto} is not a valid
    262      *           descriptor.  This can occur for a number of reasons, e.g.
    263      *           because a field has an undefined type or because two messages
    264      *           were defined with the same name.
    265      */
    266     public static FileDescriptor buildFrom(final FileDescriptorProto proto,
    267                                            final FileDescriptor[] dependencies)
    268                                     throws DescriptorValidationException {
    269       return buildFrom(proto, dependencies, false);
    270     }
    271 
    272 
    273     /**
    274      * Construct a {@code FileDescriptor}.
    275      *
    276      * @param proto The protocol message form of the FileDescriptor.
    277      * @param dependencies {@code FileDescriptor}s corresponding to all of
    278      *                     the file's dependencies.
    279      * @param allowUnknownDependencies If true, non-exist dependenncies will be
    280      *           ignored and undefined message types will be replaced with a
    281      *           placeholder type.
    282      * @throws DescriptorValidationException {@code proto} is not a valid
    283      *           descriptor.  This can occur for a number of reasons, e.g.
    284      *           because a field has an undefined type or because two messages
    285      *           were defined with the same name.
    286      */
    287     public static FileDescriptor buildFrom(
    288         final FileDescriptorProto proto, final FileDescriptor[] dependencies,
    289         final boolean allowUnknownDependencies)
    290         throws DescriptorValidationException {
    291       // Building descriptors involves two steps:  translating and linking.
    292       // In the translation step (implemented by FileDescriptor's
    293       // constructor), we build an object tree mirroring the
    294       // FileDescriptorProto's tree and put all of the descriptors into the
    295       // DescriptorPool's lookup tables.  In the linking step, we look up all
    296       // type references in the DescriptorPool, so that, for example, a
    297       // FieldDescriptor for an embedded message contains a pointer directly
    298       // to the Descriptor for that message's type.  We also detect undefined
    299       // types in the linking step.
    300       final DescriptorPool pool = new DescriptorPool(
    301           dependencies, allowUnknownDependencies);
    302       final FileDescriptor result = new FileDescriptor(
    303           proto, dependencies, pool, allowUnknownDependencies);
    304       result.crossLink();
    305       return result;
    306     }
    307 
    308     /**
    309      * This method is to be called by generated code only.  It is equivalent
    310      * to {@code buildFrom} except that the {@code FileDescriptorProto} is
    311      * encoded in protocol buffer wire format.
    312      */
    313     public static void internalBuildGeneratedFileFrom(
    314         final String[] descriptorDataParts,
    315         final FileDescriptor[] dependencies,
    316         final InternalDescriptorAssigner descriptorAssigner) {
    317       // Hack:  We can't embed a raw byte array inside generated Java code
    318       //   (at least, not efficiently), but we can embed Strings.  So, the
    319       //   protocol compiler embeds the FileDescriptorProto as a giant
    320       //   string literal which is passed to this function to construct the
    321       //   file's FileDescriptor.  The string literal contains only 8-bit
    322       //   characters, each one representing a byte of the FileDescriptorProto's
    323       //   serialized form.  So, if we convert it to bytes in ISO-8859-1, we
    324       //   should get the original bytes that we want.
    325 
    326       // descriptorData may contain multiple strings in order to get around the
    327       // Java 64k string literal limit.
    328       StringBuilder descriptorData = new StringBuilder();
    329       for (String part : descriptorDataParts) {
    330         descriptorData.append(part);
    331       }
    332 
    333       final byte[] descriptorBytes;
    334       descriptorBytes = descriptorData.toString().getBytes(Internal.ISO_8859_1);
    335 
    336       FileDescriptorProto proto;
    337       try {
    338         proto = FileDescriptorProto.parseFrom(descriptorBytes);
    339       } catch (InvalidProtocolBufferException e) {
    340         throw new IllegalArgumentException(
    341           "Failed to parse protocol buffer descriptor for generated code.", e);
    342       }
    343 
    344       final FileDescriptor result;
    345       try {
    346         // When building descriptors for generated code, we allow unknown
    347         // dependencies by default.
    348         result = buildFrom(proto, dependencies, true);
    349       } catch (DescriptorValidationException e) {
    350         throw new IllegalArgumentException(
    351           "Invalid embedded descriptor for \"" + proto.getName() + "\".", e);
    352       }
    353 
    354       final ExtensionRegistry registry =
    355           descriptorAssigner.assignDescriptors(result);
    356 
    357       if (registry != null) {
    358         // We must re-parse the proto using the registry.
    359         try {
    360           proto = FileDescriptorProto.parseFrom(descriptorBytes, registry);
    361         } catch (InvalidProtocolBufferException e) {
    362           throw new IllegalArgumentException(
    363             "Failed to parse protocol buffer descriptor for generated code.",
    364             e);
    365         }
    366 
    367         result.setProto(proto);
    368       }
    369     }
    370 
    371     /**
    372      * This method is to be called by generated code only.  It uses Java
    373      * reflection to load the dependencies' descriptors.
    374      */
    375     public static void internalBuildGeneratedFileFrom(
    376         final String[] descriptorDataParts,
    377         final Class<?> descriptorOuterClass,
    378         final String[] dependencies,
    379         final String[] dependencyFileNames,
    380         final InternalDescriptorAssigner descriptorAssigner) {
    381       List<FileDescriptor> descriptors = new ArrayList<FileDescriptor>();
    382       for (int i = 0; i < dependencies.length; i++) {
    383         try {
    384           Class<?> clazz =
    385               descriptorOuterClass.getClassLoader().loadClass(dependencies[i]);
    386           descriptors.add(
    387               (FileDescriptor) clazz.getField("descriptor").get(null));
    388         } catch (Exception e) {
    389           // We allow unknown dependencies by default. If a dependency cannot
    390           // be found we only generate a warning.
    391           logger.warning("Descriptors for \"" + dependencyFileNames[i] +
    392               "\" can not be found.");
    393         }
    394       }
    395       FileDescriptor[] descriptorArray = new FileDescriptor[descriptors.size()];
    396       descriptors.toArray(descriptorArray);
    397       internalBuildGeneratedFileFrom(
    398           descriptorDataParts, descriptorArray, descriptorAssigner);
    399     }
    400 
    401     /**
    402      * This method is to be called by generated code only.  It is used to
    403      * update the FileDescriptorProto associated with the descriptor by
    404      * parsing it again with the given ExtensionRegistry. This is needed to
    405      * recognize custom options.
    406      */
    407     public static void internalUpdateFileDescriptor(
    408         final FileDescriptor descriptor,
    409         final ExtensionRegistry registry) {
    410       ByteString bytes = descriptor.proto.toByteString();
    411       FileDescriptorProto proto;
    412       try {
    413         proto = FileDescriptorProto.parseFrom(bytes, registry);
    414       } catch (InvalidProtocolBufferException e) {
    415         throw new IllegalArgumentException(
    416           "Failed to parse protocol buffer descriptor for generated code.", e);
    417       }
    418       descriptor.setProto(proto);
    419     }
    420 
    421     /**
    422      * This class should be used by generated code only.  When calling
    423      * {@link FileDescriptor#internalBuildGeneratedFileFrom}, the caller
    424      * provides a callback implementing this interface.  The callback is called
    425      * after the FileDescriptor has been constructed, in order to assign all
    426      * the global variables defined in the generated code which point at parts
    427      * of the FileDescriptor.  The callback returns an ExtensionRegistry which
    428      * contains any extensions which might be used in the descriptor -- that
    429      * is, extensions of the various "Options" messages defined in
    430      * descriptor.proto.  The callback may also return null to indicate that
    431      * no extensions are used in the descriptor.
    432      */
    433     public interface InternalDescriptorAssigner {
    434       ExtensionRegistry assignDescriptors(FileDescriptor root);
    435     }
    436 
    437     private FileDescriptorProto proto;
    438     private final Descriptor[] messageTypes;
    439     private final EnumDescriptor[] enumTypes;
    440     private final ServiceDescriptor[] services;
    441     private final FieldDescriptor[] extensions;
    442     private final FileDescriptor[] dependencies;
    443     private final FileDescriptor[] publicDependencies;
    444     private final DescriptorPool pool;
    445 
    446     private FileDescriptor(final FileDescriptorProto proto,
    447                            final FileDescriptor[] dependencies,
    448                            final DescriptorPool pool,
    449                            boolean allowUnknownDependencies)
    450                     throws DescriptorValidationException {
    451       this.pool = pool;
    452       this.proto = proto;
    453       this.dependencies = dependencies.clone();
    454       HashMap<String, FileDescriptor> nameToFileMap =
    455           new HashMap<String, FileDescriptor>();
    456       for (FileDescriptor file : dependencies) {
    457         nameToFileMap.put(file.getName(), file);
    458       }
    459       List<FileDescriptor> publicDependencies = new ArrayList<FileDescriptor>();
    460       for (int i = 0; i < proto.getPublicDependencyCount(); i++) {
    461         int index = proto.getPublicDependency(i);
    462         if (index < 0 || index >= proto.getDependencyCount()) {
    463           throw new DescriptorValidationException(this,
    464               "Invalid public dependency index.");
    465         }
    466         String name = proto.getDependency(index);
    467         FileDescriptor file = nameToFileMap.get(name);
    468         if (file == null) {
    469           if (!allowUnknownDependencies) {
    470             throw new DescriptorValidationException(this,
    471                 "Invalid public dependency: " + name);
    472           }
    473           // Ignore unknown dependencies.
    474         } else {
    475           publicDependencies.add(file);
    476         }
    477       }
    478       this.publicDependencies = new FileDescriptor[publicDependencies.size()];
    479       publicDependencies.toArray(this.publicDependencies);
    480 
    481       pool.addPackage(getPackage(), this);
    482 
    483       messageTypes = new Descriptor[proto.getMessageTypeCount()];
    484       for (int i = 0; i < proto.getMessageTypeCount(); i++) {
    485         messageTypes[i] =
    486           new Descriptor(proto.getMessageType(i), this, null, i);
    487       }
    488 
    489       enumTypes = new EnumDescriptor[proto.getEnumTypeCount()];
    490       for (int i = 0; i < proto.getEnumTypeCount(); i++) {
    491         enumTypes[i] = new EnumDescriptor(proto.getEnumType(i), this, null, i);
    492       }
    493 
    494       services = new ServiceDescriptor[proto.getServiceCount()];
    495       for (int i = 0; i < proto.getServiceCount(); i++) {
    496         services[i] = new ServiceDescriptor(proto.getService(i), this, i);
    497       }
    498 
    499       extensions = new FieldDescriptor[proto.getExtensionCount()];
    500       for (int i = 0; i < proto.getExtensionCount(); i++) {
    501         extensions[i] = new FieldDescriptor(
    502           proto.getExtension(i), this, null, i, true);
    503       }
    504     }
    505 
    506     /**
    507      * Create a placeholder FileDescriptor for a message Descriptor.
    508      */
    509     FileDescriptor(String packageName, Descriptor message)
    510         throws DescriptorValidationException {
    511       this.pool = new DescriptorPool(new FileDescriptor[0], true);
    512       this.proto = FileDescriptorProto.newBuilder()
    513           .setName(message.getFullName() + ".placeholder.proto")
    514           .setPackage(packageName).addMessageType(message.toProto()).build();
    515       this.dependencies = new FileDescriptor[0];
    516       this.publicDependencies = new FileDescriptor[0];
    517 
    518       messageTypes = new Descriptor[] {message};
    519       enumTypes = new EnumDescriptor[0];
    520       services = new ServiceDescriptor[0];
    521       extensions = new FieldDescriptor[0];
    522 
    523       pool.addPackage(packageName, this);
    524       pool.addSymbol(message);
    525     }
    526 
    527     /** Look up and cross-link all field types, etc. */
    528     private void crossLink() throws DescriptorValidationException {
    529       for (final Descriptor messageType : messageTypes) {
    530         messageType.crossLink();
    531       }
    532 
    533       for (final ServiceDescriptor service : services) {
    534         service.crossLink();
    535       }
    536 
    537       for (final FieldDescriptor extension : extensions) {
    538         extension.crossLink();
    539       }
    540     }
    541 
    542     /**
    543      * Replace our {@link FileDescriptorProto} with the given one, which is
    544      * identical except that it might contain extensions that weren't present
    545      * in the original.  This method is needed for bootstrapping when a file
    546      * defines custom options.  The options may be defined in the file itself,
    547      * so we can't actually parse them until we've constructed the descriptors,
    548      * but to construct the descriptors we have to have parsed the descriptor
    549      * protos.  So, we have to parse the descriptor protos a second time after
    550      * constructing the descriptors.
    551      */
    552     private void setProto(final FileDescriptorProto proto) {
    553       this.proto = proto;
    554 
    555       for (int i = 0; i < messageTypes.length; i++) {
    556         messageTypes[i].setProto(proto.getMessageType(i));
    557       }
    558 
    559       for (int i = 0; i < enumTypes.length; i++) {
    560         enumTypes[i].setProto(proto.getEnumType(i));
    561       }
    562 
    563       for (int i = 0; i < services.length; i++) {
    564         services[i].setProto(proto.getService(i));
    565       }
    566 
    567       for (int i = 0; i < extensions.length; i++) {
    568         extensions[i].setProto(proto.getExtension(i));
    569       }
    570     }
    571 
    572     boolean supportsUnknownEnumValue() {
    573       return getSyntax() == Syntax.PROTO3;
    574     }
    575   }
    576 
    577   // =================================================================
    578 
    579   /** Describes a message type. */
    580   public static final class Descriptor extends GenericDescriptor {
    581     /**
    582      * Get the index of this descriptor within its parent.  In other words,
    583      * given a {@link FileDescriptor} {@code file}, the following is true:
    584      * <pre>
    585      *   for all i in [0, file.getMessageTypeCount()):
    586      *     file.getMessageType(i).getIndex() == i
    587      * </pre>
    588      * Similarly, for a {@link Descriptor} {@code messageType}:
    589      * <pre>
    590      *   for all i in [0, messageType.getNestedTypeCount()):
    591      *     messageType.getNestedType(i).getIndex() == i
    592      * </pre>
    593      */
    594     public int getIndex() { return index; }
    595 
    596     /** Convert the descriptor to its protocol message representation. */
    597     @Override
    598     public DescriptorProto toProto() {
    599       return proto;
    600     }
    601 
    602     /** Get the type's unqualified name. */
    603     @Override
    604     public String getName() {
    605       return proto.getName();
    606     }
    607 
    608     /**
    609      * Get the type's fully-qualified name, within the proto language's
    610      * namespace.  This differs from the Java name.  For example, given this
    611      * {@code .proto}:
    612      * <pre>
    613      *   package foo.bar;
    614      *   option java_package = "com.example.protos"
    615      *   message Baz {}
    616      * </pre>
    617      * {@code Baz}'s full name is "foo.bar.Baz".
    618      */
    619     @Override
    620     public String getFullName() {
    621       return fullName;
    622     }
    623 
    624     /** Get the {@link FileDescriptor} containing this descriptor. */
    625     @Override
    626     public FileDescriptor getFile() {
    627       return file;
    628     }
    629 
    630     /** If this is a nested type, get the outer descriptor, otherwise null. */
    631     public Descriptor getContainingType() { return containingType; }
    632 
    633     /** Get the {@code MessageOptions}, defined in {@code descriptor.proto}. */
    634     public MessageOptions getOptions() { return proto.getOptions(); }
    635 
    636     /** Get a list of this message type's fields. */
    637     public List<FieldDescriptor> getFields() {
    638       return Collections.unmodifiableList(Arrays.asList(fields));
    639     }
    640 
    641     /** Get a list of this message type's oneofs. */
    642     public List<OneofDescriptor> getOneofs() {
    643       return Collections.unmodifiableList(Arrays.asList(oneofs));
    644     }
    645 
    646     /** Get a list of this message type's extensions. */
    647     public List<FieldDescriptor> getExtensions() {
    648       return Collections.unmodifiableList(Arrays.asList(extensions));
    649     }
    650 
    651     /** Get a list of message types nested within this one. */
    652     public List<Descriptor> getNestedTypes() {
    653       return Collections.unmodifiableList(Arrays.asList(nestedTypes));
    654     }
    655 
    656     /** Get a list of enum types nested within this one. */
    657     public List<EnumDescriptor> getEnumTypes() {
    658       return Collections.unmodifiableList(Arrays.asList(enumTypes));
    659     }
    660 
    661     /** Determines if the given field number is an extension. */
    662     public boolean isExtensionNumber(final int number) {
    663       for (final DescriptorProto.ExtensionRange range :
    664           proto.getExtensionRangeList()) {
    665         if (range.getStart() <= number && number < range.getEnd()) {
    666           return true;
    667         }
    668       }
    669       return false;
    670     }
    671 
    672     /** Determines if the given field number is reserved. */
    673     public boolean isReservedNumber(final int number) {
    674       for (final DescriptorProto.ReservedRange range :
    675           proto.getReservedRangeList()) {
    676         if (range.getStart() <= number && number < range.getEnd()) {
    677           return true;
    678         }
    679       }
    680       return false;
    681     }
    682 
    683     /** Determines if the given field name is reserved. */
    684     public boolean isReservedName(final String name) {
    685       if (name == null) {
    686         throw new NullPointerException();
    687       }
    688       for (final String reservedName : proto.getReservedNameList()) {
    689         if (reservedName.equals(name)) {
    690           return true;
    691         }
    692       }
    693       return false;
    694     }
    695 
    696     /**
    697      * Indicates whether the message can be extended.  That is, whether it has
    698      * any "extensions x to y" ranges declared on it.
    699      */
    700     public boolean isExtendable() {
    701       return proto.getExtensionRangeList().size() != 0;
    702     }
    703 
    704     /**
    705      * Finds a field by name.
    706      * @param name The unqualified name of the field (e.g. "foo").
    707      * @return The field's descriptor, or {@code null} if not found.
    708      */
    709     public FieldDescriptor findFieldByName(final String name) {
    710       final GenericDescriptor result =
    711           file.pool.findSymbol(fullName + '.' + name);
    712       if (result != null && result instanceof FieldDescriptor) {
    713         return (FieldDescriptor)result;
    714       } else {
    715         return null;
    716       }
    717     }
    718 
    719     /**
    720      * Finds a field by field number.
    721      * @param number The field number within this message type.
    722      * @return The field's descriptor, or {@code null} if not found.
    723      */
    724     public FieldDescriptor findFieldByNumber(final int number) {
    725       return file.pool.fieldsByNumber.get(
    726         new DescriptorPool.DescriptorIntPair(this, number));
    727     }
    728 
    729     /**
    730      * Finds a nested message type by name.
    731      * @param name The unqualified name of the nested type (e.g. "Foo").
    732      * @return The types's descriptor, or {@code null} if not found.
    733      */
    734     public Descriptor findNestedTypeByName(final String name) {
    735       final GenericDescriptor result =
    736           file.pool.findSymbol(fullName + '.' + name);
    737       if (result != null && result instanceof Descriptor) {
    738         return (Descriptor)result;
    739       } else {
    740         return null;
    741       }
    742     }
    743 
    744     /**
    745      * Finds a nested enum type by name.
    746      * @param name The unqualified name of the nested type (e.g. "Foo").
    747      * @return The types's descriptor, or {@code null} if not found.
    748      */
    749     public EnumDescriptor findEnumTypeByName(final String name) {
    750       final GenericDescriptor result =
    751           file.pool.findSymbol(fullName + '.' + name);
    752       if (result != null && result instanceof EnumDescriptor) {
    753         return (EnumDescriptor)result;
    754       } else {
    755         return null;
    756       }
    757     }
    758 
    759     private final int index;
    760     private DescriptorProto proto;
    761     private final String fullName;
    762     private final FileDescriptor file;
    763     private final Descriptor containingType;
    764     private final Descriptor[] nestedTypes;
    765     private final EnumDescriptor[] enumTypes;
    766     private final FieldDescriptor[] fields;
    767     private final FieldDescriptor[] extensions;
    768     private final OneofDescriptor[] oneofs;
    769 
    770     // Used to create a placeholder when the type cannot be found.
    771     Descriptor(final String fullname) throws DescriptorValidationException {
    772       String name = fullname;
    773       String packageName = "";
    774       int pos = fullname.lastIndexOf('.');
    775       if (pos != -1) {
    776         name = fullname.substring(pos + 1);
    777         packageName = fullname.substring(0, pos);
    778       }
    779       this.index = 0;
    780       this.proto = DescriptorProto.newBuilder().setName(name).addExtensionRange(
    781           DescriptorProto.ExtensionRange.newBuilder().setStart(1)
    782           .setEnd(536870912).build()).build();
    783       this.fullName = fullname;
    784       this.containingType = null;
    785 
    786       this.nestedTypes = new Descriptor[0];
    787       this.enumTypes = new EnumDescriptor[0];
    788       this.fields = new FieldDescriptor[0];
    789       this.extensions = new FieldDescriptor[0];
    790       this.oneofs = new OneofDescriptor[0];
    791 
    792       // Create a placeholder FileDescriptor to hold this message.
    793       this.file = new FileDescriptor(packageName, this);
    794     }
    795 
    796     private Descriptor(final DescriptorProto proto,
    797                        final FileDescriptor file,
    798                        final Descriptor parent,
    799                        final int index)
    800                 throws DescriptorValidationException {
    801       this.index = index;
    802       this.proto = proto;
    803       fullName = computeFullName(file, parent, proto.getName());
    804       this.file = file;
    805       containingType = parent;
    806 
    807       oneofs = new OneofDescriptor[proto.getOneofDeclCount()];
    808       for (int i = 0; i < proto.getOneofDeclCount(); i++) {
    809         oneofs[i] = new OneofDescriptor(
    810           proto.getOneofDecl(i), file, this, i);
    811       }
    812 
    813       nestedTypes = new Descriptor[proto.getNestedTypeCount()];
    814       for (int i = 0; i < proto.getNestedTypeCount(); i++) {
    815         nestedTypes[i] = new Descriptor(
    816           proto.getNestedType(i), file, this, i);
    817       }
    818 
    819       enumTypes = new EnumDescriptor[proto.getEnumTypeCount()];
    820       for (int i = 0; i < proto.getEnumTypeCount(); i++) {
    821         enumTypes[i] = new EnumDescriptor(
    822           proto.getEnumType(i), file, this, i);
    823       }
    824 
    825       fields = new FieldDescriptor[proto.getFieldCount()];
    826       for (int i = 0; i < proto.getFieldCount(); i++) {
    827         fields[i] = new FieldDescriptor(
    828           proto.getField(i), file, this, i, false);
    829       }
    830 
    831       extensions = new FieldDescriptor[proto.getExtensionCount()];
    832       for (int i = 0; i < proto.getExtensionCount(); i++) {
    833         extensions[i] = new FieldDescriptor(
    834           proto.getExtension(i), file, this, i, true);
    835       }
    836 
    837       for (int i = 0; i < proto.getOneofDeclCount(); i++) {
    838         oneofs[i].fields = new FieldDescriptor[oneofs[i].getFieldCount()];
    839         oneofs[i].fieldCount = 0;
    840       }
    841       for (int i = 0; i < proto.getFieldCount(); i++) {
    842         OneofDescriptor oneofDescriptor = fields[i].getContainingOneof();
    843         if (oneofDescriptor != null) {
    844           oneofDescriptor.fields[oneofDescriptor.fieldCount++] = fields[i];
    845         }
    846       }
    847 
    848       file.pool.addSymbol(this);
    849     }
    850 
    851     /** Look up and cross-link all field types, etc. */
    852     private void crossLink() throws DescriptorValidationException {
    853       for (final Descriptor nestedType : nestedTypes) {
    854         nestedType.crossLink();
    855       }
    856 
    857       for (final FieldDescriptor field : fields) {
    858         field.crossLink();
    859       }
    860 
    861       for (final FieldDescriptor extension : extensions) {
    862         extension.crossLink();
    863       }
    864     }
    865 
    866     /** See {@link FileDescriptor#setProto}. */
    867     private void setProto(final DescriptorProto proto) {
    868       this.proto = proto;
    869 
    870       for (int i = 0; i < nestedTypes.length; i++) {
    871         nestedTypes[i].setProto(proto.getNestedType(i));
    872       }
    873 
    874       for (int i = 0; i < enumTypes.length; i++) {
    875         enumTypes[i].setProto(proto.getEnumType(i));
    876       }
    877 
    878       for (int i = 0; i < fields.length; i++) {
    879         fields[i].setProto(proto.getField(i));
    880       }
    881 
    882       for (int i = 0; i < extensions.length; i++) {
    883         extensions[i].setProto(proto.getExtension(i));
    884       }
    885     }
    886   }
    887 
    888   // =================================================================
    889 
    890   /** Describes a field of a message type. */
    891   public static final class FieldDescriptor
    892         extends GenericDescriptor
    893         implements Comparable<FieldDescriptor>,
    894                  FieldSet.FieldDescriptorLite<FieldDescriptor> {
    895     /**
    896      * Get the index of this descriptor within its parent.
    897      * @see Descriptors.Descriptor#getIndex()
    898      */
    899     public int getIndex() { return index; }
    900 
    901     /** Convert the descriptor to its protocol message representation. */
    902     @Override
    903     public FieldDescriptorProto toProto() {
    904       return proto;
    905     }
    906 
    907     /** Get the field's unqualified name. */
    908     @Override
    909     public String getName() {
    910       return proto.getName();
    911     }
    912 
    913     /** Get the field's number. */
    914     @Override
    915     public int getNumber() {
    916       return proto.getNumber();
    917     }
    918 
    919     /**
    920      * Get the field's fully-qualified name.
    921      * @see Descriptors.Descriptor#getFullName()
    922      */
    923     @Override
    924     public String getFullName() {
    925       return fullName;
    926     }
    927 
    928     /** Get the JSON name of this field. */
    929     public String getJsonName() {
    930       return jsonName;
    931     }
    932 
    933     /**
    934      * Get the field's java type.  This is just for convenience.  Every
    935      * {@code FieldDescriptorProto.Type} maps to exactly one Java type.
    936      */
    937     public JavaType getJavaType() { return type.getJavaType(); }
    938 
    939     /** For internal use only. */
    940     @Override
    941     public WireFormat.JavaType getLiteJavaType() {
    942       return getLiteType().getJavaType();
    943     }
    944 
    945     /** Get the {@code FileDescriptor} containing this descriptor. */
    946     @Override
    947     public FileDescriptor getFile() {
    948       return file;
    949     }
    950 
    951     /** Get the field's declared type. */
    952     public Type getType() { return type; }
    953 
    954     /** For internal use only. */
    955     @Override
    956     public WireFormat.FieldType getLiteType() {
    957       return table[type.ordinal()];
    958     }
    959 
    960     /** For internal use only. */
    961     public boolean needsUtf8Check() {
    962       if (type != Type.STRING) {
    963         return false;
    964       }
    965       if (getContainingType().getOptions().getMapEntry()) {
    966         // Always enforce strict UTF-8 checking for map fields.
    967         return true;
    968       }
    969       if (getFile().getSyntax() == Syntax.PROTO3) {
    970         return true;
    971       }
    972       return getFile().getOptions().getJavaStringCheckUtf8();
    973     }
    974 
    975     public boolean isMapField() {
    976       return getType() == Type.MESSAGE && isRepeated()
    977           && getMessageType().getOptions().getMapEntry();
    978     }
    979 
    980     // I'm pretty sure values() constructs a new array every time, since there
    981     // is nothing stopping the caller from mutating the array.  Therefore we
    982     // make a static copy here.
    983     private static final WireFormat.FieldType[] table =
    984         WireFormat.FieldType.values();
    985 
    986     /** Is this field declared required? */
    987     public boolean isRequired() {
    988       return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REQUIRED;
    989     }
    990 
    991     /** Is this field declared optional? */
    992     public boolean isOptional() {
    993       return proto.getLabel() == FieldDescriptorProto.Label.LABEL_OPTIONAL;
    994     }
    995 
    996     /** Is this field declared repeated? */
    997     @Override
    998     public boolean isRepeated() {
    999       return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REPEATED;
   1000     }
   1001 
   1002     /** Does this field have the {@code [packed = true]} option or is this field
   1003      *  packable in proto3 and not explicitly setted to unpacked?
   1004      */
   1005     @Override
   1006     public boolean isPacked() {
   1007       if (!isPackable()) {
   1008         return false;
   1009       }
   1010       if (getFile().getSyntax() == FileDescriptor.Syntax.PROTO2) {
   1011         return getOptions().getPacked();
   1012       } else {
   1013         return !getOptions().hasPacked() || getOptions().getPacked();
   1014       }
   1015     }
   1016 
   1017     /** Can this field be packed? i.e. is it a repeated primitive field? */
   1018     public boolean isPackable() {
   1019       return isRepeated() && getLiteType().isPackable();
   1020     }
   1021 
   1022     /** Returns true if the field had an explicitly-defined default value. */
   1023     public boolean hasDefaultValue() { return proto.hasDefaultValue(); }
   1024 
   1025     /**
   1026      * Returns the field's default value.  Valid for all types except for
   1027      * messages and groups.  For all other types, the object returned is of
   1028      * the same class that would returned by Message.getField(this).
   1029      */
   1030     public Object getDefaultValue() {
   1031       if (getJavaType() == JavaType.MESSAGE) {
   1032         throw new UnsupportedOperationException(
   1033           "FieldDescriptor.getDefaultValue() called on an embedded message " +
   1034           "field.");
   1035       }
   1036       return defaultValue;
   1037     }
   1038 
   1039     /** Get the {@code FieldOptions}, defined in {@code descriptor.proto}. */
   1040     public FieldOptions getOptions() { return proto.getOptions(); }
   1041 
   1042     /** Is this field an extension? */
   1043     public boolean isExtension() { return proto.hasExtendee(); }
   1044 
   1045     /**
   1046      * Get the field's containing type. For extensions, this is the type being
   1047      * extended, not the location where the extension was defined.  See
   1048      * {@link #getExtensionScope()}.
   1049      */
   1050     public Descriptor getContainingType() { return containingType; }
   1051 
   1052     /** Get the field's containing oneof. */
   1053     public OneofDescriptor getContainingOneof() { return containingOneof; }
   1054 
   1055     /**
   1056      * For extensions defined nested within message types, gets the outer
   1057      * type.  Not valid for non-extension fields.  For example, consider
   1058      * this {@code .proto} file:
   1059      * <pre>
   1060      *   message Foo {
   1061      *     extensions 1000 to max;
   1062      *   }
   1063      *   extend Foo {
   1064      *     optional int32 baz = 1234;
   1065      *   }
   1066      *   message Bar {
   1067      *     extend Foo {
   1068      *       optional int32 qux = 4321;
   1069      *     }
   1070      *   }
   1071      * </pre>
   1072      * Both {@code baz}'s and {@code qux}'s containing type is {@code Foo}.
   1073      * However, {@code baz}'s extension scope is {@code null} while
   1074      * {@code qux}'s extension scope is {@code Bar}.
   1075      */
   1076     public Descriptor getExtensionScope() {
   1077       if (!isExtension()) {
   1078         throw new UnsupportedOperationException(
   1079           "This field is not an extension.");
   1080       }
   1081       return extensionScope;
   1082     }
   1083 
   1084     /** For embedded message and group fields, gets the field's type. */
   1085     public Descriptor getMessageType() {
   1086       if (getJavaType() != JavaType.MESSAGE) {
   1087         throw new UnsupportedOperationException(
   1088           "This field is not of message type.");
   1089       }
   1090       return messageType;
   1091     }
   1092 
   1093     /** For enum fields, gets the field's type. */
   1094     @Override
   1095     public EnumDescriptor getEnumType() {
   1096       if (getJavaType() != JavaType.ENUM) {
   1097         throw new UnsupportedOperationException(
   1098           "This field is not of enum type.");
   1099       }
   1100       return enumType;
   1101     }
   1102 
   1103     /**
   1104      * Compare with another {@code FieldDescriptor}.  This orders fields in
   1105      * "canonical" order, which simply means ascending order by field number.
   1106      * {@code other} must be a field of the same type -- i.e.
   1107      * {@code getContainingType()} must return the same {@code Descriptor} for
   1108      * both fields.
   1109      *
   1110      * @return negative, zero, or positive if {@code this} is less than,
   1111      *         equal to, or greater than {@code other}, respectively.
   1112      */
   1113     @Override
   1114     public int compareTo(final FieldDescriptor other) {
   1115       if (other.containingType != containingType) {
   1116         throw new IllegalArgumentException(
   1117           "FieldDescriptors can only be compared to other FieldDescriptors " +
   1118           "for fields of the same message type.");
   1119       }
   1120       return getNumber() - other.getNumber();
   1121     }
   1122 
   1123     @Override
   1124     public String toString() {
   1125       return getFullName();
   1126     }
   1127 
   1128     private final int index;
   1129 
   1130     private FieldDescriptorProto proto;
   1131     private final String fullName;
   1132     private final String jsonName;
   1133     private final FileDescriptor file;
   1134     private final Descriptor extensionScope;
   1135 
   1136     // Possibly initialized during cross-linking.
   1137     private Type type;
   1138     private Descriptor containingType;
   1139     private Descriptor messageType;
   1140     private OneofDescriptor containingOneof;
   1141     private EnumDescriptor enumType;
   1142     private Object defaultValue;
   1143 
   1144     public enum Type {
   1145       DOUBLE  (JavaType.DOUBLE     ),
   1146       FLOAT   (JavaType.FLOAT      ),
   1147       INT64   (JavaType.LONG       ),
   1148       UINT64  (JavaType.LONG       ),
   1149       INT32   (JavaType.INT        ),
   1150       FIXED64 (JavaType.LONG       ),
   1151       FIXED32 (JavaType.INT        ),
   1152       BOOL    (JavaType.BOOLEAN    ),
   1153       STRING  (JavaType.STRING     ),
   1154       GROUP   (JavaType.MESSAGE    ),
   1155       MESSAGE (JavaType.MESSAGE    ),
   1156       BYTES   (JavaType.BYTE_STRING),
   1157       UINT32  (JavaType.INT        ),
   1158       ENUM    (JavaType.ENUM       ),
   1159       SFIXED32(JavaType.INT        ),
   1160       SFIXED64(JavaType.LONG       ),
   1161       SINT32  (JavaType.INT        ),
   1162       SINT64  (JavaType.LONG       );
   1163 
   1164       Type(final JavaType javaType) {
   1165         this.javaType = javaType;
   1166       }
   1167 
   1168       private JavaType javaType;
   1169 
   1170       public FieldDescriptorProto.Type toProto() {
   1171         return FieldDescriptorProto.Type.forNumber(ordinal() + 1);
   1172       }
   1173       public JavaType getJavaType() { return javaType; }
   1174 
   1175       public static Type valueOf(final FieldDescriptorProto.Type type) {
   1176         return values()[type.getNumber() - 1];
   1177       }
   1178     }
   1179 
   1180     static {
   1181       // Refuse to init if someone added a new declared type.
   1182       if (Type.values().length != FieldDescriptorProto.Type.values().length) {
   1183         throw new RuntimeException(""
   1184             + "descriptor.proto has a new declared type but Descriptors.java "
   1185             + "wasn't updated.");
   1186       }
   1187     }
   1188 
   1189     public enum JavaType {
   1190       INT(0),
   1191       LONG(0L),
   1192       FLOAT(0F),
   1193       DOUBLE(0D),
   1194       BOOLEAN(false),
   1195       STRING(""),
   1196       BYTE_STRING(ByteString.EMPTY),
   1197       ENUM(null),
   1198       MESSAGE(null);
   1199 
   1200       JavaType(final Object defaultDefault) {
   1201         this.defaultDefault = defaultDefault;
   1202       }
   1203 
   1204       /**
   1205        * The default default value for fields of this type, if it's a primitive
   1206        * type.  This is meant for use inside this file only, hence is private.
   1207        */
   1208       private final Object defaultDefault;
   1209     }
   1210 
   1211     // TODO(xiaofeng): Implement it consistently across different languages. See b/24751348.
   1212     private static String fieldNameToLowerCamelCase(String name) {
   1213       StringBuilder result = new StringBuilder(name.length());
   1214       boolean isNextUpperCase = false;
   1215       for (int i = 0; i < name.length(); i++) {
   1216         Character ch = name.charAt(i);
   1217         if (Character.isLowerCase(ch)) {
   1218           if (isNextUpperCase) {
   1219             result.append(Character.toUpperCase(ch));
   1220           } else {
   1221             result.append(ch);
   1222           }
   1223           isNextUpperCase = false;
   1224         } else if (Character.isUpperCase(ch)) {
   1225           if (i == 0) {
   1226             // Force first letter to lower-case.
   1227             result.append(Character.toLowerCase(ch));
   1228           } else {
   1229             // Capital letters after the first are left as-is.
   1230             result.append(ch);
   1231           }
   1232           isNextUpperCase = false;
   1233         } else if (Character.isDigit(ch)) {
   1234           result.append(ch);
   1235           isNextUpperCase = false;
   1236         } else {
   1237           isNextUpperCase = true;
   1238         }
   1239       }
   1240       return result.toString();
   1241     }
   1242 
   1243     private FieldDescriptor(final FieldDescriptorProto proto,
   1244                             final FileDescriptor file,
   1245                             final Descriptor parent,
   1246                             final int index,
   1247                             final boolean isExtension)
   1248                      throws DescriptorValidationException {
   1249       this.index = index;
   1250       this.proto = proto;
   1251       fullName = computeFullName(file, parent, proto.getName());
   1252       this.file = file;
   1253       if (proto.hasJsonName()) {
   1254         jsonName = proto.getJsonName();
   1255       } else {
   1256         jsonName = fieldNameToLowerCamelCase(proto.getName());
   1257       }
   1258 
   1259       if (proto.hasType()) {
   1260         type = Type.valueOf(proto.getType());
   1261       }
   1262 
   1263       if (getNumber() <= 0) {
   1264         throw new DescriptorValidationException(this,
   1265           "Field numbers must be positive integers.");
   1266       }
   1267 
   1268       if (isExtension) {
   1269         if (!proto.hasExtendee()) {
   1270           throw new DescriptorValidationException(this,
   1271             "FieldDescriptorProto.extendee not set for extension field.");
   1272         }
   1273         containingType = null;  // Will be filled in when cross-linking
   1274         if (parent != null) {
   1275           extensionScope = parent;
   1276         } else {
   1277           extensionScope = null;
   1278         }
   1279 
   1280         if (proto.hasOneofIndex()) {
   1281           throw new DescriptorValidationException(this,
   1282             "FieldDescriptorProto.oneof_index set for extension field.");
   1283         }
   1284         containingOneof = null;
   1285       } else {
   1286         if (proto.hasExtendee()) {
   1287           throw new DescriptorValidationException(this,
   1288             "FieldDescriptorProto.extendee set for non-extension field.");
   1289         }
   1290         containingType = parent;
   1291 
   1292         if (proto.hasOneofIndex()) {
   1293           if (proto.getOneofIndex() < 0 ||
   1294               proto.getOneofIndex() >= parent.toProto().getOneofDeclCount()) {
   1295             throw new DescriptorValidationException(this,
   1296               "FieldDescriptorProto.oneof_index is out of range for type "
   1297               + parent.getName());
   1298           }
   1299           containingOneof = parent.getOneofs().get(proto.getOneofIndex());
   1300           containingOneof.fieldCount++;
   1301         } else {
   1302           containingOneof = null;
   1303         }
   1304         extensionScope = null;
   1305       }
   1306 
   1307       file.pool.addSymbol(this);
   1308     }
   1309 
   1310     /** Look up and cross-link all field types, etc. */
   1311     private void crossLink() throws DescriptorValidationException {
   1312       if (proto.hasExtendee()) {
   1313         final GenericDescriptor extendee =
   1314           file.pool.lookupSymbol(proto.getExtendee(), this,
   1315               DescriptorPool.SearchFilter.TYPES_ONLY);
   1316         if (!(extendee instanceof Descriptor)) {
   1317           throw new DescriptorValidationException(this,
   1318               '\"' + proto.getExtendee() + "\" is not a message type.");
   1319         }
   1320         containingType = (Descriptor)extendee;
   1321 
   1322         if (!getContainingType().isExtensionNumber(getNumber())) {
   1323           throw new DescriptorValidationException(this,
   1324               '\"' + getContainingType().getFullName() +
   1325               "\" does not declare " + getNumber() +
   1326               " as an extension number.");
   1327         }
   1328       }
   1329 
   1330       if (proto.hasTypeName()) {
   1331         final GenericDescriptor typeDescriptor =
   1332           file.pool.lookupSymbol(proto.getTypeName(), this,
   1333               DescriptorPool.SearchFilter.TYPES_ONLY);
   1334 
   1335         if (!proto.hasType()) {
   1336           // Choose field type based on symbol.
   1337           if (typeDescriptor instanceof Descriptor) {
   1338             type = Type.MESSAGE;
   1339           } else if (typeDescriptor instanceof EnumDescriptor) {
   1340             type = Type.ENUM;
   1341           } else {
   1342             throw new DescriptorValidationException(this,
   1343                 '\"' + proto.getTypeName() + "\" is not a type.");
   1344           }
   1345         }
   1346 
   1347         if (getJavaType() == JavaType.MESSAGE) {
   1348           if (!(typeDescriptor instanceof Descriptor)) {
   1349             throw new DescriptorValidationException(this,
   1350                 '\"' + proto.getTypeName() + "\" is not a message type.");
   1351           }
   1352           messageType = (Descriptor)typeDescriptor;
   1353 
   1354           if (proto.hasDefaultValue()) {
   1355             throw new DescriptorValidationException(this,
   1356               "Messages can't have default values.");
   1357           }
   1358         } else if (getJavaType() == JavaType.ENUM) {
   1359           if (!(typeDescriptor instanceof EnumDescriptor)) {
   1360             throw new DescriptorValidationException(this,
   1361                 '\"' + proto.getTypeName() + "\" is not an enum type.");
   1362           }
   1363           enumType = (EnumDescriptor)typeDescriptor;
   1364         } else {
   1365           throw new DescriptorValidationException(this,
   1366             "Field with primitive type has type_name.");
   1367         }
   1368       } else {
   1369         if (getJavaType() == JavaType.MESSAGE ||
   1370             getJavaType() == JavaType.ENUM) {
   1371           throw new DescriptorValidationException(this,
   1372             "Field with message or enum type missing type_name.");
   1373         }
   1374       }
   1375 
   1376       // Only repeated primitive fields may be packed.
   1377       if (proto.getOptions().getPacked() && !isPackable()) {
   1378         throw new DescriptorValidationException(this,
   1379           "[packed = true] can only be specified for repeated primitive " +
   1380           "fields.");
   1381       }
   1382 
   1383       // We don't attempt to parse the default value until here because for
   1384       // enums we need the enum type's descriptor.
   1385       if (proto.hasDefaultValue()) {
   1386         if (isRepeated()) {
   1387           throw new DescriptorValidationException(this,
   1388             "Repeated fields cannot have default values.");
   1389         }
   1390 
   1391         try {
   1392           switch (getType()) {
   1393             case INT32:
   1394             case SINT32:
   1395             case SFIXED32:
   1396               defaultValue = TextFormat.parseInt32(proto.getDefaultValue());
   1397               break;
   1398             case UINT32:
   1399             case FIXED32:
   1400               defaultValue = TextFormat.parseUInt32(proto.getDefaultValue());
   1401               break;
   1402             case INT64:
   1403             case SINT64:
   1404             case SFIXED64:
   1405               defaultValue = TextFormat.parseInt64(proto.getDefaultValue());
   1406               break;
   1407             case UINT64:
   1408             case FIXED64:
   1409               defaultValue = TextFormat.parseUInt64(proto.getDefaultValue());
   1410               break;
   1411             case FLOAT:
   1412               if (proto.getDefaultValue().equals("inf")) {
   1413                 defaultValue = Float.POSITIVE_INFINITY;
   1414               } else if (proto.getDefaultValue().equals("-inf")) {
   1415                 defaultValue = Float.NEGATIVE_INFINITY;
   1416               } else if (proto.getDefaultValue().equals("nan")) {
   1417                 defaultValue = Float.NaN;
   1418               } else {
   1419                 defaultValue = Float.valueOf(proto.getDefaultValue());
   1420               }
   1421               break;
   1422             case DOUBLE:
   1423               if (proto.getDefaultValue().equals("inf")) {
   1424                 defaultValue = Double.POSITIVE_INFINITY;
   1425               } else if (proto.getDefaultValue().equals("-inf")) {
   1426                 defaultValue = Double.NEGATIVE_INFINITY;
   1427               } else if (proto.getDefaultValue().equals("nan")) {
   1428                 defaultValue = Double.NaN;
   1429               } else {
   1430                 defaultValue = Double.valueOf(proto.getDefaultValue());
   1431               }
   1432               break;
   1433             case BOOL:
   1434               defaultValue = Boolean.valueOf(proto.getDefaultValue());
   1435               break;
   1436             case STRING:
   1437               defaultValue = proto.getDefaultValue();
   1438               break;
   1439             case BYTES:
   1440               try {
   1441                 defaultValue =
   1442                   TextFormat.unescapeBytes(proto.getDefaultValue());
   1443               } catch (TextFormat.InvalidEscapeSequenceException e) {
   1444                 throw new DescriptorValidationException(this,
   1445                   "Couldn't parse default value: " + e.getMessage(), e);
   1446               }
   1447               break;
   1448             case ENUM:
   1449               defaultValue = enumType.findValueByName(proto.getDefaultValue());
   1450               if (defaultValue == null) {
   1451                 throw new DescriptorValidationException(this,
   1452                   "Unknown enum default value: \"" +
   1453                   proto.getDefaultValue() + '\"');
   1454               }
   1455               break;
   1456             case MESSAGE:
   1457             case GROUP:
   1458               throw new DescriptorValidationException(this,
   1459                 "Message type had default value.");
   1460           }
   1461         } catch (NumberFormatException e) {
   1462           throw new DescriptorValidationException(this,
   1463               "Could not parse default value: \"" +
   1464               proto.getDefaultValue() + '\"', e);
   1465         }
   1466       } else {
   1467         // Determine the default default for this field.
   1468         if (isRepeated()) {
   1469           defaultValue = Collections.emptyList();
   1470         } else {
   1471           switch (getJavaType()) {
   1472             case ENUM:
   1473               // We guarantee elsewhere that an enum type always has at least
   1474               // one possible value.
   1475               defaultValue = enumType.getValues().get(0);
   1476               break;
   1477             case MESSAGE:
   1478               defaultValue = null;
   1479               break;
   1480             default:
   1481               defaultValue = getJavaType().defaultDefault;
   1482               break;
   1483           }
   1484         }
   1485       }
   1486 
   1487       if (!isExtension()) {
   1488         file.pool.addFieldByNumber(this);
   1489       }
   1490 
   1491       if (containingType != null &&
   1492           containingType.getOptions().getMessageSetWireFormat()) {
   1493         if (isExtension()) {
   1494           if (!isOptional() || getType() != Type.MESSAGE) {
   1495             throw new DescriptorValidationException(this,
   1496               "Extensions of MessageSets must be optional messages.");
   1497           }
   1498         } else {
   1499           throw new DescriptorValidationException(this,
   1500             "MessageSets cannot have fields, only extensions.");
   1501         }
   1502       }
   1503     }
   1504 
   1505     /** See {@link FileDescriptor#setProto}. */
   1506     private void setProto(final FieldDescriptorProto proto) {
   1507       this.proto = proto;
   1508     }
   1509 
   1510     /**
   1511      * For internal use only.  This is to satisfy the FieldDescriptorLite
   1512      * interface.
   1513      */
   1514     @Override
   1515     public MessageLite.Builder internalMergeFrom(MessageLite.Builder to, MessageLite from) {
   1516       // FieldDescriptors are only used with non-lite messages so we can just
   1517       // down-cast and call mergeFrom directly.
   1518       return ((Message.Builder) to).mergeFrom((Message) from);
   1519     }
   1520 
   1521   }
   1522 
   1523   // =================================================================
   1524 
   1525   /** Describes an enum type. */
   1526   public static final class EnumDescriptor extends GenericDescriptor
   1527       implements Internal.EnumLiteMap<EnumValueDescriptor> {
   1528     /**
   1529      * Get the index of this descriptor within its parent.
   1530      * @see Descriptors.Descriptor#getIndex()
   1531      */
   1532     public int getIndex() { return index; }
   1533 
   1534     /** Convert the descriptor to its protocol message representation. */
   1535     @Override
   1536     public EnumDescriptorProto toProto() {
   1537       return proto;
   1538     }
   1539 
   1540     /** Get the type's unqualified name. */
   1541     @Override
   1542     public String getName() {
   1543       return proto.getName();
   1544     }
   1545 
   1546     /**
   1547      * Get the type's fully-qualified name.
   1548      * @see Descriptors.Descriptor#getFullName()
   1549      */
   1550     @Override
   1551     public String getFullName() {
   1552       return fullName;
   1553     }
   1554 
   1555     /** Get the {@link FileDescriptor} containing this descriptor. */
   1556     @Override
   1557     public FileDescriptor getFile() {
   1558       return file;
   1559     }
   1560 
   1561     /** If this is a nested type, get the outer descriptor, otherwise null. */
   1562     public Descriptor getContainingType() { return containingType; }
   1563 
   1564     /** Get the {@code EnumOptions}, defined in {@code descriptor.proto}. */
   1565     public EnumOptions getOptions() { return proto.getOptions(); }
   1566 
   1567     /** Get a list of defined values for this enum. */
   1568     public List<EnumValueDescriptor> getValues() {
   1569       return Collections.unmodifiableList(Arrays.asList(values));
   1570     }
   1571 
   1572     /**
   1573      * Find an enum value by name.
   1574      * @param name The unqualified name of the value (e.g. "FOO").
   1575      * @return the value's descriptor, or {@code null} if not found.
   1576      */
   1577     public EnumValueDescriptor findValueByName(final String name) {
   1578       final GenericDescriptor result =
   1579           file.pool.findSymbol(fullName + '.' + name);
   1580       if (result != null && result instanceof EnumValueDescriptor) {
   1581         return (EnumValueDescriptor)result;
   1582       } else {
   1583         return null;
   1584       }
   1585     }
   1586 
   1587     /**
   1588      * Find an enum value by number.  If multiple enum values have the same
   1589      * number, this returns the first defined value with that number.
   1590      * @param number The value's number.
   1591      * @return the value's descriptor, or {@code null} if not found.
   1592      */
   1593     @Override
   1594     public EnumValueDescriptor findValueByNumber(final int number) {
   1595       return file.pool.enumValuesByNumber.get(
   1596         new DescriptorPool.DescriptorIntPair(this, number));
   1597     }
   1598 
   1599     /**
   1600      * Get the enum value for a number. If no enum value has this number,
   1601      * construct an EnumValueDescriptor for it.
   1602      */
   1603     public EnumValueDescriptor findValueByNumberCreatingIfUnknown(final int number) {
   1604       EnumValueDescriptor result = findValueByNumber(number);
   1605       if (result != null) {
   1606         return result;
   1607       }
   1608       // The number represents an unknown enum value.
   1609       synchronized (this) {
   1610         // Descriptors are compared by object identity so for the same number
   1611         // we need to return the same EnumValueDescriptor object. This means
   1612         // we have to store created EnumValueDescriptors. However, as there
   1613         // are potentially 2G unknown enum values, storing all of these
   1614         // objects persistently will consume lots of memory for long-running
   1615         // services and it's also unnecessary as not many EnumValueDescriptors
   1616         // will be used at the same time.
   1617         //
   1618         // To solve the problem we take advantage of Java's weak references and
   1619         // rely on gc to release unused descriptors.
   1620         //
   1621         // Here is how it works:
   1622         //   * We store unknown EnumValueDescriptors in a WeakHashMap with the
   1623         //     value being a weak reference to the descriptor.
   1624         //   * The descriptor holds a strong reference to the key so as long
   1625         //     as the EnumValueDescriptor is in use, the key will be there
   1626         //     and the corresponding map entry will be there. Following-up
   1627         //     queries with the same number will return the same descriptor.
   1628         //   * If the user no longer uses an unknown EnumValueDescriptor,
   1629         //     it will be gc-ed since we only hold a weak reference to it in
   1630         //     the map. The key in the corresponding map entry will also be
   1631         //     gc-ed as the only strong reference to it is in the descriptor
   1632         //     which is just gc-ed. With the key being gone WeakHashMap will
   1633         //     then remove the whole entry. This way unknown descriptors will
   1634         //     be freed automatically and we don't need to do anything to
   1635         //     clean-up unused map entries.
   1636 
   1637         // Note: We must use "new Integer(number)" here because we don't want
   1638         // these Integer objects to be cached.
   1639         Integer key = new Integer(number);
   1640         WeakReference<EnumValueDescriptor> reference = unknownValues.get(key);
   1641         if (reference != null) {
   1642           result = reference.get();
   1643         }
   1644         if (result == null) {
   1645           result = new EnumValueDescriptor(file, this, key);
   1646           unknownValues.put(key, new WeakReference<EnumValueDescriptor>(result));
   1647         }
   1648       }
   1649       return result;
   1650     }
   1651 
   1652     // Used in tests only.
   1653     int getUnknownEnumValueDescriptorCount() {
   1654       return unknownValues.size();
   1655     }
   1656 
   1657     private final int index;
   1658     private EnumDescriptorProto proto;
   1659     private final String fullName;
   1660     private final FileDescriptor file;
   1661     private final Descriptor containingType;
   1662     private EnumValueDescriptor[] values;
   1663     private final WeakHashMap<Integer, WeakReference<EnumValueDescriptor>> unknownValues =
   1664         new WeakHashMap<Integer, WeakReference<EnumValueDescriptor>>();
   1665 
   1666     private EnumDescriptor(final EnumDescriptorProto proto,
   1667                            final FileDescriptor file,
   1668                            final Descriptor parent,
   1669                            final int index)
   1670                     throws DescriptorValidationException {
   1671       this.index = index;
   1672       this.proto = proto;
   1673       fullName = computeFullName(file, parent, proto.getName());
   1674       this.file = file;
   1675       containingType = parent;
   1676 
   1677       if (proto.getValueCount() == 0) {
   1678         // We cannot allow enums with no values because this would mean there
   1679         // would be no valid default value for fields of this type.
   1680         throw new DescriptorValidationException(this,
   1681           "Enums must contain at least one value.");
   1682       }
   1683 
   1684       values = new EnumValueDescriptor[proto.getValueCount()];
   1685       for (int i = 0; i < proto.getValueCount(); i++) {
   1686         values[i] = new EnumValueDescriptor(
   1687           proto.getValue(i), file, this, i);
   1688       }
   1689 
   1690       file.pool.addSymbol(this);
   1691     }
   1692 
   1693     /** See {@link FileDescriptor#setProto}. */
   1694     private void setProto(final EnumDescriptorProto proto) {
   1695       this.proto = proto;
   1696 
   1697       for (int i = 0; i < values.length; i++) {
   1698         values[i].setProto(proto.getValue(i));
   1699       }
   1700     }
   1701   }
   1702 
   1703   // =================================================================
   1704 
   1705   /**
   1706    * Describes one value within an enum type.  Note that multiple defined
   1707    * values may have the same number.  In generated Java code, all values
   1708    * with the same number after the first become aliases of the first.
   1709    * However, they still have independent EnumValueDescriptors.
   1710    */
   1711   public static final class EnumValueDescriptor extends GenericDescriptor
   1712       implements Internal.EnumLite {
   1713     /**
   1714      * Get the index of this descriptor within its parent.
   1715      * @see Descriptors.Descriptor#getIndex()
   1716      */
   1717     public int getIndex() { return index; }
   1718 
   1719     /** Convert the descriptor to its protocol message representation. */
   1720     @Override
   1721     public EnumValueDescriptorProto toProto() {
   1722       return proto;
   1723     }
   1724 
   1725     /** Get the value's unqualified name. */
   1726     @Override
   1727     public String getName() {
   1728       return proto.getName();
   1729     }
   1730 
   1731     /** Get the value's number. */
   1732     @Override
   1733     public int getNumber() {
   1734       return proto.getNumber();
   1735     }
   1736 
   1737     @Override
   1738     public String toString() { return proto.getName(); }
   1739 
   1740     /**
   1741      * Get the value's fully-qualified name.
   1742      * @see Descriptors.Descriptor#getFullName()
   1743      */
   1744     @Override
   1745     public String getFullName() {
   1746       return fullName;
   1747     }
   1748 
   1749     /** Get the {@link FileDescriptor} containing this descriptor. */
   1750     @Override
   1751     public FileDescriptor getFile() {
   1752       return file;
   1753     }
   1754 
   1755     /** Get the value's enum type. */
   1756     public EnumDescriptor getType() { return type; }
   1757 
   1758     /**
   1759      * Get the {@code EnumValueOptions}, defined in {@code descriptor.proto}.
   1760      */
   1761     public EnumValueOptions getOptions() { return proto.getOptions(); }
   1762 
   1763     private final int index;
   1764     private EnumValueDescriptorProto proto;
   1765     private final String fullName;
   1766     private final FileDescriptor file;
   1767     private final EnumDescriptor type;
   1768 
   1769     private EnumValueDescriptor(final EnumValueDescriptorProto proto,
   1770                                 final FileDescriptor file,
   1771                                 final EnumDescriptor parent,
   1772                                 final int index)
   1773                          throws DescriptorValidationException {
   1774       this.index = index;
   1775       this.proto = proto;
   1776       this.file = file;
   1777       type = parent;
   1778 
   1779       fullName = parent.getFullName() + '.' + proto.getName();
   1780 
   1781       file.pool.addSymbol(this);
   1782       file.pool.addEnumValueByNumber(this);
   1783     }
   1784 
   1785     private Integer number;
   1786     // Create an unknown enum value.
   1787     private EnumValueDescriptor(
   1788         final FileDescriptor file,
   1789         final EnumDescriptor parent,
   1790         final Integer number) {
   1791       String name = "UNKNOWN_ENUM_VALUE_" + parent.getName() + "_" + number;
   1792       EnumValueDescriptorProto proto = EnumValueDescriptorProto
   1793           .newBuilder().setName(name).setNumber(number).build();
   1794       this.index = -1;
   1795       this.proto = proto;
   1796       this.file = file;
   1797       this.type = parent;
   1798       this.fullName = parent.getFullName() + '.' + proto.getName();
   1799       this.number = number;
   1800 
   1801       // Don't add this descriptor into pool.
   1802     }
   1803 
   1804     /** See {@link FileDescriptor#setProto}. */
   1805     private void setProto(final EnumValueDescriptorProto proto) {
   1806       this.proto = proto;
   1807     }
   1808   }
   1809 
   1810   // =================================================================
   1811 
   1812   /** Describes a service type. */
   1813   public static final class ServiceDescriptor extends GenericDescriptor {
   1814     /**
   1815      * Get the index of this descriptor within its parent.
   1816      * * @see Descriptors.Descriptor#getIndex()
   1817      */
   1818     public int getIndex() { return index; }
   1819 
   1820     /** Convert the descriptor to its protocol message representation. */
   1821     @Override
   1822     public ServiceDescriptorProto toProto() {
   1823       return proto;
   1824     }
   1825 
   1826     /** Get the type's unqualified name. */
   1827     @Override
   1828     public String getName() {
   1829       return proto.getName();
   1830     }
   1831 
   1832     /**
   1833      * Get the type's fully-qualified name.
   1834      * @see Descriptors.Descriptor#getFullName()
   1835      */
   1836     @Override
   1837     public String getFullName() {
   1838       return fullName;
   1839     }
   1840 
   1841     /** Get the {@link FileDescriptor} containing this descriptor. */
   1842     @Override
   1843     public FileDescriptor getFile() {
   1844       return file;
   1845     }
   1846 
   1847     /** Get the {@code ServiceOptions}, defined in {@code descriptor.proto}. */
   1848     public ServiceOptions getOptions() { return proto.getOptions(); }
   1849 
   1850     /** Get a list of methods for this service. */
   1851     public List<MethodDescriptor> getMethods() {
   1852       return Collections.unmodifiableList(Arrays.asList(methods));
   1853     }
   1854 
   1855     /**
   1856      * Find a method by name.
   1857      * @param name The unqualified name of the method (e.g. "Foo").
   1858      * @return the method's descriptor, or {@code null} if not found.
   1859      */
   1860     public MethodDescriptor findMethodByName(final String name) {
   1861       final GenericDescriptor result =
   1862           file.pool.findSymbol(fullName + '.' + name);
   1863       if (result != null && result instanceof MethodDescriptor) {
   1864         return (MethodDescriptor)result;
   1865       } else {
   1866         return null;
   1867       }
   1868     }
   1869 
   1870     private final int index;
   1871     private ServiceDescriptorProto proto;
   1872     private final String fullName;
   1873     private final FileDescriptor file;
   1874     private MethodDescriptor[] methods;
   1875 
   1876     private ServiceDescriptor(final ServiceDescriptorProto proto,
   1877                               final FileDescriptor file,
   1878                               final int index)
   1879                        throws DescriptorValidationException {
   1880       this.index = index;
   1881       this.proto = proto;
   1882       fullName = computeFullName(file, null, proto.getName());
   1883       this.file = file;
   1884 
   1885       methods = new MethodDescriptor[proto.getMethodCount()];
   1886       for (int i = 0; i < proto.getMethodCount(); i++) {
   1887         methods[i] = new MethodDescriptor(
   1888           proto.getMethod(i), file, this, i);
   1889       }
   1890 
   1891       file.pool.addSymbol(this);
   1892     }
   1893 
   1894     private void crossLink() throws DescriptorValidationException {
   1895       for (final MethodDescriptor method : methods) {
   1896         method.crossLink();
   1897       }
   1898     }
   1899 
   1900     /** See {@link FileDescriptor#setProto}. */
   1901     private void setProto(final ServiceDescriptorProto proto) {
   1902       this.proto = proto;
   1903 
   1904       for (int i = 0; i < methods.length; i++) {
   1905         methods[i].setProto(proto.getMethod(i));
   1906       }
   1907     }
   1908   }
   1909 
   1910   // =================================================================
   1911 
   1912   /**
   1913    * Describes one method within a service type.
   1914    */
   1915   public static final class MethodDescriptor extends GenericDescriptor {
   1916     /**
   1917      * Get the index of this descriptor within its parent.
   1918      * * @see Descriptors.Descriptor#getIndex()
   1919      */
   1920     public int getIndex() { return index; }
   1921 
   1922     /** Convert the descriptor to its protocol message representation. */
   1923     @Override
   1924     public MethodDescriptorProto toProto() {
   1925       return proto;
   1926     }
   1927 
   1928     /** Get the method's unqualified name. */
   1929     @Override
   1930     public String getName() {
   1931       return proto.getName();
   1932     }
   1933 
   1934     /**
   1935      * Get the method's fully-qualified name.
   1936      * @see Descriptors.Descriptor#getFullName()
   1937      */
   1938     @Override
   1939     public String getFullName() {
   1940       return fullName;
   1941     }
   1942 
   1943     /** Get the {@link FileDescriptor} containing this descriptor. */
   1944     @Override
   1945     public FileDescriptor getFile() {
   1946       return file;
   1947     }
   1948 
   1949     /** Get the method's service type. */
   1950     public ServiceDescriptor getService() { return service; }
   1951 
   1952     /** Get the method's input type. */
   1953     public Descriptor getInputType() { return inputType; }
   1954 
   1955     /** Get the method's output type. */
   1956     public Descriptor getOutputType() { return outputType; }
   1957 
   1958     /**
   1959      * Get the {@code MethodOptions}, defined in {@code descriptor.proto}.
   1960      */
   1961     public MethodOptions getOptions() { return proto.getOptions(); }
   1962 
   1963     private final int index;
   1964     private MethodDescriptorProto proto;
   1965     private final String fullName;
   1966     private final FileDescriptor file;
   1967     private final ServiceDescriptor service;
   1968 
   1969     // Initialized during cross-linking.
   1970     private Descriptor inputType;
   1971     private Descriptor outputType;
   1972 
   1973     private MethodDescriptor(final MethodDescriptorProto proto,
   1974                              final FileDescriptor file,
   1975                              final ServiceDescriptor parent,
   1976                              final int index)
   1977                       throws DescriptorValidationException {
   1978       this.index = index;
   1979       this.proto = proto;
   1980       this.file = file;
   1981       service = parent;
   1982 
   1983       fullName = parent.getFullName() + '.' + proto.getName();
   1984 
   1985       file.pool.addSymbol(this);
   1986     }
   1987 
   1988     private void crossLink() throws DescriptorValidationException {
   1989       final GenericDescriptor input =
   1990         file.pool.lookupSymbol(proto.getInputType(), this,
   1991             DescriptorPool.SearchFilter.TYPES_ONLY);
   1992       if (!(input instanceof Descriptor)) {
   1993         throw new DescriptorValidationException(this,
   1994             '\"' + proto.getInputType() + "\" is not a message type.");
   1995       }
   1996       inputType = (Descriptor)input;
   1997 
   1998       final GenericDescriptor output =
   1999         file.pool.lookupSymbol(proto.getOutputType(), this,
   2000             DescriptorPool.SearchFilter.TYPES_ONLY);
   2001       if (!(output instanceof Descriptor)) {
   2002         throw new DescriptorValidationException(this,
   2003             '\"' + proto.getOutputType() + "\" is not a message type.");
   2004       }
   2005       outputType = (Descriptor)output;
   2006     }
   2007 
   2008     /** See {@link FileDescriptor#setProto}. */
   2009     private void setProto(final MethodDescriptorProto proto) {
   2010       this.proto = proto;
   2011     }
   2012   }
   2013 
   2014   // =================================================================
   2015 
   2016   private static String computeFullName(final FileDescriptor file,
   2017                                         final Descriptor parent,
   2018                                         final String name) {
   2019     if (parent != null) {
   2020       return parent.getFullName() + '.' + name;
   2021     } else if (file.getPackage().length() > 0) {
   2022       return file.getPackage() + '.' + name;
   2023     } else {
   2024       return name;
   2025     }
   2026   }
   2027 
   2028   // =================================================================
   2029 
   2030   /**
   2031    * All descriptors implement this to make it easier to implement tools like
   2032    * {@code DescriptorPool}.<p>
   2033    *
   2034    * This class is public so that the methods it exposes can be called from
   2035    * outside of this package. However, it should only be subclassed from
   2036    * nested classes of Descriptors.
   2037    */
   2038   public abstract static class GenericDescriptor {
   2039     public abstract Message toProto();
   2040     public abstract String getName();
   2041     public abstract String getFullName();
   2042     public abstract FileDescriptor getFile();
   2043   }
   2044 
   2045   /**
   2046    * Thrown when building descriptors fails because the source DescriptorProtos
   2047    * are not valid.
   2048    */
   2049   public static class DescriptorValidationException extends Exception {
   2050     private static final long serialVersionUID = 5750205775490483148L;
   2051 
   2052     /** Gets the full name of the descriptor where the error occurred. */
   2053     public String getProblemSymbolName() { return name; }
   2054 
   2055     /**
   2056      * Gets the protocol message representation of the invalid descriptor.
   2057      */
   2058     public Message getProblemProto() { return proto; }
   2059 
   2060     /**
   2061      * Gets a human-readable description of the error.
   2062      */
   2063     public String getDescription() { return description; }
   2064 
   2065     private final String name;
   2066     private final Message proto;
   2067     private final String description;
   2068 
   2069     private DescriptorValidationException(
   2070         final GenericDescriptor problemDescriptor,
   2071         final String description) {
   2072       super(problemDescriptor.getFullName() + ": " + description);
   2073 
   2074       // Note that problemDescriptor may be partially uninitialized, so we
   2075       // don't want to expose it directly to the user.  So, we only provide
   2076       // the name and the original proto.
   2077       name = problemDescriptor.getFullName();
   2078       proto = problemDescriptor.toProto();
   2079       this.description = description;
   2080     }
   2081 
   2082     private DescriptorValidationException(
   2083         final GenericDescriptor problemDescriptor,
   2084         final String description,
   2085         final Throwable cause) {
   2086       this(problemDescriptor, description);
   2087       initCause(cause);
   2088     }
   2089 
   2090     private DescriptorValidationException(
   2091         final FileDescriptor problemDescriptor,
   2092         final String description) {
   2093       super(problemDescriptor.getName() + ": " + description);
   2094 
   2095       // Note that problemDescriptor may be partially uninitialized, so we
   2096       // don't want to expose it directly to the user.  So, we only provide
   2097       // the name and the original proto.
   2098       name = problemDescriptor.getName();
   2099       proto = problemDescriptor.toProto();
   2100       this.description = description;
   2101     }
   2102   }
   2103 
   2104   // =================================================================
   2105 
   2106   /**
   2107    * A private helper class which contains lookup tables containing all the
   2108    * descriptors defined in a particular file.
   2109    */
   2110   private static final class DescriptorPool {
   2111 
   2112     /** Defines what subclass of descriptors to search in the descriptor pool.
   2113      */
   2114     enum SearchFilter {
   2115       TYPES_ONLY, AGGREGATES_ONLY, ALL_SYMBOLS
   2116     }
   2117 
   2118     DescriptorPool(final FileDescriptor[] dependencies,
   2119         boolean allowUnknownDependencies) {
   2120       this.dependencies = new HashSet<FileDescriptor>();
   2121       this.allowUnknownDependencies = allowUnknownDependencies;
   2122 
   2123       for (int i = 0; i < dependencies.length; i++) {
   2124         this.dependencies.add(dependencies[i]);
   2125         importPublicDependencies(dependencies[i]);
   2126       }
   2127 
   2128       for (final FileDescriptor dependency : this.dependencies) {
   2129         try {
   2130           addPackage(dependency.getPackage(), dependency);
   2131         } catch (DescriptorValidationException e) {
   2132           // Can't happen, because addPackage() only fails when the name
   2133           // conflicts with a non-package, but we have not yet added any
   2134           // non-packages at this point.
   2135           assert false;
   2136         }
   2137       }
   2138     }
   2139 
   2140     /** Find and put public dependencies of the file into dependencies set.*/
   2141     private void importPublicDependencies(final FileDescriptor file) {
   2142       for (FileDescriptor dependency : file.getPublicDependencies()) {
   2143         if (dependencies.add(dependency)) {
   2144           importPublicDependencies(dependency);
   2145         }
   2146       }
   2147     }
   2148 
   2149     private final Set<FileDescriptor> dependencies;
   2150     private boolean allowUnknownDependencies;
   2151 
   2152     private final Map<String, GenericDescriptor> descriptorsByName =
   2153       new HashMap<String, GenericDescriptor>();
   2154     private final Map<DescriptorIntPair, FieldDescriptor> fieldsByNumber =
   2155       new HashMap<DescriptorIntPair, FieldDescriptor>();
   2156     private final Map<DescriptorIntPair, EnumValueDescriptor> enumValuesByNumber
   2157         = new HashMap<DescriptorIntPair, EnumValueDescriptor>();
   2158 
   2159     /** Find a generic descriptor by fully-qualified name. */
   2160     GenericDescriptor findSymbol(final String fullName) {
   2161       return findSymbol(fullName, SearchFilter.ALL_SYMBOLS);
   2162     }
   2163 
   2164     /** Find a descriptor by fully-qualified name and given option to only
   2165      * search valid field type descriptors.
   2166      */
   2167     GenericDescriptor findSymbol(final String fullName,
   2168                                  final SearchFilter filter) {
   2169       GenericDescriptor result = descriptorsByName.get(fullName);
   2170       if (result != null) {
   2171         if ((filter==SearchFilter.ALL_SYMBOLS) ||
   2172             ((filter==SearchFilter.TYPES_ONLY) && isType(result)) ||
   2173             ((filter==SearchFilter.AGGREGATES_ONLY) && isAggregate(result))) {
   2174           return result;
   2175         }
   2176       }
   2177 
   2178       for (final FileDescriptor dependency : dependencies) {
   2179         result = dependency.pool.descriptorsByName.get(fullName);
   2180         if (result != null) {
   2181           if ((filter==SearchFilter.ALL_SYMBOLS) ||
   2182               ((filter==SearchFilter.TYPES_ONLY) && isType(result)) ||
   2183               ((filter==SearchFilter.AGGREGATES_ONLY) && isAggregate(result))) {
   2184             return result;
   2185           }
   2186         }
   2187       }
   2188 
   2189       return null;
   2190     }
   2191 
   2192     /** Checks if the descriptor is a valid type for a message field. */
   2193     boolean isType(GenericDescriptor descriptor) {
   2194       return (descriptor instanceof Descriptor) ||
   2195         (descriptor instanceof EnumDescriptor);
   2196     }
   2197 
   2198     /** Checks if the descriptor is a valid namespace type. */
   2199     boolean isAggregate(GenericDescriptor descriptor) {
   2200       return (descriptor instanceof Descriptor) ||
   2201         (descriptor instanceof EnumDescriptor) ||
   2202         (descriptor instanceof PackageDescriptor) ||
   2203         (descriptor instanceof ServiceDescriptor);
   2204     }
   2205 
   2206     /**
   2207      * Look up a type descriptor by name, relative to some other descriptor.
   2208      * The name may be fully-qualified (with a leading '.'),
   2209      * partially-qualified, or unqualified.  C++-like name lookup semantics
   2210      * are used to search for the matching descriptor.
   2211      */
   2212     GenericDescriptor lookupSymbol(final String name,
   2213                                    final GenericDescriptor relativeTo,
   2214                                    final DescriptorPool.SearchFilter filter)
   2215                             throws DescriptorValidationException {
   2216       // TODO(kenton):  This could be optimized in a number of ways.
   2217 
   2218       GenericDescriptor result;
   2219       String fullname;
   2220       if (name.startsWith(".")) {
   2221         // Fully-qualified name.
   2222         fullname = name.substring(1);
   2223         result = findSymbol(fullname, filter);
   2224       } else {
   2225         // If "name" is a compound identifier, we want to search for the
   2226         // first component of it, then search within it for the rest.
   2227         // If name is something like "Foo.Bar.baz", and symbols named "Foo" are
   2228         // defined in multiple parent scopes, we only want to find "Bar.baz" in
   2229         // the innermost one.  E.g., the following should produce an error:
   2230         //   message Bar { message Baz {} }
   2231         //   message Foo {
   2232         //     message Bar {
   2233         //     }
   2234         //     optional Bar.Baz baz = 1;
   2235         //   }
   2236         // So, we look for just "Foo" first, then look for "Bar.baz" within it
   2237         // if found.
   2238         final int firstPartLength = name.indexOf('.');
   2239         final String firstPart;
   2240         if (firstPartLength == -1) {
   2241           firstPart = name;
   2242         } else {
   2243           firstPart = name.substring(0, firstPartLength);
   2244         }
   2245 
   2246         // We will search each parent scope of "relativeTo" looking for the
   2247         // symbol.
   2248         final StringBuilder scopeToTry =
   2249             new StringBuilder(relativeTo.getFullName());
   2250 
   2251         while (true) {
   2252           // Chop off the last component of the scope.
   2253           final int dotpos = scopeToTry.lastIndexOf(".");
   2254           if (dotpos == -1) {
   2255             fullname = name;
   2256             result = findSymbol(name, filter);
   2257             break;
   2258           } else {
   2259             scopeToTry.setLength(dotpos + 1);
   2260 
   2261             // Append firstPart and try to find
   2262             scopeToTry.append(firstPart);
   2263             result = findSymbol(scopeToTry.toString(),
   2264                 DescriptorPool.SearchFilter.AGGREGATES_ONLY);
   2265 
   2266             if (result != null) {
   2267               if (firstPartLength != -1) {
   2268                 // We only found the first part of the symbol.  Now look for
   2269                 // the whole thing.  If this fails, we *don't* want to keep
   2270                 // searching parent scopes.
   2271                 scopeToTry.setLength(dotpos + 1);
   2272                 scopeToTry.append(name);
   2273                 result = findSymbol(scopeToTry.toString(), filter);
   2274               }
   2275               fullname = scopeToTry.toString();
   2276               break;
   2277             }
   2278 
   2279             // Not found.  Remove the name so we can try again.
   2280             scopeToTry.setLength(dotpos);
   2281           }
   2282         }
   2283       }
   2284 
   2285       if (result == null) {
   2286         if (allowUnknownDependencies && filter == SearchFilter.TYPES_ONLY) {
   2287           logger.warning("The descriptor for message type \"" + name +
   2288               "\" can not be found and a placeholder is created for it");
   2289           // We create a dummy message descriptor here regardless of the
   2290           // expected type. If the type should be message, this dummy
   2291           // descriptor will work well and if the type should be enum, a
   2292           // DescriptorValidationException will be thrown latter. In either
   2293           // case, the code works as expected: we allow unknown message types
   2294           // but not unknwon enum types.
   2295           result = new Descriptor(fullname);
   2296           // Add the placeholder file as a dependency so we can find the
   2297           // placeholder symbol when resolving other references.
   2298           this.dependencies.add(result.getFile());
   2299           return result;
   2300         } else {
   2301           throw new DescriptorValidationException(relativeTo,
   2302               '\"' + name + "\" is not defined.");
   2303         }
   2304       } else {
   2305         return result;
   2306       }
   2307     }
   2308 
   2309     /**
   2310      * Adds a symbol to the symbol table.  If a symbol with the same name
   2311      * already exists, throws an error.
   2312      */
   2313     void addSymbol(final GenericDescriptor descriptor)
   2314             throws DescriptorValidationException {
   2315       validateSymbolName(descriptor);
   2316 
   2317       final String fullName = descriptor.getFullName();
   2318       final int dotpos = fullName.lastIndexOf('.');
   2319 
   2320       final GenericDescriptor old = descriptorsByName.put(fullName, descriptor);
   2321       if (old != null) {
   2322         descriptorsByName.put(fullName, old);
   2323 
   2324         if (descriptor.getFile() == old.getFile()) {
   2325           if (dotpos == -1) {
   2326             throw new DescriptorValidationException(descriptor,
   2327                 '\"' + fullName + "\" is already defined.");
   2328           } else {
   2329             throw new DescriptorValidationException(descriptor,
   2330                 '\"' + fullName.substring(dotpos + 1) +
   2331               "\" is already defined in \"" +
   2332               fullName.substring(0, dotpos) + "\".");
   2333           }
   2334         } else {
   2335           throw new DescriptorValidationException(descriptor,
   2336               '\"' + fullName + "\" is already defined in file \"" +
   2337             old.getFile().getName() + "\".");
   2338         }
   2339       }
   2340     }
   2341 
   2342     /**
   2343      * Represents a package in the symbol table.  We use PackageDescriptors
   2344      * just as placeholders so that someone cannot define, say, a message type
   2345      * that has the same name as an existing package.
   2346      */
   2347     private static final class PackageDescriptor extends GenericDescriptor {
   2348       @Override
   2349       public Message toProto() {
   2350         return file.toProto();
   2351       }
   2352       @Override
   2353       public String getName() {
   2354         return name;
   2355       }
   2356       @Override
   2357       public String getFullName() {
   2358         return fullName;
   2359       }
   2360       @Override
   2361       public FileDescriptor getFile() {
   2362         return file;
   2363       }
   2364 
   2365       PackageDescriptor(final String name, final String fullName,
   2366                         final FileDescriptor file) {
   2367         this.file = file;
   2368         this.fullName = fullName;
   2369         this.name = name;
   2370       }
   2371 
   2372       private final String name;
   2373       private final String fullName;
   2374       private final FileDescriptor file;
   2375     }
   2376 
   2377     /**
   2378      * Adds a package to the symbol tables.  If a package by the same name
   2379      * already exists, that is fine, but if some other kind of symbol exists
   2380      * under the same name, an exception is thrown.  If the package has
   2381      * multiple components, this also adds the parent package(s).
   2382      */
   2383     void addPackage(final String fullName, final FileDescriptor file)
   2384              throws DescriptorValidationException {
   2385       final int dotpos = fullName.lastIndexOf('.');
   2386       final String name;
   2387       if (dotpos == -1) {
   2388         name = fullName;
   2389       } else {
   2390         addPackage(fullName.substring(0, dotpos), file);
   2391         name = fullName.substring(dotpos + 1);
   2392       }
   2393 
   2394       final GenericDescriptor old =
   2395         descriptorsByName.put(fullName,
   2396           new PackageDescriptor(name, fullName, file));
   2397       if (old != null) {
   2398         descriptorsByName.put(fullName, old);
   2399         if (!(old instanceof PackageDescriptor)) {
   2400           throw new DescriptorValidationException(file,
   2401               '\"' + name + "\" is already defined (as something other than a "
   2402               + "package) in file \"" + old.getFile().getName() + "\".");
   2403         }
   2404       }
   2405     }
   2406 
   2407     /** A (GenericDescriptor, int) pair, used as a map key. */
   2408     private static final class DescriptorIntPair {
   2409       private final GenericDescriptor descriptor;
   2410       private final int number;
   2411 
   2412       DescriptorIntPair(final GenericDescriptor descriptor, final int number) {
   2413         this.descriptor = descriptor;
   2414         this.number = number;
   2415       }
   2416 
   2417       @Override
   2418       public int hashCode() {
   2419         return descriptor.hashCode() * ((1 << 16) - 1) + number;
   2420       }
   2421       @Override
   2422       public boolean equals(final Object obj) {
   2423         if (!(obj instanceof DescriptorIntPair)) {
   2424           return false;
   2425         }
   2426         final DescriptorIntPair other = (DescriptorIntPair)obj;
   2427         return descriptor == other.descriptor && number == other.number;
   2428       }
   2429     }
   2430 
   2431     /**
   2432      * Adds a field to the fieldsByNumber table.  Throws an exception if a
   2433      * field with the same containing type and number already exists.
   2434      */
   2435     void addFieldByNumber(final FieldDescriptor field)
   2436                    throws DescriptorValidationException {
   2437       final DescriptorIntPair key =
   2438         new DescriptorIntPair(field.getContainingType(), field.getNumber());
   2439       final FieldDescriptor old = fieldsByNumber.put(key, field);
   2440       if (old != null) {
   2441         fieldsByNumber.put(key, old);
   2442         throw new DescriptorValidationException(field,
   2443           "Field number " + field.getNumber() +
   2444           " has already been used in \"" +
   2445           field.getContainingType().getFullName() +
   2446           "\" by field \"" + old.getName() + "\".");
   2447       }
   2448     }
   2449 
   2450     /**
   2451      * Adds an enum value to the enumValuesByNumber table.  If an enum value
   2452      * with the same type and number already exists, does nothing.  (This is
   2453      * allowed; the first value define with the number takes precedence.)
   2454      */
   2455     void addEnumValueByNumber(final EnumValueDescriptor value) {
   2456       final DescriptorIntPair key =
   2457         new DescriptorIntPair(value.getType(), value.getNumber());
   2458       final EnumValueDescriptor old = enumValuesByNumber.put(key, value);
   2459       if (old != null) {
   2460         enumValuesByNumber.put(key, old);
   2461         // Not an error:  Multiple enum values may have the same number, but
   2462         // we only want the first one in the map.
   2463       }
   2464     }
   2465 
   2466     /**
   2467      * Verifies that the descriptor's name is valid (i.e. it contains only
   2468      * letters, digits, and underscores, and does not start with a digit).
   2469      */
   2470     static void validateSymbolName(final GenericDescriptor descriptor)
   2471                                    throws DescriptorValidationException {
   2472       final String name = descriptor.getName();
   2473       if (name.length() == 0) {
   2474         throw new DescriptorValidationException(descriptor, "Missing name.");
   2475       } else {
   2476         boolean valid = true;
   2477         for (int i = 0; i < name.length(); i++) {
   2478           final char c = name.charAt(i);
   2479           // Non-ASCII characters are not valid in protobuf identifiers, even
   2480           // if they are letters or digits.
   2481           if (c >= 128) {
   2482             valid = false;
   2483           }
   2484           // First character must be letter or _.  Subsequent characters may
   2485           // be letters, numbers, or digits.
   2486           if (Character.isLetter(c) || c == '_' ||
   2487               (Character.isDigit(c) && i > 0)) {
   2488             // Valid
   2489           } else {
   2490             valid = false;
   2491           }
   2492         }
   2493         if (!valid) {
   2494           throw new DescriptorValidationException(descriptor,
   2495               '\"' + name + "\" is not a valid identifier.");
   2496         }
   2497       }
   2498     }
   2499   }
   2500 
   2501   /** Describes an oneof of a message type. */
   2502   public static final class OneofDescriptor {
   2503     /** Get the index of this descriptor within its parent. */
   2504     public int getIndex() { return index; }
   2505 
   2506     public String getName() { return proto.getName(); }
   2507 
   2508     public FileDescriptor getFile() { return file; }
   2509 
   2510     public String getFullName() { return fullName; }
   2511 
   2512     public Descriptor getContainingType() { return containingType; }
   2513 
   2514     public int getFieldCount() { return fieldCount; }
   2515 
   2516     /** Get a list of this message type's fields. */
   2517     public List<FieldDescriptor> getFields() {
   2518       return Collections.unmodifiableList(Arrays.asList(fields));
   2519     }
   2520 
   2521     public FieldDescriptor getField(int index) {
   2522       return fields[index];
   2523     }
   2524 
   2525     private OneofDescriptor(final OneofDescriptorProto proto,
   2526                             final FileDescriptor file,
   2527                             final Descriptor parent,
   2528                             final int index)
   2529                      throws DescriptorValidationException {
   2530       this.proto = proto;
   2531       fullName = computeFullName(file, parent, proto.getName());
   2532       this.file = file;
   2533       this.index = index;
   2534 
   2535       containingType = parent;
   2536       fieldCount = 0;
   2537     }
   2538 
   2539     private final int index;
   2540     private OneofDescriptorProto proto;
   2541     private final String fullName;
   2542     private final FileDescriptor file;
   2543 
   2544     private Descriptor containingType;
   2545     private int fieldCount;
   2546     private FieldDescriptor[] fields;
   2547   }
   2548 }
   2549