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