37
37
import java.util.HashMap;
38
38
import java.util.List;
39
39
import java.util.Map;
40
import java.io.UnsupportedEncodingException;
42
43
* Contains a collection of classes which describe protocol message types.
44
* Every message type has a {@link Descriptors.Descriptor}, which lists all
45
* Every message type has a {@link Descriptor}, which lists all
45
46
* its fields and other information about a type. You can get a message
46
47
* type's descriptor by calling {@code MessageType.getDescriptor()}, or
47
48
* (given a message object of the type) {@code message.getDescriptorForType()}.
106
107
public Descriptor findMessageTypeByName(String name) {
107
108
// Don't allow looking up nested types. This will make optimization
109
if (name.indexOf('.') != -1) return null;
110
if (name.indexOf('.') != -1) {
110
113
if (getPackage().length() > 0) {
111
name = getPackage() + "." + name;
114
name = getPackage() + '.' + name;
113
GenericDescriptor result = pool.findSymbol(name);
116
final GenericDescriptor result = pool.findSymbol(name);
114
117
if (result != null && result instanceof Descriptor &&
115
118
result.getFile() == this) {
116
119
return (Descriptor)result;
128
131
public EnumDescriptor findEnumTypeByName(String name) {
129
132
// Don't allow looking up nested types. This will make optimization
131
if (name.indexOf('.') != -1) return null;
134
if (name.indexOf('.') != -1) {
132
137
if (getPackage().length() > 0) {
133
name = getPackage() + "." + name;
138
name = getPackage() + '.' + name;
135
GenericDescriptor result = pool.findSymbol(name);
140
final GenericDescriptor result = pool.findSymbol(name);
136
141
if (result != null && result instanceof EnumDescriptor &&
137
142
result.getFile() == this) {
138
143
return (EnumDescriptor)result;
150
155
public ServiceDescriptor findServiceByName(String name) {
151
156
// Don't allow looking up nested types. This will make optimization
153
if (name.indexOf('.') != -1) return null;
158
if (name.indexOf('.') != -1) {
154
161
if (getPackage().length() > 0) {
155
name = getPackage() + "." + name;
162
name = getPackage() + '.' + name;
157
GenericDescriptor result = pool.findSymbol(name);
164
final GenericDescriptor result = pool.findSymbol(name);
158
165
if (result != null && result instanceof ServiceDescriptor &&
159
166
result.getFile() == this) {
160
167
return (ServiceDescriptor)result;
171
178
* @return The extension's descriptor, or {@code null} if not found.
173
180
public FieldDescriptor findExtensionByName(String name) {
174
if (name.indexOf('.') != -1) return null;
181
if (name.indexOf('.') != -1) {
175
184
if (getPackage().length() > 0) {
176
name = getPackage() + "." + name;
185
name = getPackage() + '.' + name;
178
GenericDescriptor result = pool.findSymbol(name);
187
final GenericDescriptor result = pool.findSymbol(name);
179
188
if (result != null && result instanceof FieldDescriptor &&
180
189
result.getFile() == this) {
181
190
return (FieldDescriptor)result;
196
205
* because a field has an undefined type or because two messages
197
206
* were defined with the same name.
199
public static FileDescriptor buildFrom(FileDescriptorProto proto,
200
FileDescriptor[] dependencies)
208
public static FileDescriptor buildFrom(final FileDescriptorProto proto,
209
final FileDescriptor[] dependencies)
201
210
throws DescriptorValidationException {
202
211
// Building decsriptors involves two steps: translating and linking.
203
212
// In the translation step (implemented by FileDescriptor's
208
217
// FieldDescriptor for an embedded message contains a pointer directly
209
218
// to the Descriptor for that message's type. We also detect undefined
210
219
// types in the linking step.
211
DescriptorPool pool = new DescriptorPool(dependencies);
212
FileDescriptor result = new FileDescriptor(proto, dependencies, pool);
220
final DescriptorPool pool = new DescriptorPool(dependencies);
221
final FileDescriptor result =
222
new FileDescriptor(proto, dependencies, pool);
214
224
if (dependencies.length != proto.getDependencyCount()) {
215
225
throw new DescriptorValidationException(result,
234
244
* encoded in protocol buffer wire format.
236
246
public static void internalBuildGeneratedFileFrom(
237
String descriptorData, FileDescriptor[] dependencies,
238
InternalDescriptorAssigner descriptorAssigner) {
247
final String[] descriptorDataParts,
248
final FileDescriptor[] dependencies,
249
final InternalDescriptorAssigner descriptorAssigner) {
239
250
// Hack: We can't embed a raw byte array inside generated Java code
240
251
// (at least, not efficiently), but we can embed Strings. So, the
241
252
// protocol compiler embeds the FileDescriptorProto as a giant
245
256
// serialized form. So, if we convert it to bytes in ISO-8859-1, we
246
257
// should get the original bytes that we want.
248
byte[] descriptorBytes;
259
// descriptorData may contain multiple strings in order to get around the
260
// Java 64k string literal limit.
261
StringBuilder descriptorData = new StringBuilder();
262
for (String part : descriptorDataParts) {
263
descriptorData.append(part);
266
final byte[] descriptorBytes;
250
descriptorBytes = descriptorData.getBytes("ISO-8859-1");
251
} catch (java.io.UnsupportedEncodingException e) {
268
descriptorBytes = descriptorData.toString().getBytes("ISO-8859-1");
269
} catch (UnsupportedEncodingException e) {
252
270
throw new RuntimeException(
253
271
"Standard encoding ISO-8859-1 not supported by JVM.", e);
309
328
private final FileDescriptor[] dependencies;
310
329
private final DescriptorPool pool;
312
private FileDescriptor(FileDescriptorProto proto,
313
FileDescriptor[] dependencies,
331
private FileDescriptor(final FileDescriptorProto proto,
332
final FileDescriptor[] dependencies,
333
final DescriptorPool pool)
315
334
throws DescriptorValidationException {
316
335
this.pool = pool;
317
336
this.proto = proto;
345
364
/** Look up and cross-link all field types, etc. */
346
365
private void crossLink() throws DescriptorValidationException {
347
for (int i = 0; i < messageTypes.length; i++) {
348
messageTypes[i].crossLink();
351
for (int i = 0; i < services.length; i++) {
352
services[i].crossLink();
355
for (int i = 0; i < extensions.length; i++) {
356
extensions[i].crossLink();
366
for (final Descriptor messageType : messageTypes) {
367
messageType.crossLink();
370
for (final ServiceDescriptor service : services) {
374
for (final FieldDescriptor extension : extensions) {
375
extension.crossLink();
458
477
/** Determines if the given field number is an extension. */
459
public boolean isExtensionNumber(int number) {
460
for (DescriptorProto.ExtensionRange range : proto.getExtensionRangeList()) {
478
public boolean isExtensionNumber(final int number) {
479
for (final DescriptorProto.ExtensionRange range :
480
proto.getExtensionRangeList()) {
461
481
if (range.getStart() <= number && number < range.getEnd()) {
470
490
* @param name The unqualified name of the field (e.g. "foo").
471
491
* @return The field's descriptor, or {@code null} if not found.
473
public FieldDescriptor findFieldByName(String name) {
474
GenericDescriptor result = file.pool.findSymbol(fullName + "." + name);
493
public FieldDescriptor findFieldByName(final String name) {
494
final GenericDescriptor result =
495
file.pool.findSymbol(fullName + '.' + name);
475
496
if (result != null && result instanceof FieldDescriptor) {
476
497
return (FieldDescriptor)result;
484
505
* @param number The field number within this message type.
485
506
* @return The field's descriptor, or {@code null} if not found.
487
public FieldDescriptor findFieldByNumber(int number) {
508
public FieldDescriptor findFieldByNumber(final int number) {
488
509
return file.pool.fieldsByNumber.get(
489
510
new DescriptorPool.DescriptorIntPair(this, number));
494
515
* @param name The unqualified name of the nested type (e.g. "Foo").
495
516
* @return The types's descriptor, or {@code null} if not found.
497
public Descriptor findNestedTypeByName(String name) {
498
GenericDescriptor result = file.pool.findSymbol(fullName + "." + name);
518
public Descriptor findNestedTypeByName(final String name) {
519
final GenericDescriptor result =
520
file.pool.findSymbol(fullName + '.' + name);
499
521
if (result != null && result instanceof Descriptor) {
500
522
return (Descriptor)result;
508
530
* @param name The unqualified name of the nested type (e.g. "Foo").
509
531
* @return The types's descriptor, or {@code null} if not found.
511
public EnumDescriptor findEnumTypeByName(String name) {
512
GenericDescriptor result = file.pool.findSymbol(fullName + "." + name);
533
public EnumDescriptor findEnumTypeByName(final String name) {
534
final GenericDescriptor result =
535
file.pool.findSymbol(fullName + '.' + name);
513
536
if (result != null && result instanceof EnumDescriptor) {
514
537
return (EnumDescriptor)result;
527
550
private final FieldDescriptor[] fields;
528
551
private final FieldDescriptor[] extensions;
530
private Descriptor(DescriptorProto proto,
553
private Descriptor(final DescriptorProto proto,
554
final FileDescriptor file,
555
final Descriptor parent,
534
557
throws DescriptorValidationException {
535
558
this.index = index;
536
559
this.proto = proto;
537
this.fullName = computeFullName(file, parent, proto.getName());
560
fullName = computeFullName(file, parent, proto.getName());
538
561
this.file = file;
539
this.containingType = parent;
562
containingType = parent;
541
this.nestedTypes = new Descriptor[proto.getNestedTypeCount()];
564
nestedTypes = new Descriptor[proto.getNestedTypeCount()];
542
565
for (int i = 0; i < proto.getNestedTypeCount(); i++) {
543
this.nestedTypes[i] = new Descriptor(
566
nestedTypes[i] = new Descriptor(
544
567
proto.getNestedType(i), file, this, i);
547
this.enumTypes = new EnumDescriptor[proto.getEnumTypeCount()];
570
enumTypes = new EnumDescriptor[proto.getEnumTypeCount()];
548
571
for (int i = 0; i < proto.getEnumTypeCount(); i++) {
549
this.enumTypes[i] = new EnumDescriptor(
572
enumTypes[i] = new EnumDescriptor(
550
573
proto.getEnumType(i), file, this, i);
553
this.fields = new FieldDescriptor[proto.getFieldCount()];
576
fields = new FieldDescriptor[proto.getFieldCount()];
554
577
for (int i = 0; i < proto.getFieldCount(); i++) {
555
this.fields[i] = new FieldDescriptor(
578
fields[i] = new FieldDescriptor(
556
579
proto.getField(i), file, this, i, false);
559
this.extensions = new FieldDescriptor[proto.getExtensionCount()];
582
extensions = new FieldDescriptor[proto.getExtensionCount()];
560
583
for (int i = 0; i < proto.getExtensionCount(); i++) {
561
this.extensions[i] = new FieldDescriptor(
584
extensions[i] = new FieldDescriptor(
562
585
proto.getExtension(i), file, this, i, true);
568
591
/** Look up and cross-link all field types, etc. */
569
592
private void crossLink() throws DescriptorValidationException {
570
for (int i = 0; i < nestedTypes.length; i++) {
571
nestedTypes[i].crossLink();
574
for (int i = 0; i < fields.length; i++) {
575
fields[i].crossLink();
578
for (int i = 0; i < extensions.length; i++) {
579
extensions[i].crossLink();
593
for (final Descriptor nestedType : nestedTypes) {
594
nestedType.crossLink();
597
for (final FieldDescriptor field : fields) {
601
for (final FieldDescriptor extension : extensions) {
602
extension.crossLink();
583
/** See {@link FileDescriptor.setProto}. */
584
private void setProto(DescriptorProto proto) {
606
/** See {@link FileDescriptor#setProto}. */
607
private void setProto(final DescriptorProto proto) {
585
608
this.proto = proto;
587
610
for (int i = 0; i < nestedTypes.length; i++) {
607
630
/** Describes a field of a message type. */
608
631
public static final class FieldDescriptor
609
implements GenericDescriptor, Comparable<FieldDescriptor> {
632
implements GenericDescriptor, Comparable<FieldDescriptor>,
633
FieldSet.FieldDescriptorLite<FieldDescriptor> {
611
635
* Get the index of this descriptor within its parent.
612
* @see Descriptors.Descriptor#getIndex()
636
* @see Descriptor#getIndex()
614
638
public int getIndex() { return index; }
635
659
public JavaType getJavaType() { return type.getJavaType(); }
661
/** For internal use only. */
662
public WireFormat.JavaType getLiteJavaType() {
663
return getLiteType().getJavaType();
637
666
/** Get the {@code FileDescriptor} containing this descriptor. */
638
667
public FileDescriptor getFile() { return file; }
640
669
/** Get the field's declared type. */
641
670
public Type getType() { return type; }
672
/** For internal use only. */
673
public WireFormat.FieldType getLiteType() {
674
return table[type.ordinal()];
676
// I'm pretty sure values() constructs a new array every time, since there
677
// is nothing stopping the caller from mutating the array. Therefore we
678
// make a static copy here.
679
private static final WireFormat.FieldType[] table =
680
WireFormat.FieldType.values();
643
682
/** Is this field declared required? */
644
683
public boolean isRequired() {
645
684
return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REQUIRED;
742
786
* @return negative, zero, or positive if {@code this} is less than,
743
787
* equal to, or greater than {@code other}, respectively.
745
public int compareTo(FieldDescriptor other) {
789
public int compareTo(final FieldDescriptor other) {
746
790
if (other.containingType != containingType) {
747
791
throw new IllegalArgumentException(
748
792
"FieldDescriptors can only be compared to other FieldDescriptors " +
765
809
private EnumDescriptor enumType;
766
810
private Object defaultValue;
768
public static enum Type {
769
813
DOUBLE (FieldDescriptorProto.Type.TYPE_DOUBLE , JavaType.DOUBLE ),
770
814
FLOAT (FieldDescriptorProto.Type.TYPE_FLOAT , JavaType.FLOAT ),
771
815
INT64 (FieldDescriptorProto.Type.TYPE_INT64 , JavaType.LONG ),
785
829
SINT32 (FieldDescriptorProto.Type.TYPE_SINT32 , JavaType.INT ),
786
830
SINT64 (FieldDescriptorProto.Type.TYPE_SINT64 , JavaType.LONG );
788
private Type(FieldDescriptorProto.Type proto, JavaType javaType) {
832
Type(final FieldDescriptorProto.Type proto, final JavaType javaType) {
789
833
this.proto = proto;
790
834
this.javaType = javaType;
792
if (this.ordinal() != proto.getNumber() - 1) {
836
if (ordinal() != proto.getNumber() - 1) {
793
837
throw new RuntimeException(
794
838
"descriptor.proto changed but Desrciptors.java wasn't updated.");
834
878
* The default default value for fields of this type, if it's a primitive
835
879
* type. This is meant for use inside this file only, hence is private.
837
private Object defaultDefault;
881
private final Object defaultDefault;
840
private FieldDescriptor(FieldDescriptorProto proto,
884
private FieldDescriptor(final FieldDescriptorProto proto,
885
final FileDescriptor file,
886
final Descriptor parent,
888
final boolean isExtension)
845
889
throws DescriptorValidationException {
846
890
this.index = index;
847
891
this.proto = proto;
848
this.fullName = computeFullName(file, parent, proto.getName());
892
fullName = computeFullName(file, parent, proto.getName());
849
893
this.file = file;
851
895
if (proto.hasType()) {
852
this.type = Type.valueOf(proto.getType());
896
type = Type.valueOf(proto.getType());
855
899
if (getNumber() <= 0) {
875
919
throw new DescriptorValidationException(this,
876
920
"FieldDescriptorProto.extendee not set for extension field.");
878
this.containingType = null; // Will be filled in when cross-linking
922
containingType = null; // Will be filled in when cross-linking
879
923
if (parent != null) {
880
this.extensionScope = parent;
924
extensionScope = parent;
882
this.extensionScope = null;
926
extensionScope = null;
885
929
if (proto.hasExtendee()) {
886
930
throw new DescriptorValidationException(this,
887
931
"FieldDescriptorProto.extendee set for non-extension field.");
889
this.containingType = parent;
890
this.extensionScope = null;
933
containingType = parent;
934
extensionScope = null;
893
937
file.pool.addSymbol(this);
896
940
/** Look up and cross-link all field types, etc. */
897
941
private void crossLink() throws DescriptorValidationException {
898
942
if (proto.hasExtendee()) {
899
GenericDescriptor extendee =
943
final GenericDescriptor extendee =
900
944
file.pool.lookupSymbol(proto.getExtendee(), this);
901
945
if (!(extendee instanceof Descriptor)) {
902
946
throw new DescriptorValidationException(this,
903
"\"" + proto.getExtendee() + "\" is not a message type.");
947
'\"' + proto.getExtendee() + "\" is not a message type.");
905
this.containingType = (Descriptor)extendee;
949
containingType = (Descriptor)extendee;
907
951
if (!getContainingType().isExtensionNumber(getNumber())) {
908
952
throw new DescriptorValidationException(this,
909
"\"" + getContainingType().getFullName() + "\" does not declare " +
910
getNumber() + " as an extension number.");
953
'\"' + getContainingType().getFullName() +
954
"\" does not declare " + getNumber() +
955
" as an extension number.");
914
959
if (proto.hasTypeName()) {
915
GenericDescriptor typeDescriptor =
960
final GenericDescriptor typeDescriptor =
916
961
file.pool.lookupSymbol(proto.getTypeName(), this);
918
963
if (!proto.hasType()) {
919
964
// Choose field type based on symbol.
920
965
if (typeDescriptor instanceof Descriptor) {
921
this.type = Type.MESSAGE;
922
967
} else if (typeDescriptor instanceof EnumDescriptor) {
923
this.type = Type.ENUM;
925
970
throw new DescriptorValidationException(this,
926
"\"" + proto.getTypeName() + "\" is not a type.");
971
'\"' + proto.getTypeName() + "\" is not a type.");
930
975
if (getJavaType() == JavaType.MESSAGE) {
931
976
if (!(typeDescriptor instanceof Descriptor)) {
932
977
throw new DescriptorValidationException(this,
933
"\"" + proto.getTypeName() + "\" is not a message type.");
978
'\"' + proto.getTypeName() + "\" is not a message type.");
935
this.messageType = (Descriptor)typeDescriptor;
980
messageType = (Descriptor)typeDescriptor;
937
982
if (proto.hasDefaultValue()) {
938
983
throw new DescriptorValidationException(this,
941
986
} else if (getJavaType() == JavaType.ENUM) {
942
987
if (!(typeDescriptor instanceof EnumDescriptor)) {
943
988
throw new DescriptorValidationException(this,
944
"\"" + proto.getTypeName() + "\" is not an enum type.");
989
'\"' + proto.getTypeName() + "\" is not an enum type.");
946
this.enumType = (EnumDescriptor)typeDescriptor;
991
enumType = (EnumDescriptor)typeDescriptor;
948
993
throw new DescriptorValidationException(this,
949
994
"Field with primitive type has type_name.");
1004
1047
TextFormat.unescapeBytes(proto.getDefaultValue());
1005
} catch (TextFormat.InvalidEscapeSequence e) {
1048
} catch (TextFormat.InvalidEscapeSequenceException e) {
1006
1049
throw new DescriptorValidationException(this,
1007
"Couldn't parse default value: " + e.getMessage());
1050
"Couldn't parse default value: " + e.getMessage(), e);
1021
1064
"Message type had default value.");
1023
1066
} catch (NumberFormatException e) {
1024
DescriptorValidationException validationException =
1067
final DescriptorValidationException validationException =
1025
1068
new DescriptorValidationException(this,
1026
1069
"Could not parse default value: \"" +
1027
proto.getDefaultValue() + "\"");
1070
proto.getDefaultValue() + '\"');
1028
1071
validationException.initCause(e);
1029
1072
throw validationException;
1032
1075
// Determine the default default for this field.
1033
1076
if (isRepeated()) {
1034
defaultValue = Collections.EMPTY_LIST;
1077
defaultValue = Collections.emptyList();
1036
1079
switch (getJavaType()) {
1070
/** See {@link FileDescriptor.setProto}. */
1071
private void setProto(FieldDescriptorProto proto) {
1113
/** See {@link FileDescriptor#setProto}. */
1114
private void setProto(final FieldDescriptorProto proto) {
1072
1115
this.proto = proto;
1119
* For internal use only. This is to satisfy the FieldDescriptorLite
1122
public MessageLite.Builder internalMergeFrom(
1123
MessageLite.Builder to, MessageLite from) {
1124
// FieldDescriptors are only used with non-lite messages so we can just
1125
// down-cast and call mergeFrom directly.
1126
return ((Message.Builder) to).mergeFrom((Message) from);
1076
1130
// =================================================================
1078
1132
/** Describes an enum type. */
1079
public static final class EnumDescriptor implements GenericDescriptor {
1133
public static final class EnumDescriptor
1134
implements GenericDescriptor, Internal.EnumLiteMap<EnumValueDescriptor> {
1081
1136
* Get the index of this descriptor within its parent.
1082
* @see Descriptors.Descriptor#getIndex()
1137
* @see Descriptor#getIndex()
1084
1139
public int getIndex() { return index; }
1114
1169
* @param name The unqualified name of the value (e.g. "FOO").
1115
1170
* @return the value's decsriptor, or {@code null} if not found.
1117
public EnumValueDescriptor findValueByName(String name) {
1118
GenericDescriptor result = file.pool.findSymbol(fullName + "." + name);
1172
public EnumValueDescriptor findValueByName(final String name) {
1173
final GenericDescriptor result =
1174
file.pool.findSymbol(fullName + '.' + name);
1119
1175
if (result != null && result instanceof EnumValueDescriptor) {
1120
1176
return (EnumValueDescriptor)result;
1129
1185
* @param number The value's number.
1130
1186
* @return the value's decsriptor, or {@code null} if not found.
1132
public EnumValueDescriptor findValueByNumber(int number) {
1188
public EnumValueDescriptor findValueByNumber(final int number) {
1133
1189
return file.pool.enumValuesByNumber.get(
1134
1190
new DescriptorPool.DescriptorIntPair(this, number));
1141
1197
private final Descriptor containingType;
1142
1198
private EnumValueDescriptor[] values;
1144
private EnumDescriptor(EnumDescriptorProto proto,
1145
FileDescriptor file,
1200
private EnumDescriptor(final EnumDescriptorProto proto,
1201
final FileDescriptor file,
1202
final Descriptor parent,
1148
1204
throws DescriptorValidationException {
1149
1205
this.index = index;
1150
1206
this.proto = proto;
1151
this.fullName = computeFullName(file, parent, proto.getName());
1207
fullName = computeFullName(file, parent, proto.getName());
1152
1208
this.file = file;
1153
this.containingType = parent;
1209
containingType = parent;
1155
1211
if (proto.getValueCount() == 0) {
1156
1212
// We cannot allow enums with no values because this would mean there
1162
1218
values = new EnumValueDescriptor[proto.getValueCount()];
1163
1219
for (int i = 0; i < proto.getValueCount(); i++) {
1164
this.values[i] = new EnumValueDescriptor(
1220
values[i] = new EnumValueDescriptor(
1165
1221
proto.getValue(i), file, this, i);
1168
1224
file.pool.addSymbol(this);
1171
/** See {@link FileDescriptor.setProto}. */
1172
private void setProto(EnumDescriptorProto proto) {
1227
/** See {@link FileDescriptor#setProto}. */
1228
private void setProto(final EnumDescriptorProto proto) {
1173
1229
this.proto = proto;
1175
1231
for (int i = 0; i < values.length; i++) {
1186
1242
* with the same number after the first become aliases of the first.
1187
1243
* However, they still have independent EnumValueDescriptors.
1189
public static final class EnumValueDescriptor implements GenericDescriptor {
1245
public static final class EnumValueDescriptor
1246
implements GenericDescriptor, Internal.EnumLite {
1191
1248
* Get the index of this descriptor within its parent.
1192
* @see Descriptors.Descriptor#getIndex()
1249
* @see Descriptor#getIndex()
1194
1251
public int getIndex() { return index; }
1225
1282
private final FileDescriptor file;
1226
1283
private final EnumDescriptor type;
1228
private EnumValueDescriptor(EnumValueDescriptorProto proto,
1229
FileDescriptor file,
1230
EnumDescriptor parent,
1285
private EnumValueDescriptor(final EnumValueDescriptorProto proto,
1286
final FileDescriptor file,
1287
final EnumDescriptor parent,
1232
1289
throws DescriptorValidationException {
1233
1290
this.index = index;
1234
1291
this.proto = proto;
1235
1292
this.file = file;
1238
this.fullName = parent.getFullName() + "." + proto.getName();
1295
fullName = parent.getFullName() + '.' + proto.getName();
1240
1297
file.pool.addSymbol(this);
1241
1298
file.pool.addEnumValueByNumber(this);
1244
/** See {@link FileDescriptor.setProto}. */
1245
private void setProto(EnumValueDescriptorProto proto) {
1301
/** See {@link FileDescriptor#setProto}. */
1302
private void setProto(final EnumValueDescriptorProto proto) {
1246
1303
this.proto = proto;
1285
1342
* @param name The unqualified name of the method (e.g. "Foo").
1286
1343
* @return the method's decsriptor, or {@code null} if not found.
1288
public MethodDescriptor findMethodByName(String name) {
1289
GenericDescriptor result = file.pool.findSymbol(fullName + "." + name);
1345
public MethodDescriptor findMethodByName(final String name) {
1346
final GenericDescriptor result =
1347
file.pool.findSymbol(fullName + '.' + name);
1290
1348
if (result != null && result instanceof MethodDescriptor) {
1291
1349
return (MethodDescriptor)result;
1300
1358
private final FileDescriptor file;
1301
1359
private MethodDescriptor[] methods;
1303
private ServiceDescriptor(ServiceDescriptorProto proto,
1304
FileDescriptor file,
1361
private ServiceDescriptor(final ServiceDescriptorProto proto,
1362
final FileDescriptor file,
1306
1364
throws DescriptorValidationException {
1307
1365
this.index = index;
1308
1366
this.proto = proto;
1309
this.fullName = computeFullName(file, null, proto.getName());
1367
fullName = computeFullName(file, null, proto.getName());
1310
1368
this.file = file;
1312
this.methods = new MethodDescriptor[proto.getMethodCount()];
1370
methods = new MethodDescriptor[proto.getMethodCount()];
1313
1371
for (int i = 0; i < proto.getMethodCount(); i++) {
1314
this.methods[i] = new MethodDescriptor(
1372
methods[i] = new MethodDescriptor(
1315
1373
proto.getMethod(i), file, this, i);
1321
1379
private void crossLink() throws DescriptorValidationException {
1322
for (int i = 0; i < methods.length; i++) {
1323
methods[i].crossLink();
1380
for (final MethodDescriptor method : methods) {
1327
/** See {@link FileDescriptor.setProto}. */
1328
private void setProto(ServiceDescriptorProto proto) {
1385
/** See {@link FileDescriptor#setProto}. */
1386
private void setProto(final ServiceDescriptorProto proto) {
1329
1387
this.proto = proto;
1331
1389
for (int i = 0; i < methods.length; i++) {
1385
1443
private Descriptor inputType;
1386
1444
private Descriptor outputType;
1388
private MethodDescriptor(MethodDescriptorProto proto,
1389
FileDescriptor file,
1390
ServiceDescriptor parent,
1446
private MethodDescriptor(final MethodDescriptorProto proto,
1447
final FileDescriptor file,
1448
final ServiceDescriptor parent,
1392
1450
throws DescriptorValidationException {
1393
1451
this.index = index;
1394
1452
this.proto = proto;
1395
1453
this.file = file;
1396
this.service = parent;
1398
this.fullName = parent.getFullName() + "." + proto.getName();
1456
fullName = parent.getFullName() + '.' + proto.getName();
1400
1458
file.pool.addSymbol(this);
1403
1461
private void crossLink() throws DescriptorValidationException {
1404
GenericDescriptor inputType =
1462
final GenericDescriptor input =
1405
1463
file.pool.lookupSymbol(proto.getInputType(), this);
1406
if (!(inputType instanceof Descriptor)) {
1464
if (!(input instanceof Descriptor)) {
1407
1465
throw new DescriptorValidationException(this,
1408
"\"" + proto.getInputType() + "\" is not a message type.");
1466
'\"' + proto.getInputType() + "\" is not a message type.");
1410
this.inputType = (Descriptor)inputType;
1468
inputType = (Descriptor)input;
1412
GenericDescriptor outputType =
1470
final GenericDescriptor output =
1413
1471
file.pool.lookupSymbol(proto.getOutputType(), this);
1414
if (!(outputType instanceof Descriptor)) {
1472
if (!(output instanceof Descriptor)) {
1415
1473
throw new DescriptorValidationException(this,
1416
"\"" + proto.getOutputType() + "\" is not a message type.");
1474
'\"' + proto.getOutputType() + "\" is not a message type.");
1418
this.outputType = (Descriptor)outputType;
1476
outputType = (Descriptor)output;
1421
/** See {@link FileDescriptor.setProto}. */
1422
private void setProto(MethodDescriptorProto proto) {
1479
/** See {@link FileDescriptor#setProto}. */
1480
private void setProto(final MethodDescriptorProto proto) {
1423
1481
this.proto = proto;
1427
1485
// =================================================================
1429
private static String computeFullName(FileDescriptor file,
1487
private static String computeFullName(final FileDescriptor file,
1488
final Descriptor parent,
1489
final String name) {
1432
1490
if (parent != null) {
1433
return parent.getFullName() + "." + name;
1491
return parent.getFullName() + '.' + name;
1434
1492
} else if (file.getPackage().length() > 0) {
1435
return file.getPackage() + "." + name;
1493
return file.getPackage() + '.' + name;
1473
1533
private final Message proto;
1474
1534
private final String description;
1476
private DescriptorValidationException(GenericDescriptor problemDescriptor,
1477
String description) {
1478
super(problemDescriptor.getFullName() + ": " + description);
1536
private DescriptorValidationException(
1537
final GenericDescriptor problemDescriptor,
1538
final String description) {
1539
this(problemDescriptor, description, null);
1542
private DescriptorValidationException(
1543
final GenericDescriptor problemDescriptor,
1544
final String description,
1545
final Throwable cause) {
1546
super(problemDescriptor.getFullName() + ": " + description, cause);
1480
1548
// Note that problemDescriptor may be partially uninitialized, so we
1481
1549
// don't want to expose it directly to the user. So, we only provide
1482
1550
// the name and the original proto.
1483
this.name = problemDescriptor.getFullName();
1484
this.proto = problemDescriptor.toProto();
1551
name = problemDescriptor.getFullName();
1552
proto = problemDescriptor.toProto();
1485
1553
this.description = description;
1488
private DescriptorValidationException(FileDescriptor problemDescriptor,
1489
String description) {
1556
private DescriptorValidationException(
1557
final FileDescriptor problemDescriptor,
1558
final String description) {
1490
1559
super(problemDescriptor.getName() + ": " + description);
1492
1561
// Note that problemDescriptor may be partially uninitialized, so we
1493
1562
// don't want to expose it directly to the user. So, we only provide
1494
1563
// the name and the original proto.
1495
this.name = problemDescriptor.getName();
1496
this.proto = problemDescriptor.toProto();
1564
name = problemDescriptor.getName();
1565
proto = problemDescriptor.toProto();
1497
1566
this.description = description;
1505
1574
* descriptors defined in a particular file.
1507
1576
private static final class DescriptorPool {
1508
DescriptorPool(FileDescriptor[] dependencies) {
1577
DescriptorPool(final FileDescriptor[] dependencies) {
1509
1578
this.dependencies = new DescriptorPool[dependencies.length];
1511
1580
for (int i = 0; i < dependencies.length; i++) {
1512
1581
this.dependencies[i] = dependencies[i].pool;
1515
for (int i = 0; i < dependencies.length; i++) {
1584
for (final FileDescriptor dependency : dependencies) {
1517
addPackage(dependencies[i].getPackage(), dependencies[i]);
1586
addPackage(dependency.getPackage(), dependency);
1518
1587
} catch (DescriptorValidationException e) {
1519
1588
// Can't happen, because addPackage() only fails when the name
1520
1589
// conflicts with a non-package, but we have not yet added any
1527
final DescriptorPool[] dependencies;
1596
private final DescriptorPool[] dependencies;
1529
final Map<String, GenericDescriptor> descriptorsByName =
1598
private final Map<String, GenericDescriptor> descriptorsByName =
1530
1599
new HashMap<String, GenericDescriptor>();
1531
final Map<DescriptorIntPair, FieldDescriptor> fieldsByNumber =
1600
private final Map<DescriptorIntPair, FieldDescriptor> fieldsByNumber =
1532
1601
new HashMap<DescriptorIntPair, FieldDescriptor>();
1533
final Map<DescriptorIntPair, EnumValueDescriptor> enumValuesByNumber =
1534
new HashMap<DescriptorIntPair, EnumValueDescriptor>();
1602
private final Map<DescriptorIntPair, EnumValueDescriptor> enumValuesByNumber
1603
= new HashMap<DescriptorIntPair, EnumValueDescriptor>();
1536
1605
/** Find a generic descriptor by fully-qualified name. */
1537
GenericDescriptor findSymbol(String fullName) {
1606
GenericDescriptor findSymbol(final String fullName) {
1538
1607
GenericDescriptor result = descriptorsByName.get(fullName);
1539
if (result != null) return result;
1608
if (result != null) {
1541
for (int i = 0; i < dependencies.length; i++) {
1542
result = dependencies[i].descriptorsByName.get(fullName);
1543
if (result != null) return result;
1612
for (final DescriptorPool dependency : dependencies) {
1613
result = dependency.descriptorsByName.get(fullName);
1614
if (result != null) {
1552
1625
* partially-qualified, or unqualified. C++-like name lookup semantics
1553
1626
* are used to search for the matching descriptor.
1555
GenericDescriptor lookupSymbol(String name,
1556
GenericDescriptor relativeTo)
1628
GenericDescriptor lookupSymbol(final String name,
1629
final GenericDescriptor relativeTo)
1557
1630
throws DescriptorValidationException {
1558
1631
// TODO(kenton): This could be optimized in a number of ways.
1575
1648
// We will search each parent scope of "relativeTo" looking for the
1577
StringBuilder scopeToTry = new StringBuilder(relativeTo.getFullName());
1650
final StringBuilder scopeToTry =
1651
new StringBuilder(relativeTo.getFullName());
1580
1654
// Chop off the last component of the scope.
1581
int dotpos = scopeToTry.lastIndexOf(".");
1655
final int dotpos = scopeToTry.lastIndexOf(".");
1582
1656
if (dotpos == -1) {
1583
1657
result = findSymbol(name);
1619
1693
* Adds a symbol to the symbol table. If a symbol with the same name
1620
1694
* already exists, throws an error.
1622
void addSymbol(GenericDescriptor descriptor)
1696
void addSymbol(final GenericDescriptor descriptor)
1623
1697
throws DescriptorValidationException {
1624
1698
validateSymbolName(descriptor);
1626
String fullName = descriptor.getFullName();
1627
int dotpos = fullName.lastIndexOf('.');
1700
final String fullName = descriptor.getFullName();
1701
final int dotpos = fullName.lastIndexOf('.');
1629
GenericDescriptor old = descriptorsByName.put(fullName, descriptor);
1703
final GenericDescriptor old = descriptorsByName.put(fullName, descriptor);
1630
1704
if (old != null) {
1631
1705
descriptorsByName.put(fullName, old);
1633
1707
if (descriptor.getFile() == old.getFile()) {
1634
1708
if (dotpos == -1) {
1635
1709
throw new DescriptorValidationException(descriptor,
1636
"\"" + fullName + "\" is already defined.");
1710
'\"' + fullName + "\" is already defined.");
1638
1712
throw new DescriptorValidationException(descriptor,
1639
"\"" + fullName.substring(dotpos + 1) +
1713
'\"' + fullName.substring(dotpos + 1) +
1640
1714
"\" is already defined in \"" +
1641
1715
fullName.substring(0, dotpos) + "\".");
1644
1718
throw new DescriptorValidationException(descriptor,
1645
"\"" + fullName + "\" is already defined in file \"" +
1719
'\"' + fullName + "\" is already defined in file \"" +
1646
1720
old.getFile().getName() + "\".");
1653
1727
* just as placeholders so that someone cannot define, say, a message type
1654
1728
* that has the same name as an existing package.
1656
static final class PackageDescriptor implements GenericDescriptor {
1730
private static final class PackageDescriptor implements GenericDescriptor {
1657
1731
public Message toProto() { return file.toProto(); }
1658
1732
public String getName() { return name; }
1659
1733
public String getFullName() { return fullName; }
1660
1734
public FileDescriptor getFile() { return file; }
1662
PackageDescriptor(String name, String fullName, FileDescriptor file) {
1736
PackageDescriptor(final String name, final String fullName,
1737
final FileDescriptor file) {
1663
1738
this.file = file;
1664
1739
this.fullName = fullName;
1665
1740
this.name = name;
1670
FileDescriptor file;
1743
private final String name;
1744
private final String fullName;
1745
private final FileDescriptor file;
1676
1751
* under the same name, an exception is thrown. If the package has
1677
1752
* multiple components, this also adds the parent package(s).
1679
void addPackage(String fullName, FileDescriptor file)
1754
void addPackage(final String fullName, final FileDescriptor file)
1680
1755
throws DescriptorValidationException {
1681
int dotpos = fullName.lastIndexOf('.');
1756
final int dotpos = fullName.lastIndexOf('.');
1684
1761
addPackage(fullName.substring(0, dotpos), file);
1685
1762
name = fullName.substring(dotpos + 1);
1690
GenericDescriptor old =
1765
final GenericDescriptor old =
1691
1766
descriptorsByName.put(fullName,
1692
1767
new PackageDescriptor(name, fullName, file));
1693
1768
if (old != null) {
1694
1769
descriptorsByName.put(fullName, old);
1695
1770
if (!(old instanceof PackageDescriptor)) {
1696
1771
throw new DescriptorValidationException(file,
1697
"\"" + name + "\" is already defined (as something other than a " +
1698
"package) in file \"" + old.getFile().getName() + "\".");
1772
'\"' + name + "\" is already defined (as something other than a "
1773
+ "package) in file \"" + old.getFile().getName() + "\".");
1703
1778
/** A (GenericDescriptor, int) pair, used as a map key. */
1704
static final class DescriptorIntPair {
1705
final GenericDescriptor descriptor;
1779
private static final class DescriptorIntPair {
1780
private final GenericDescriptor descriptor;
1781
private final int number;
1708
DescriptorIntPair(GenericDescriptor descriptor, int number) {
1783
DescriptorIntPair(final GenericDescriptor descriptor, final int number) {
1709
1784
this.descriptor = descriptor;
1710
1785
this.number = number;
1713
1789
public int hashCode() {
1714
1790
return descriptor.hashCode() * ((1 << 16) - 1) + number;
1716
public boolean equals(Object obj) {
1717
if (!(obj instanceof DescriptorIntPair)) return false;
1718
DescriptorIntPair other = (DescriptorIntPair)obj;
1793
public boolean equals(final Object obj) {
1794
if (!(obj instanceof DescriptorIntPair)) {
1797
final DescriptorIntPair other = (DescriptorIntPair)obj;
1719
1798
return descriptor == other.descriptor && number == other.number;
1724
1803
* Adds a field to the fieldsByNumber table. Throws an exception if a
1725
1804
* field with hte same containing type and number already exists.
1727
void addFieldByNumber(FieldDescriptor field)
1806
void addFieldByNumber(final FieldDescriptor field)
1728
1807
throws DescriptorValidationException {
1729
DescriptorIntPair key =
1808
final DescriptorIntPair key =
1730
1809
new DescriptorIntPair(field.getContainingType(), field.getNumber());
1731
FieldDescriptor old = fieldsByNumber.put(key, field);
1810
final FieldDescriptor old = fieldsByNumber.put(key, field);
1732
1811
if (old != null) {
1733
1812
fieldsByNumber.put(key, old);
1734
1813
throw new DescriptorValidationException(field,
1744
1823
* with the same type and number already exists, does nothing. (This is
1745
1824
* allowed; the first value define with the number takes precedence.)
1747
void addEnumValueByNumber(EnumValueDescriptor value) {
1748
DescriptorIntPair key =
1826
void addEnumValueByNumber(final EnumValueDescriptor value) {
1827
final DescriptorIntPair key =
1749
1828
new DescriptorIntPair(value.getType(), value.getNumber());
1750
EnumValueDescriptor old = enumValuesByNumber.put(key, value);
1829
final EnumValueDescriptor old = enumValuesByNumber.put(key, value);
1751
1830
if (old != null) {
1752
1831
enumValuesByNumber.put(key, old);
1753
1832
// Not an error: Multiple enum values may have the same number, but
1759
1838
* Verifies that the descriptor's name is valid (i.e. it contains only
1760
1839
* letters, digits, and underscores, and does not start with a digit).
1762
void validateSymbolName(GenericDescriptor descriptor)
1763
throws DescriptorValidationException {
1764
String name = descriptor.getName();
1841
static void validateSymbolName(final GenericDescriptor descriptor)
1842
throws DescriptorValidationException {
1843
final String name = descriptor.getName();
1765
1844
if (name.length() == 0) {
1766
1845
throw new DescriptorValidationException(descriptor, "Missing name.");
1768
1847
boolean valid = true;
1769
1848
for (int i = 0; i < name.length(); i++) {
1770
char c = name.charAt(i);
1849
final char c = name.charAt(i);
1771
1850
// Non-ASCII characters are not valid in protobuf identifiers, even
1772
1851
// if they are letters or digits.
1773
1852
if (c >= 128) {