PageRenderTime 97ms CodeModel.GetById 19ms app.highlight 65ms RepoModel.GetById 1ms app.codeStats 1ms

/thirdparty/breakpad/third_party/protobuf/protobuf/java/src/main/java/com/google/protobuf/Descriptors.java

http://github.com/tomahawk-player/tomahawk
Java | 1814 lines | 1100 code | 239 blank | 475 comment | 213 complexity | 333958e765c10ab41881d08554caaf04 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1// Protocol Buffers - Google's data interchange format
   2// Copyright 2008 Google Inc.  All rights reserved.
   3// http://code.google.com/p/protobuf/
   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
  31package com.google.protobuf;
  32
  33import com.google.protobuf.DescriptorProtos.*;
  34
  35import java.util.Arrays;
  36import java.util.Collections;
  37import java.util.HashMap;
  38import java.util.List;
  39import java.util.Map;
  40import java.io.UnsupportedEncodingException;
  41
  42/**
  43 * Contains a collection of classes which describe protocol message types.
  44 *
  45 * Every message type has a {@link Descriptor}, which lists all
  46 * its fields and other information about a type.  You can get a message
  47 * type's descriptor by calling {@code MessageType.getDescriptor()}, or
  48 * (given a message object of the type) {@code message.getDescriptorForType()}.
  49 * Furthermore, each message is associated with a {@link FileDescriptor} for
  50 * a relevant {@code .proto} file. You can obtain it by calling
  51 * {@code Descriptor.getFile()}. A {@link FileDescriptor} contains descriptors
  52 * for all the messages defined in that file, and file descriptors for all the
  53 * imported {@code .proto} files.
  54 *
  55 * Descriptors are built from DescriptorProtos, as defined in
  56 * {@code google/protobuf/descriptor.proto}.
  57 *
  58 * @author kenton@google.com Kenton Varda
  59 */
  60public final class Descriptors {
  61  /**
  62   * Describes a {@code .proto} file, including everything defined within.
  63   * That includes, in particular, descriptors for all the messages and
  64   * file descriptors for all other imported {@code .proto} files
  65   * (dependencies).
  66   */
  67  public static final class FileDescriptor {
  68    /** Convert the descriptor to its protocol message representation. */
  69    public FileDescriptorProto toProto() { return proto; }
  70
  71    /** Get the file name. */
  72    public String getName() { return proto.getName(); }
  73
  74    /**
  75     * Get the proto package name.  This is the package name given by the
  76     * {@code package} statement in the {@code .proto} file, which differs
  77     * from the Java package.
  78     */
  79    public String getPackage() { return proto.getPackage(); }
  80
  81    /** Get the {@code FileOptions}, defined in {@code descriptor.proto}. */
  82    public FileOptions getOptions() { return proto.getOptions(); }
  83
  84    /** Get a list of top-level message types declared in this file. */
  85    public List<Descriptor> getMessageTypes() {
  86      return Collections.unmodifiableList(Arrays.asList(messageTypes));
  87    }
  88
  89    /** Get a list of top-level enum types declared in this file. */
  90    public List<EnumDescriptor> getEnumTypes() {
  91      return Collections.unmodifiableList(Arrays.asList(enumTypes));
  92    }
  93
  94    /** Get a list of top-level services declared in this file. */
  95    public List<ServiceDescriptor> getServices() {
  96      return Collections.unmodifiableList(Arrays.asList(services));
  97    }
  98
  99    /** Get a list of top-level extensions declared in this file. */
 100    public List<FieldDescriptor> getExtensions() {
 101      return Collections.unmodifiableList(Arrays.asList(extensions));
 102    }
 103
 104    /** Get a list of this file's dependencies (imports). */
 105    public List<FileDescriptor> getDependencies() {
 106      return Collections.unmodifiableList(Arrays.asList(dependencies));
 107    }
 108
 109    /**
 110     * Find a message type in the file by name.  Does not find nested types.
 111     *
 112     * @param name The unqualified type name to look for.
 113     * @return The message type's descriptor, or {@code null} if not found.
 114     */
 115    public Descriptor findMessageTypeByName(String name) {
 116      // Don't allow looking up nested types.  This will make optimization
 117      // easier later.
 118      if (name.indexOf('.') != -1) {
 119        return null;
 120      }
 121      if (getPackage().length() > 0) {
 122        name = getPackage() + '.' + name;
 123      }
 124      final GenericDescriptor result = pool.findSymbol(name);
 125      if (result != null && result instanceof Descriptor &&
 126          result.getFile() == this) {
 127        return (Descriptor)result;
 128      } else {
 129        return null;
 130      }
 131    }
 132
 133    /**
 134     * Find an enum type in the file by name.  Does not find nested types.
 135     *
 136     * @param name The unqualified type name to look for.
 137     * @return The enum type's descriptor, or {@code null} if not found.
 138     */
 139    public EnumDescriptor findEnumTypeByName(String name) {
 140      // Don't allow looking up nested types.  This will make optimization
 141      // easier later.
 142      if (name.indexOf('.') != -1) {
 143        return null;
 144      }
 145      if (getPackage().length() > 0) {
 146        name = getPackage() + '.' + name;
 147      }
 148      final GenericDescriptor result = pool.findSymbol(name);
 149      if (result != null && result instanceof EnumDescriptor &&
 150          result.getFile() == this) {
 151        return (EnumDescriptor)result;
 152      } else {
 153        return null;
 154      }
 155    }
 156
 157    /**
 158     * Find a service type in the file by name.
 159     *
 160     * @param name The unqualified type name to look for.
 161     * @return The service type's descriptor, or {@code null} if not found.
 162     */
 163    public ServiceDescriptor findServiceByName(String name) {
 164      // Don't allow looking up nested types.  This will make optimization
 165      // easier later.
 166      if (name.indexOf('.') != -1) {
 167        return null;
 168      }
 169      if (getPackage().length() > 0) {
 170        name = getPackage() + '.' + name;
 171      }
 172      final GenericDescriptor result = pool.findSymbol(name);
 173      if (result != null && result instanceof ServiceDescriptor &&
 174          result.getFile() == this) {
 175        return (ServiceDescriptor)result;
 176      } else {
 177        return null;
 178      }
 179    }
 180
 181    /**
 182     * Find an extension in the file by name.  Does not find extensions nested
 183     * inside message types.
 184     *
 185     * @param name The unqualified extension name to look for.
 186     * @return The extension's descriptor, or {@code null} if not found.
 187     */
 188    public FieldDescriptor findExtensionByName(String name) {
 189      if (name.indexOf('.') != -1) {
 190        return null;
 191      }
 192      if (getPackage().length() > 0) {
 193        name = getPackage() + '.' + name;
 194      }
 195      final GenericDescriptor result = pool.findSymbol(name);
 196      if (result != null && result instanceof FieldDescriptor &&
 197          result.getFile() == this) {
 198        return (FieldDescriptor)result;
 199      } else {
 200        return null;
 201      }
 202    }
 203
 204    /**
 205     * Construct a {@code FileDescriptor}.
 206     *
 207     * @param proto The protocol message form of the FileDescriptor.
 208     * @param dependencies {@code FileDescriptor}s corresponding to all of
 209     *                     the file's dependencies, in the exact order listed
 210     *                     in {@code proto}.
 211     * @throws DescriptorValidationException {@code proto} is not a valid
 212     *           descriptor.  This can occur for a number of reasons, e.g.
 213     *           because a field has an undefined type or because two messages
 214     *           were defined with the same name.
 215     */
 216    public static FileDescriptor buildFrom(final FileDescriptorProto proto,
 217                                           final FileDescriptor[] dependencies)
 218                                    throws DescriptorValidationException {
 219      // Building decsriptors involves two steps:  translating and linking.
 220      // In the translation step (implemented by FileDescriptor's
 221      // constructor), we build an object tree mirroring the
 222      // FileDescriptorProto's tree and put all of the descriptors into the
 223      // DescriptorPool's lookup tables.  In the linking step, we look up all
 224      // type references in the DescriptorPool, so that, for example, a
 225      // FieldDescriptor for an embedded message contains a pointer directly
 226      // to the Descriptor for that message's type.  We also detect undefined
 227      // types in the linking step.
 228      final DescriptorPool pool = new DescriptorPool(dependencies);
 229      final FileDescriptor result =
 230          new FileDescriptor(proto, dependencies, pool);
 231
 232      if (dependencies.length != proto.getDependencyCount()) {
 233        throw new DescriptorValidationException(result,
 234          "Dependencies passed to FileDescriptor.buildFrom() don't match " +
 235          "those listed in the FileDescriptorProto.");
 236      }
 237      for (int i = 0; i < proto.getDependencyCount(); i++) {
 238        if (!dependencies[i].getName().equals(proto.getDependency(i))) {
 239          throw new DescriptorValidationException(result,
 240            "Dependencies passed to FileDescriptor.buildFrom() don't match " +
 241            "those listed in the FileDescriptorProto.");
 242        }
 243      }
 244
 245      result.crossLink();
 246      return result;
 247    }
 248
 249    /**
 250     * This method is to be called by generated code only.  It is equivalent
 251     * to {@code buildFrom} except that the {@code FileDescriptorProto} is
 252     * encoded in protocol buffer wire format.
 253     */
 254    public static void internalBuildGeneratedFileFrom(
 255        final String[] descriptorDataParts,
 256        final FileDescriptor[] dependencies,
 257        final InternalDescriptorAssigner descriptorAssigner) {
 258      // Hack:  We can't embed a raw byte array inside generated Java code
 259      //   (at least, not efficiently), but we can embed Strings.  So, the
 260      //   protocol compiler embeds the FileDescriptorProto as a giant
 261      //   string literal which is passed to this function to construct the
 262      //   file's FileDescriptor.  The string literal contains only 8-bit
 263      //   characters, each one representing a byte of the FileDescriptorProto's
 264      //   serialized form.  So, if we convert it to bytes in ISO-8859-1, we
 265      //   should get the original bytes that we want.
 266
 267      // descriptorData may contain multiple strings in order to get around the
 268      // Java 64k string literal limit.
 269      StringBuilder descriptorData = new StringBuilder();
 270      for (String part : descriptorDataParts) {
 271        descriptorData.append(part);
 272      }
 273
 274      final byte[] descriptorBytes;
 275      try {
 276        descriptorBytes = descriptorData.toString().getBytes("ISO-8859-1");
 277      } catch (UnsupportedEncodingException e) {
 278        throw new RuntimeException(
 279          "Standard encoding ISO-8859-1 not supported by JVM.", e);
 280      }
 281
 282      FileDescriptorProto proto;
 283      try {
 284        proto = FileDescriptorProto.parseFrom(descriptorBytes);
 285      } catch (InvalidProtocolBufferException e) {
 286        throw new IllegalArgumentException(
 287          "Failed to parse protocol buffer descriptor for generated code.", e);
 288      }
 289
 290      final FileDescriptor result;
 291      try {
 292        result = buildFrom(proto, dependencies);
 293      } catch (DescriptorValidationException e) {
 294        throw new IllegalArgumentException(
 295          "Invalid embedded descriptor for \"" + proto.getName() + "\".", e);
 296      }
 297
 298      final ExtensionRegistry registry =
 299          descriptorAssigner.assignDescriptors(result);
 300
 301      if (registry != null) {
 302        // We must re-parse the proto using the registry.
 303        try {
 304          proto = FileDescriptorProto.parseFrom(descriptorBytes, registry);
 305        } catch (InvalidProtocolBufferException e) {
 306          throw new IllegalArgumentException(
 307            "Failed to parse protocol buffer descriptor for generated code.",
 308            e);
 309        }
 310
 311        result.setProto(proto);
 312      }
 313    }
 314
 315    /**
 316     * This class should be used by generated code only.  When calling
 317     * {@link FileDescriptor#internalBuildGeneratedFileFrom}, the caller
 318     * provides a callback implementing this interface.  The callback is called
 319     * after the FileDescriptor has been constructed, in order to assign all
 320     * the global variales defined in the generated code which point at parts
 321     * of the FileDescriptor.  The callback returns an ExtensionRegistry which
 322     * contains any extensions which might be used in the descriptor -- that
 323     * is, extensions of the various "Options" messages defined in
 324     * descriptor.proto.  The callback may also return null to indicate that
 325     * no extensions are used in the decsriptor.
 326     */
 327    public interface InternalDescriptorAssigner {
 328      ExtensionRegistry assignDescriptors(FileDescriptor root);
 329    }
 330
 331    private FileDescriptorProto proto;
 332    private final Descriptor[] messageTypes;
 333    private final EnumDescriptor[] enumTypes;
 334    private final ServiceDescriptor[] services;
 335    private final FieldDescriptor[] extensions;
 336    private final FileDescriptor[] dependencies;
 337    private final DescriptorPool pool;
 338
 339    private FileDescriptor(final FileDescriptorProto proto,
 340                           final FileDescriptor[] dependencies,
 341                           final DescriptorPool pool)
 342                    throws DescriptorValidationException {
 343      this.pool = pool;
 344      this.proto = proto;
 345      this.dependencies = dependencies.clone();
 346
 347      pool.addPackage(getPackage(), this);
 348
 349      messageTypes = new Descriptor[proto.getMessageTypeCount()];
 350      for (int i = 0; i < proto.getMessageTypeCount(); i++) {
 351        messageTypes[i] =
 352          new Descriptor(proto.getMessageType(i), this, null, i);
 353      }
 354
 355      enumTypes = new EnumDescriptor[proto.getEnumTypeCount()];
 356      for (int i = 0; i < proto.getEnumTypeCount(); i++) {
 357        enumTypes[i] = new EnumDescriptor(proto.getEnumType(i), this, null, i);
 358      }
 359
 360      services = new ServiceDescriptor[proto.getServiceCount()];
 361      for (int i = 0; i < proto.getServiceCount(); i++) {
 362        services[i] = new ServiceDescriptor(proto.getService(i), this, i);
 363      }
 364
 365      extensions = new FieldDescriptor[proto.getExtensionCount()];
 366      for (int i = 0; i < proto.getExtensionCount(); i++) {
 367        extensions[i] = new FieldDescriptor(
 368          proto.getExtension(i), this, null, i, true);
 369      }
 370    }
 371
 372    /** Look up and cross-link all field types, etc. */
 373    private void crossLink() throws DescriptorValidationException {
 374      for (final Descriptor messageType : messageTypes) {
 375        messageType.crossLink();
 376      }
 377
 378      for (final ServiceDescriptor service : services) {
 379        service.crossLink();
 380      }
 381
 382      for (final FieldDescriptor extension : extensions) {
 383        extension.crossLink();
 384      }
 385    }
 386
 387    /**
 388     * Replace our {@link FileDescriptorProto} with the given one, which is
 389     * identical except that it might contain extensions that weren't present
 390     * in the original.  This method is needed for bootstrapping when a file
 391     * defines custom options.  The options may be defined in the file itself,
 392     * so we can't actually parse them until we've constructed the descriptors,
 393     * but to construct the decsriptors we have to have parsed the descriptor
 394     * protos.  So, we have to parse the descriptor protos a second time after
 395     * constructing the descriptors.
 396     */
 397    private void setProto(final FileDescriptorProto proto) {
 398      this.proto = proto;
 399
 400      for (int i = 0; i < messageTypes.length; i++) {
 401        messageTypes[i].setProto(proto.getMessageType(i));
 402      }
 403
 404      for (int i = 0; i < enumTypes.length; i++) {
 405        enumTypes[i].setProto(proto.getEnumType(i));
 406      }
 407
 408      for (int i = 0; i < services.length; i++) {
 409        services[i].setProto(proto.getService(i));
 410      }
 411
 412      for (int i = 0; i < extensions.length; i++) {
 413        extensions[i].setProto(proto.getExtension(i));
 414      }
 415    }
 416  }
 417
 418  // =================================================================
 419
 420  /** Describes a message type. */
 421  public static final class Descriptor implements GenericDescriptor {
 422    /**
 423     * Get the index of this descriptor within its parent.  In other words,
 424     * given a {@link FileDescriptor} {@code file}, the following is true:
 425     * <pre>
 426     *   for all i in [0, file.getMessageTypeCount()):
 427     *     file.getMessageType(i).getIndex() == i
 428     * </pre>
 429     * Similarly, for a {@link Descriptor} {@code messageType}:
 430     * <pre>
 431     *   for all i in [0, messageType.getNestedTypeCount()):
 432     *     messageType.getNestedType(i).getIndex() == i
 433     * </pre>
 434     */
 435    public int getIndex() { return index; }
 436
 437    /** Convert the descriptor to its protocol message representation. */
 438    public DescriptorProto toProto() { return proto; }
 439
 440    /** Get the type's unqualified name. */
 441    public String getName() { return proto.getName(); }
 442
 443    /**
 444     * Get the type's fully-qualified name, within the proto language's
 445     * namespace.  This differs from the Java name.  For example, given this
 446     * {@code .proto}:
 447     * <pre>
 448     *   package foo.bar;
 449     *   option java_package = "com.example.protos"
 450     *   message Baz {}
 451     * </pre>
 452     * {@code Baz}'s full name is "foo.bar.Baz".
 453     */
 454    public String getFullName() { return fullName; }
 455
 456    /** Get the {@link FileDescriptor} containing this descriptor. */
 457    public FileDescriptor getFile() { return file; }
 458
 459    /** If this is a nested type, get the outer descriptor, otherwise null. */
 460    public Descriptor getContainingType() { return containingType; }
 461
 462    /** Get the {@code MessageOptions}, defined in {@code descriptor.proto}. */
 463    public MessageOptions getOptions() { return proto.getOptions(); }
 464
 465    /** Get a list of this message type's fields. */
 466    public List<FieldDescriptor> getFields() {
 467      return Collections.unmodifiableList(Arrays.asList(fields));
 468    }
 469
 470    /** Get a list of this message type's extensions. */
 471    public List<FieldDescriptor> getExtensions() {
 472      return Collections.unmodifiableList(Arrays.asList(extensions));
 473    }
 474
 475    /** Get a list of message types nested within this one. */
 476    public List<Descriptor> getNestedTypes() {
 477      return Collections.unmodifiableList(Arrays.asList(nestedTypes));
 478    }
 479
 480    /** Get a list of enum types nested within this one. */
 481    public List<EnumDescriptor> getEnumTypes() {
 482      return Collections.unmodifiableList(Arrays.asList(enumTypes));
 483    }
 484
 485    /** Determines if the given field number is an extension. */
 486    public boolean isExtensionNumber(final int number) {
 487      for (final DescriptorProto.ExtensionRange range :
 488          proto.getExtensionRangeList()) {
 489        if (range.getStart() <= number && number < range.getEnd()) {
 490          return true;
 491        }
 492      }
 493      return false;
 494    }
 495
 496    /**
 497     * Finds a field by name.
 498     * @param name The unqualified name of the field (e.g. "foo").
 499     * @return The field's descriptor, or {@code null} if not found.
 500     */
 501    public FieldDescriptor findFieldByName(final String name) {
 502      final GenericDescriptor result =
 503          file.pool.findSymbol(fullName + '.' + name);
 504      if (result != null && result instanceof FieldDescriptor) {
 505        return (FieldDescriptor)result;
 506      } else {
 507        return null;
 508      }
 509    }
 510
 511    /**
 512     * Finds a field by field number.
 513     * @param number The field number within this message type.
 514     * @return The field's descriptor, or {@code null} if not found.
 515     */
 516    public FieldDescriptor findFieldByNumber(final int number) {
 517      return file.pool.fieldsByNumber.get(
 518        new DescriptorPool.DescriptorIntPair(this, number));
 519    }
 520
 521    /**
 522     * Finds a nested message type by name.
 523     * @param name The unqualified name of the nested type (e.g. "Foo").
 524     * @return The types's descriptor, or {@code null} if not found.
 525     */
 526    public Descriptor findNestedTypeByName(final String name) {
 527      final GenericDescriptor result =
 528          file.pool.findSymbol(fullName + '.' + name);
 529      if (result != null && result instanceof Descriptor) {
 530        return (Descriptor)result;
 531      } else {
 532        return null;
 533      }
 534    }
 535
 536    /**
 537     * Finds a nested enum type by name.
 538     * @param name The unqualified name of the nested type (e.g. "Foo").
 539     * @return The types's descriptor, or {@code null} if not found.
 540     */
 541    public EnumDescriptor findEnumTypeByName(final String name) {
 542      final GenericDescriptor result =
 543          file.pool.findSymbol(fullName + '.' + name);
 544      if (result != null && result instanceof EnumDescriptor) {
 545        return (EnumDescriptor)result;
 546      } else {
 547        return null;
 548      }
 549    }
 550
 551    private final int index;
 552    private DescriptorProto proto;
 553    private final String fullName;
 554    private final FileDescriptor file;
 555    private final Descriptor containingType;
 556    private final Descriptor[] nestedTypes;
 557    private final EnumDescriptor[] enumTypes;
 558    private final FieldDescriptor[] fields;
 559    private final FieldDescriptor[] extensions;
 560
 561    private Descriptor(final DescriptorProto proto,
 562                       final FileDescriptor file,
 563                       final Descriptor parent,
 564                       final int index)
 565                throws DescriptorValidationException {
 566      this.index = index;
 567      this.proto = proto;
 568      fullName = computeFullName(file, parent, proto.getName());
 569      this.file = file;
 570      containingType = parent;
 571
 572      nestedTypes = new Descriptor[proto.getNestedTypeCount()];
 573      for (int i = 0; i < proto.getNestedTypeCount(); i++) {
 574        nestedTypes[i] = new Descriptor(
 575          proto.getNestedType(i), file, this, i);
 576      }
 577
 578      enumTypes = new EnumDescriptor[proto.getEnumTypeCount()];
 579      for (int i = 0; i < proto.getEnumTypeCount(); i++) {
 580        enumTypes[i] = new EnumDescriptor(
 581          proto.getEnumType(i), file, this, i);
 582      }
 583
 584      fields = new FieldDescriptor[proto.getFieldCount()];
 585      for (int i = 0; i < proto.getFieldCount(); i++) {
 586        fields[i] = new FieldDescriptor(
 587          proto.getField(i), file, this, i, false);
 588      }
 589
 590      extensions = new FieldDescriptor[proto.getExtensionCount()];
 591      for (int i = 0; i < proto.getExtensionCount(); i++) {
 592        extensions[i] = new FieldDescriptor(
 593          proto.getExtension(i), file, this, i, true);
 594      }
 595
 596      file.pool.addSymbol(this);
 597    }
 598
 599    /** Look up and cross-link all field types, etc. */
 600    private void crossLink() throws DescriptorValidationException {
 601      for (final Descriptor nestedType : nestedTypes) {
 602        nestedType.crossLink();
 603      }
 604
 605      for (final FieldDescriptor field : fields) {
 606        field.crossLink();
 607      }
 608
 609      for (final FieldDescriptor extension : extensions) {
 610        extension.crossLink();
 611      }
 612    }
 613
 614    /** See {@link FileDescriptor#setProto}. */
 615    private void setProto(final DescriptorProto proto) {
 616      this.proto = proto;
 617
 618      for (int i = 0; i < nestedTypes.length; i++) {
 619        nestedTypes[i].setProto(proto.getNestedType(i));
 620      }
 621
 622      for (int i = 0; i < enumTypes.length; i++) {
 623        enumTypes[i].setProto(proto.getEnumType(i));
 624      }
 625
 626      for (int i = 0; i < fields.length; i++) {
 627        fields[i].setProto(proto.getField(i));
 628      }
 629
 630      for (int i = 0; i < extensions.length; i++) {
 631        extensions[i].setProto(proto.getExtension(i));
 632      }
 633    }
 634  }
 635
 636  // =================================================================
 637
 638  /** Describes a field of a message type. */
 639  public static final class FieldDescriptor
 640      implements GenericDescriptor, Comparable<FieldDescriptor>,
 641                 FieldSet.FieldDescriptorLite<FieldDescriptor> {
 642    /**
 643     * Get the index of this descriptor within its parent.
 644     * @see Descriptor#getIndex()
 645     */
 646    public int getIndex() { return index; }
 647
 648    /** Convert the descriptor to its protocol message representation. */
 649    public FieldDescriptorProto toProto() { return proto; }
 650
 651    /** Get the field's unqualified name. */
 652    public String getName() { return proto.getName(); }
 653
 654    /** Get the field's number. */
 655    public int getNumber() { return proto.getNumber(); }
 656
 657    /**
 658     * Get the field's fully-qualified name.
 659     * @see Descriptor#getFullName()
 660     */
 661    public String getFullName() { return fullName; }
 662
 663    /**
 664     * Get the field's java type.  This is just for convenience.  Every
 665     * {@code FieldDescriptorProto.Type} maps to exactly one Java type.
 666     */
 667    public JavaType getJavaType() { return type.getJavaType(); }
 668
 669    /** For internal use only. */
 670    public WireFormat.JavaType getLiteJavaType() {
 671      return getLiteType().getJavaType();
 672    }
 673
 674    /** Get the {@code FileDescriptor} containing this descriptor. */
 675    public FileDescriptor getFile() { return file; }
 676
 677    /** Get the field's declared type. */
 678    public Type getType() { return type; }
 679
 680    /** For internal use only. */
 681    public WireFormat.FieldType getLiteType() {
 682      return table[type.ordinal()];
 683    }
 684    // I'm pretty sure values() constructs a new array every time, since there
 685    // is nothing stopping the caller from mutating the array.  Therefore we
 686    // make a static copy here.
 687    private static final WireFormat.FieldType[] table =
 688        WireFormat.FieldType.values();
 689
 690    /** Is this field declared required? */
 691    public boolean isRequired() {
 692      return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REQUIRED;
 693    }
 694
 695    /** Is this field declared optional? */
 696    public boolean isOptional() {
 697      return proto.getLabel() == FieldDescriptorProto.Label.LABEL_OPTIONAL;
 698    }
 699
 700    /** Is this field declared repeated? */
 701    public boolean isRepeated() {
 702      return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REPEATED;
 703    }
 704
 705    /** Does this field have the {@code [packed = true]} option? */
 706    public boolean isPacked() {
 707      return getOptions().getPacked();
 708    }
 709
 710    /** Can this field be packed? i.e. is it a repeated primitive field? */
 711    public boolean isPackable() {
 712      return isRepeated() && getLiteType().isPackable();
 713    }
 714
 715    /** Returns true if the field had an explicitly-defined default value. */
 716    public boolean hasDefaultValue() { return proto.hasDefaultValue(); }
 717
 718    /**
 719     * Returns the field's default value.  Valid for all types except for
 720     * messages and groups.  For all other types, the object returned is of
 721     * the same class that would returned by Message.getField(this).
 722     */
 723    public Object getDefaultValue() {
 724      if (getJavaType() == JavaType.MESSAGE) {
 725        throw new UnsupportedOperationException(
 726          "FieldDescriptor.getDefaultValue() called on an embedded message " +
 727          "field.");
 728      }
 729      return defaultValue;
 730    }
 731
 732    /** Get the {@code FieldOptions}, defined in {@code descriptor.proto}. */
 733    public FieldOptions getOptions() { return proto.getOptions(); }
 734
 735    /** Is this field an extension? */
 736    public boolean isExtension() { return proto.hasExtendee(); }
 737
 738    /**
 739     * Get the field's containing type. For extensions, this is the type being
 740     * extended, not the location where the extension was defined.  See
 741     * {@link #getExtensionScope()}.
 742     */
 743    public Descriptor getContainingType() { return containingType; }
 744
 745    /**
 746     * For extensions defined nested within message types, gets the outer
 747     * type.  Not valid for non-extension fields.  For example, consider
 748     * this {@code .proto} file:
 749     * <pre>
 750     *   message Foo {
 751     *     extensions 1000 to max;
 752     *   }
 753     *   extend Foo {
 754     *     optional int32 baz = 1234;
 755     *   }
 756     *   message Bar {
 757     *     extend Foo {
 758     *       optional int32 qux = 4321;
 759     *     }
 760     *   }
 761     * </pre>
 762     * Both {@code baz}'s and {@code qux}'s containing type is {@code Foo}.
 763     * However, {@code baz}'s extension scope is {@code null} while
 764     * {@code qux}'s extension scope is {@code Bar}.
 765     */
 766    public Descriptor getExtensionScope() {
 767      if (!isExtension()) {
 768        throw new UnsupportedOperationException(
 769          "This field is not an extension.");
 770      }
 771      return extensionScope;
 772    }
 773
 774    /** For embedded message and group fields, gets the field's type. */
 775    public Descriptor getMessageType() {
 776      if (getJavaType() != JavaType.MESSAGE) {
 777        throw new UnsupportedOperationException(
 778          "This field is not of message type.");
 779      }
 780      return messageType;
 781    }
 782
 783    /** For enum fields, gets the field's type. */
 784    public EnumDescriptor getEnumType() {
 785      if (getJavaType() != JavaType.ENUM) {
 786        throw new UnsupportedOperationException(
 787          "This field is not of enum type.");
 788      }
 789      return enumType;
 790    }
 791
 792    /**
 793     * Compare with another {@code FieldDescriptor}.  This orders fields in
 794     * "canonical" order, which simply means ascending order by field number.
 795     * {@code other} must be a field of the same type -- i.e.
 796     * {@code getContainingType()} must return the same {@code Descriptor} for
 797     * both fields.
 798     *
 799     * @return negative, zero, or positive if {@code this} is less than,
 800     *         equal to, or greater than {@code other}, respectively.
 801     */
 802    public int compareTo(final FieldDescriptor other) {
 803      if (other.containingType != containingType) {
 804        throw new IllegalArgumentException(
 805          "FieldDescriptors can only be compared to other FieldDescriptors " +
 806          "for fields of the same message type.");
 807      }
 808      return getNumber() - other.getNumber();
 809    }
 810
 811    private final int index;
 812
 813    private FieldDescriptorProto proto;
 814    private final String fullName;
 815    private final FileDescriptor file;
 816    private final Descriptor extensionScope;
 817
 818    // Possibly initialized during cross-linking.
 819    private Type type;
 820    private Descriptor containingType;
 821    private Descriptor messageType;
 822    private EnumDescriptor enumType;
 823    private Object defaultValue;
 824
 825    public enum Type {
 826      DOUBLE  (JavaType.DOUBLE     ),
 827      FLOAT   (JavaType.FLOAT      ),
 828      INT64   (JavaType.LONG       ),
 829      UINT64  (JavaType.LONG       ),
 830      INT32   (JavaType.INT        ),
 831      FIXED64 (JavaType.LONG       ),
 832      FIXED32 (JavaType.INT        ),
 833      BOOL    (JavaType.BOOLEAN    ),
 834      STRING  (JavaType.STRING     ),
 835      GROUP   (JavaType.MESSAGE    ),
 836      MESSAGE (JavaType.MESSAGE    ),
 837      BYTES   (JavaType.BYTE_STRING),
 838      UINT32  (JavaType.INT        ),
 839      ENUM    (JavaType.ENUM       ),
 840      SFIXED32(JavaType.INT        ),
 841      SFIXED64(JavaType.LONG       ),
 842      SINT32  (JavaType.INT        ),
 843      SINT64  (JavaType.LONG       );
 844
 845      Type(final JavaType javaType) {
 846        this.javaType = javaType;
 847      }
 848
 849      private JavaType javaType;
 850
 851      public FieldDescriptorProto.Type toProto() {
 852        return FieldDescriptorProto.Type.valueOf(ordinal() + 1);
 853      }
 854      public JavaType getJavaType() { return javaType; }
 855
 856      public static Type valueOf(final FieldDescriptorProto.Type type) {
 857        return values()[type.getNumber() - 1];
 858      }
 859    }
 860
 861    static {
 862      // Refuse to init if someone added a new declared type.
 863      if (Type.values().length != FieldDescriptorProto.Type.values().length) {
 864        throw new RuntimeException(
 865          "descriptor.proto has a new declared type but Desrciptors.java " +
 866          "wasn't updated.");
 867      }
 868    }
 869
 870    public enum JavaType {
 871      INT(0),
 872      LONG(0L),
 873      FLOAT(0F),
 874      DOUBLE(0D),
 875      BOOLEAN(false),
 876      STRING(""),
 877      BYTE_STRING(ByteString.EMPTY),
 878      ENUM(null),
 879      MESSAGE(null);
 880
 881      JavaType(final Object defaultDefault) {
 882        this.defaultDefault = defaultDefault;
 883      }
 884
 885      /**
 886       * The default default value for fields of this type, if it's a primitive
 887       * type.  This is meant for use inside this file only, hence is private.
 888       */
 889      private final Object defaultDefault;
 890    }
 891
 892    private FieldDescriptor(final FieldDescriptorProto proto,
 893                            final FileDescriptor file,
 894                            final Descriptor parent,
 895                            final int index,
 896                            final boolean isExtension)
 897                     throws DescriptorValidationException {
 898      this.index = index;
 899      this.proto = proto;
 900      fullName = computeFullName(file, parent, proto.getName());
 901      this.file = file;
 902
 903      if (proto.hasType()) {
 904        type = Type.valueOf(proto.getType());
 905      }
 906
 907      if (getNumber() <= 0) {
 908        throw new DescriptorValidationException(this,
 909          "Field numbers must be positive integers.");
 910      }
 911
 912      // Only repeated primitive fields may be packed.
 913      if (proto.getOptions().getPacked() && !isPackable()) {
 914        throw new DescriptorValidationException(this,
 915          "[packed = true] can only be specified for repeated primitive " +
 916          "fields.");
 917      }
 918
 919      if (isExtension) {
 920        if (!proto.hasExtendee()) {
 921          throw new DescriptorValidationException(this,
 922            "FieldDescriptorProto.extendee not set for extension field.");
 923        }
 924        containingType = null;  // Will be filled in when cross-linking
 925        if (parent != null) {
 926          extensionScope = parent;
 927        } else {
 928          extensionScope = null;
 929        }
 930      } else {
 931        if (proto.hasExtendee()) {
 932          throw new DescriptorValidationException(this,
 933            "FieldDescriptorProto.extendee set for non-extension field.");
 934        }
 935        containingType = parent;
 936        extensionScope = null;
 937      }
 938
 939      file.pool.addSymbol(this);
 940    }
 941
 942    /** Look up and cross-link all field types, etc. */
 943    private void crossLink() throws DescriptorValidationException {
 944      if (proto.hasExtendee()) {
 945        final GenericDescriptor extendee =
 946          file.pool.lookupSymbol(proto.getExtendee(), this);
 947        if (!(extendee instanceof Descriptor)) {
 948          throw new DescriptorValidationException(this,
 949              '\"' + proto.getExtendee() + "\" is not a message type.");
 950        }
 951        containingType = (Descriptor)extendee;
 952
 953        if (!getContainingType().isExtensionNumber(getNumber())) {
 954          throw new DescriptorValidationException(this,
 955              '\"' + getContainingType().getFullName() +
 956              "\" does not declare " + getNumber() +
 957              " as an extension number.");
 958        }
 959      }
 960
 961      if (proto.hasTypeName()) {
 962        final GenericDescriptor typeDescriptor =
 963          file.pool.lookupSymbol(proto.getTypeName(), this);
 964
 965        if (!proto.hasType()) {
 966          // Choose field type based on symbol.
 967          if (typeDescriptor instanceof Descriptor) {
 968            type = Type.MESSAGE;
 969          } else if (typeDescriptor instanceof EnumDescriptor) {
 970            type = Type.ENUM;
 971          } else {
 972            throw new DescriptorValidationException(this,
 973                '\"' + proto.getTypeName() + "\" is not a type.");
 974          }
 975        }
 976
 977        if (getJavaType() == JavaType.MESSAGE) {
 978          if (!(typeDescriptor instanceof Descriptor)) {
 979            throw new DescriptorValidationException(this,
 980                '\"' + proto.getTypeName() + "\" is not a message type.");
 981          }
 982          messageType = (Descriptor)typeDescriptor;
 983
 984          if (proto.hasDefaultValue()) {
 985            throw new DescriptorValidationException(this,
 986              "Messages can't have default values.");
 987          }
 988        } else if (getJavaType() == JavaType.ENUM) {
 989          if (!(typeDescriptor instanceof EnumDescriptor)) {
 990            throw new DescriptorValidationException(this,
 991                '\"' + proto.getTypeName() + "\" is not an enum type.");
 992          }
 993          enumType = (EnumDescriptor)typeDescriptor;
 994        } else {
 995          throw new DescriptorValidationException(this,
 996            "Field with primitive type has type_name.");
 997        }
 998      } else {
 999        if (getJavaType() == JavaType.MESSAGE ||
1000            getJavaType() == JavaType.ENUM) {
1001          throw new DescriptorValidationException(this,
1002            "Field with message or enum type missing type_name.");
1003        }
1004      }
1005
1006      // We don't attempt to parse the default value until here because for
1007      // enums we need the enum type's descriptor.
1008      if (proto.hasDefaultValue()) {
1009        if (isRepeated()) {
1010          throw new DescriptorValidationException(this,
1011            "Repeated fields cannot have default values.");
1012        }
1013
1014        try {
1015          switch (getType()) {
1016            case INT32:
1017            case SINT32:
1018            case SFIXED32:
1019              defaultValue = TextFormat.parseInt32(proto.getDefaultValue());
1020              break;
1021            case UINT32:
1022            case FIXED32:
1023              defaultValue = TextFormat.parseUInt32(proto.getDefaultValue());
1024              break;
1025            case INT64:
1026            case SINT64:
1027            case SFIXED64:
1028              defaultValue = TextFormat.parseInt64(proto.getDefaultValue());
1029              break;
1030            case UINT64:
1031            case FIXED64:
1032              defaultValue = TextFormat.parseUInt64(proto.getDefaultValue());
1033              break;
1034            case FLOAT:
1035              if (proto.getDefaultValue().equals("inf")) {
1036                defaultValue = Float.POSITIVE_INFINITY;
1037              } else if (proto.getDefaultValue().equals("-inf")) {
1038                defaultValue = Float.NEGATIVE_INFINITY;
1039              } else if (proto.getDefaultValue().equals("nan")) {
1040                defaultValue = Float.NaN;
1041              } else {
1042                defaultValue = Float.valueOf(proto.getDefaultValue());
1043              }
1044              break;
1045            case DOUBLE:
1046              if (proto.getDefaultValue().equals("inf")) {
1047                defaultValue = Double.POSITIVE_INFINITY;
1048              } else if (proto.getDefaultValue().equals("-inf")) {
1049                defaultValue = Double.NEGATIVE_INFINITY;
1050              } else if (proto.getDefaultValue().equals("nan")) {
1051                defaultValue = Double.NaN;
1052              } else {
1053                defaultValue = Double.valueOf(proto.getDefaultValue());
1054              }
1055              break;
1056            case BOOL:
1057              defaultValue = Boolean.valueOf(proto.getDefaultValue());
1058              break;
1059            case STRING:
1060              defaultValue = proto.getDefaultValue();
1061              break;
1062            case BYTES:
1063              try {
1064                defaultValue =
1065                  TextFormat.unescapeBytes(proto.getDefaultValue());
1066              } catch (TextFormat.InvalidEscapeSequenceException e) {
1067                throw new DescriptorValidationException(this,
1068                  "Couldn't parse default value: " + e.getMessage(), e);
1069              }
1070              break;
1071            case ENUM:
1072              defaultValue = enumType.findValueByName(proto.getDefaultValue());
1073              if (defaultValue == null) {
1074                throw new DescriptorValidationException(this,
1075                  "Unknown enum default value: \"" +
1076                  proto.getDefaultValue() + '\"');
1077              }
1078              break;
1079            case MESSAGE:
1080            case GROUP:
1081              throw new DescriptorValidationException(this,
1082                "Message type had default value.");
1083          }
1084        } catch (NumberFormatException e) {
1085          throw new DescriptorValidationException(this, 
1086              "Could not parse default value: \"" + 
1087              proto.getDefaultValue() + '\"', e);
1088        }
1089      } else {
1090        // Determine the default default for this field.
1091        if (isRepeated()) {
1092          defaultValue = Collections.emptyList();
1093        } else {
1094          switch (getJavaType()) {
1095            case ENUM:
1096              // We guarantee elsewhere that an enum type always has at least
1097              // one possible value.
1098              defaultValue = enumType.getValues().get(0);
1099              break;
1100            case MESSAGE:
1101              defaultValue = null;
1102              break;
1103            default:
1104              defaultValue = getJavaType().defaultDefault;
1105              break;
1106          }
1107        }
1108      }
1109
1110      if (!isExtension()) {
1111        file.pool.addFieldByNumber(this);
1112      }
1113
1114      if (containingType != null &&
1115          containingType.getOptions().getMessageSetWireFormat()) {
1116        if (isExtension()) {
1117          if (!isOptional() || getType() != Type.MESSAGE) {
1118            throw new DescriptorValidationException(this,
1119              "Extensions of MessageSets must be optional messages.");
1120          }
1121        } else {
1122          throw new DescriptorValidationException(this,
1123            "MessageSets cannot have fields, only extensions.");
1124        }
1125      }
1126    }
1127
1128    /** See {@link FileDescriptor#setProto}. */
1129    private void setProto(final FieldDescriptorProto proto) {
1130      this.proto = proto;
1131    }
1132
1133    /**
1134     * For internal use only.  This is to satisfy the FieldDescriptorLite
1135     * interface.
1136     */
1137    public MessageLite.Builder internalMergeFrom(
1138        MessageLite.Builder to, MessageLite from) {
1139      // FieldDescriptors are only used with non-lite messages so we can just
1140      // down-cast and call mergeFrom directly.
1141      return ((Message.Builder) to).mergeFrom((Message) from);
1142    }
1143  }
1144
1145  // =================================================================
1146
1147  /** Describes an enum type. */
1148  public static final class EnumDescriptor
1149      implements GenericDescriptor, Internal.EnumLiteMap<EnumValueDescriptor> {
1150    /**
1151     * Get the index of this descriptor within its parent.
1152     * @see Descriptor#getIndex()
1153     */
1154    public int getIndex() { return index; }
1155
1156    /** Convert the descriptor to its protocol message representation. */
1157    public EnumDescriptorProto toProto() { return proto; }
1158
1159    /** Get the type's unqualified name. */
1160    public String getName() { return proto.getName(); }
1161
1162    /**
1163     * Get the type's fully-qualified name.
1164     * @see Descriptor#getFullName()
1165     */
1166    public String getFullName() { return fullName; }
1167
1168    /** Get the {@link FileDescriptor} containing this descriptor. */
1169    public FileDescriptor getFile() { return file; }
1170
1171    /** If this is a nested type, get the outer descriptor, otherwise null. */
1172    public Descriptor getContainingType() { return containingType; }
1173
1174    /** Get the {@code EnumOptions}, defined in {@code descriptor.proto}. */
1175    public EnumOptions getOptions() { return proto.getOptions(); }
1176
1177    /** Get a list of defined values for this enum. */
1178    public List<EnumValueDescriptor> getValues() {
1179      return Collections.unmodifiableList(Arrays.asList(values));
1180    }
1181
1182    /**
1183     * Find an enum value by name.
1184     * @param name The unqualified name of the value (e.g. "FOO").
1185     * @return the value's decsriptor, or {@code null} if not found.
1186     */
1187    public EnumValueDescriptor findValueByName(final String name) {
1188      final GenericDescriptor result =
1189          file.pool.findSymbol(fullName + '.' + name);
1190      if (result != null && result instanceof EnumValueDescriptor) {
1191        return (EnumValueDescriptor)result;
1192      } else {
1193        return null;
1194      }
1195    }
1196
1197    /**
1198     * Find an enum value by number.  If multiple enum values have the same
1199     * number, this returns the first defined value with that number.
1200     * @param number The value's number.
1201     * @return the value's decsriptor, or {@code null} if not found.
1202     */
1203    public EnumValueDescriptor findValueByNumber(final int number) {
1204      return file.pool.enumValuesByNumber.get(
1205        new DescriptorPool.DescriptorIntPair(this, number));
1206    }
1207
1208    private final int index;
1209    private EnumDescriptorProto proto;
1210    private final String fullName;
1211    private final FileDescriptor file;
1212    private final Descriptor containingType;
1213    private EnumValueDescriptor[] values;
1214
1215    private EnumDescriptor(final EnumDescriptorProto proto,
1216                           final FileDescriptor file,
1217                           final Descriptor parent,
1218                           final int index)
1219                    throws DescriptorValidationException {
1220      this.index = index;
1221      this.proto = proto;
1222      fullName = computeFullName(file, parent, proto.getName());
1223      this.file = file;
1224      containingType = parent;
1225
1226      if (proto.getValueCount() == 0) {
1227        // We cannot allow enums with no values because this would mean there
1228        // would be no valid default value for fields of this type.
1229        throw new DescriptorValidationException(this,
1230          "Enums must contain at least one value.");
1231      }
1232
1233      values = new EnumValueDescriptor[proto.getValueCount()];
1234      for (int i = 0; i < proto.getValueCount(); i++) {
1235        values[i] = new EnumValueDescriptor(
1236          proto.getValue(i), file, this, i);
1237      }
1238
1239      file.pool.addSymbol(this);
1240    }
1241
1242    /** See {@link FileDescriptor#setProto}. */
1243    private void setProto(final EnumDescriptorProto proto) {
1244      this.proto = proto;
1245
1246      for (int i = 0; i < values.length; i++) {
1247        values[i].setProto(proto.getValue(i));
1248      }
1249    }
1250  }
1251
1252  // =================================================================
1253
1254  /**
1255   * Describes one value within an enum type.  Note that multiple defined
1256   * values may have the same number.  In generated Java code, all values
1257   * with the same number after the first become aliases of the first.
1258   * However, they still have independent EnumValueDescriptors.
1259   */
1260  public static final class EnumValueDescriptor
1261      implements GenericDescriptor, Internal.EnumLite {
1262    /**
1263     * Get the index of this descriptor within its parent.
1264     * @see Descriptor#getIndex()
1265     */
1266    public int getIndex() { return index; }
1267
1268    /** Convert the descriptor to its protocol message representation. */
1269    public EnumValueDescriptorProto toProto() { return proto; }
1270
1271    /** Get the value's unqualified name. */
1272    public String getName() { return proto.getName(); }
1273
1274    /** Get the value's number. */
1275    public int getNumber() { return proto.getNumber(); }
1276
1277    /**
1278     * Get the value's fully-qualified name.
1279     * @see Descriptor#getFullName()
1280     */
1281    public String getFullName() { return fullName; }
1282
1283    /** Get the {@link FileDescriptor} containing this descriptor. */
1284    public FileDescriptor getFile() { return file; }
1285
1286    /** Get the value's enum type. */
1287    public EnumDescriptor getType() { return type; }
1288
1289    /**
1290     * Get the {@code EnumValueOptions}, defined in {@code descriptor.proto}.
1291     */
1292    public EnumValueOptions getOptions() { return proto.getOptions(); }
1293
1294    private final int index;
1295    private EnumValueDescriptorProto proto;
1296    private final String fullName;
1297    private final FileDescriptor file;
1298    private final EnumDescriptor type;
1299
1300    private EnumValueDescriptor(final EnumValueDescriptorProto proto,
1301                                final FileDescriptor file,
1302                                final EnumDescriptor parent,
1303                                final int index)
1304                         throws DescriptorValidationException {
1305      this.index = index;
1306      this.proto = proto;
1307      this.file = file;
1308      type = parent;
1309
1310      fullName = parent.getFullName() + '.' + proto.getName();
1311
1312      file.pool.addSymbol(this);
1313      file.pool.addEnumValueByNumber(this);
1314    }
1315
1316    /** See {@link FileDescriptor#setProto}. */
1317    private void setProto(final EnumValueDescriptorProto proto) {
1318      this.proto = proto;
1319    }
1320  }
1321
1322  // =================================================================
1323
1324  /** Describes a service type. */
1325  public static final class ServiceDescriptor implements GenericDescriptor {
1326    /**
1327     * Get the index of this descriptor within its parent.
1328     * * @see Descriptors.Descriptor#getIndex()
1329     */
1330    public int getIndex() { return index; }
1331
1332    /** Convert the descriptor to its protocol message representation. */
1333    public ServiceDescriptorProto toProto() { return proto; }
1334
1335    /** Get the type's unqualified name. */
1336    public String getName() { return proto.getName(); }
1337
1338    /**
1339     * Get the type's fully-qualified name.
1340     * @see Descriptor#getFullName()
1341     */
1342    public String getFullName() { return fullName; }
1343
1344    /** Get the {@link FileDescriptor} containing this descriptor. */
1345    public FileDescriptor getFile() { return file; }
1346
1347    /** Get the {@code ServiceOptions}, defined in {@code descriptor.proto}. */
1348    public ServiceOptions getOptions() { return proto.getOptions(); }
1349
1350    /** Get a list of methods for this service. */
1351    public List<MethodDescriptor> getMethods() {
1352      return Collections.unmodifiableList(Arrays.asList(methods));
1353    }
1354
1355    /**
1356     * Find a method by name.
1357     * @param name The unqualified name of the method (e.g. "Foo").
1358     * @return the method's decsriptor, or {@code null} if not found.
1359     */
1360    public MethodDescriptor findMethodByName(final String name) {
1361      final GenericDescriptor result =
1362          file.pool.findSymbol(fullName + '.' + name);
1363      if (result != null && result instanceof MethodDescriptor) {
1364        return (Met

Large files files are truncated, but you can click here to view the full file