@@ -27,10 +27,27 @@ class MessageGenerator extends ProtobufContainer {
2727 /// The name of the Dart class to generate.
2828 final String classname;
2929
30- /// The fully-qualified name of the message type.
30+ /// The fully-qualified name of the message (without any leading '.').
31+ final String fullName;
32+
33+ /// The part of the fully qualified name that comes after the package prefix.
34+ ///
35+ /// For nested messages this will include the names of the parents.
3136 ///
32- /// (Used as a unique key and in error messages, not in Dart code.)
33- final String fqname;
37+ /// For example:
38+ /// ```
39+ /// package foo;
40+ ///
41+ /// message Container {
42+ /// message Nested {
43+ /// int32 int32_value = 1;
44+ /// }
45+ /// }
46+ /// ```
47+ /// The nested message will have a `fullName` of 'foo.Container.Nested', and a
48+ /// `messageName` of 'Container.Nested'.
49+ String get messageName =>
50+ fullName.substring (package.length == 0 ? 0 : package.length + 1 );
3451
3552 final PbMixin mixin ;
3653
@@ -48,11 +65,10 @@ class MessageGenerator extends ProtobufContainer {
4865 : _descriptor = descriptor,
4966 _parent = parent,
5067 classname = messageClassName (descriptor, parent: parent.classname),
51- fqname = (parent == null || parent.fqname == null )
68+ assert (parent != null ),
69+ fullName = parent.fullName == ''
5270 ? descriptor.name
53- : (parent.fqname == '.'
54- ? '.${descriptor .name }'
55- : '${parent .fqname }.${descriptor .name }' ),
71+ : '${parent .fullName }.${descriptor .name }' ,
5672 mixin = _getMixin (descriptor, parent.fileGen.descriptor, declaredMixins,
5773 defaultMixin) {
5874 for (EnumDescriptorProto e in _descriptor.enumType) {
@@ -77,7 +93,7 @@ class MessageGenerator extends ProtobufContainer {
7793 /// Throws an exception if [resolve] hasn't been called yet.
7894 void checkResolved () {
7995 if (_fieldList == null ) {
80- throw new StateError ("message not resolved: ${fqname }" );
96+ throw new StateError ("message not resolved: ${fullName }" );
8197 }
8298 }
8399
@@ -103,7 +119,7 @@ class MessageGenerator extends ProtobufContainer {
103119
104120 // Registers message and enum types that can be used elsewhere.
105121 void register (GenerationContext ctx) {
106- ctx.registerFieldType (fqname, this );
122+ ctx.registerFieldType (this );
107123 for (var m in _messageGenerators) {
108124 m.register (ctx);
109125 }
@@ -205,11 +221,15 @@ class MessageGenerator extends ProtobufContainer {
205221 mixinClause = ' with ${mixinNames .join (", " )}' ;
206222 }
207223
224+ String packageClause = package == ''
225+ ? ''
226+ : ', package: const $_protobufImportPrefix .PackageName(\' $package \' )' ;
208227 out.addBlock (
209228 'class ${classname } extends $_protobufImportPrefix .GeneratedMessage${mixinClause } {' ,
210229 '}' , () {
211230 out.addBlock (
212- 'static final $_protobufImportPrefix .BuilderInfo _i = new $_protobufImportPrefix .BuilderInfo(\' ${classname }\' )' ,
231+ 'static final $_protobufImportPrefix .BuilderInfo _i = '
232+ 'new $_protobufImportPrefix .BuilderInfo(\' ${messageName }\' $packageClause )' ,
213233 ';' , () {
214234 for (ProtobufField field in _fieldList) {
215235 var dartFieldName = field.memberNames.fieldName;
@@ -255,9 +275,12 @@ class MessageGenerator extends ProtobufContainer {
255275 out.println ('static ${classname } _defaultInstance;' );
256276 out.addBlock ('static void $checkItem ($classname v) {' , '}' , () {
257277 out.println ('if (v is! $classname )'
258- " $_protobufImportPrefix .checkItemFailed(v, '$ classname ' );" );
278+ " $_protobufImportPrefix .checkItemFailed(v, _i.messageName );" );
259279 });
260280 generateFieldsAccessorsMutators (out);
281+ if (fullName == 'google.protobuf.Any' ) {
282+ generateAnyMethods (out);
283+ }
261284 });
262285 out.println ();
263286 }
@@ -271,7 +294,7 @@ class MessageGenerator extends ProtobufContainer {
271294 bool _hasRequiredFields (MessageGenerator type, Set alreadySeen) {
272295 if (type._fieldList == null ) throw new StateError ("message not resolved" );
273296
274- if (alreadySeen.contains (type.fqname )) {
297+ if (alreadySeen.contains (type.fullName )) {
275298 // The type is already in cache. This means that either:
276299 // a. The type has no required fields.
277300 // b. We are in the midst of checking if the type has required fields,
@@ -282,7 +305,7 @@ class MessageGenerator extends ProtobufContainer {
282305 // here.
283306 return false ;
284307 }
285- alreadySeen.add (type.fqname );
308+ alreadySeen.add (type.fullName );
286309 // If the type has extensions, an extension with message type could contain
287310 // required fields, so we have to be conservative and assume such an
288311 // extension exists.
@@ -304,6 +327,45 @@ class MessageGenerator extends ProtobufContainer {
304327 return false ;
305328 }
306329
330+ /// Generates methods for the Any message class for packing and unpacking
331+ /// values.
332+ void generateAnyMethods (IndentingWriter out) {
333+ out.println ('''
334+ /// Unpacks the message in [value] into [instance].
335+ ///
336+ /// Throws a [InvalidProtocolBufferException] if [typeUrl] does not correspond
337+ /// to the type of [instance].
338+ ///
339+ /// A typical usage would be `any.unpackInto(new Message())`.
340+ ///
341+ /// Returns [instance].
342+ T unpackInto<T extends $_protobufImportPrefix .GeneratedMessage>(T instance,
343+ {$_protobufImportPrefix .ExtensionRegistry extensionRegistry = $_protobufImportPrefix .ExtensionRegistry.EMPTY}) {
344+ $_protobufImportPrefix .unpackIntoHelper(value, instance, typeUrl,
345+ extensionRegistry: extensionRegistry);
346+ return instance;
347+ }
348+
349+ /// Returns `true` if the encoded message matches the type of [instance].
350+ ///
351+ /// Can be used with a default instance:
352+ /// `any.canUnpackInto(Message.getDefault())`
353+ bool canUnpackInto($_protobufImportPrefix .GeneratedMessage instance) {
354+ return $_protobufImportPrefix .canUnpackIntoHelper(instance, typeUrl);
355+ }
356+
357+ /// Creates a new [Any] encoding [message].
358+ ///
359+ /// The [typeUrl] will be [typeUrlPrefix]/`fullName` where `fullName` is
360+ /// the fully qualified name of the type of [message].
361+ static Any pack($_protobufImportPrefix .GeneratedMessage message,
362+ {String typeUrlPrefix = 'type.googleapis.com'}) {
363+ return new Any()
364+ ..value = message.writeToBuffer()
365+ ..typeUrl = '\$ {typeUrlPrefix}/\$ {message.info_.messageName}';
366+ }''' );
367+ }
368+
307369 void generateFieldsAccessorsMutators (IndentingWriter out) {
308370 for (ProtobufField field in _fieldList) {
309371 out.println ();
@@ -324,15 +386,15 @@ class MessageGenerator extends ProtobufContainer {
324386
325387 if (field.isRepeated) {
326388 if (field.overridesSetter) {
327- throw 'Field ${field .fqname } cannot override a setter for '
389+ throw 'Field ${field .fullName } cannot override a setter for '
328390 '${names .fieldName } because it is repeated.' ;
329391 }
330392 if (field.overridesHasMethod) {
331- throw 'Field ${field .fqname } cannot override '
393+ throw 'Field ${field .fullName } cannot override '
332394 '${names .hasMethodName }() because it is repeated.' ;
333395 }
334396 if (field.overridesClearMethod) {
335- throw 'Field ${field .fqname } cannot override '
397+ throw 'Field ${field .fullName } cannot override '
336398 '${names .clearMethodName }() because it is repeated.' ;
337399 }
338400 } else {
0 commit comments