PageRenderTime 56ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

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

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