1616
1717import static com .google .common .base .Preconditions .checkNotNull ;
1818
19- import com .google .common .annotations .VisibleForTesting ;
2019import com .google .common .base .Defaults ;
2120import com .google .common .collect .ImmutableList ;
2221import com .google .common .collect .ImmutableMap ;
5958@ Immutable
6059@ Internal
6160public final class ProtoLiteCelValueConverter extends BaseProtoCelValueConverter {
62- private static final String MAP_KEY_FIELD_NAME = "key" ;
63- private static final String MAP_VALUE_FIELD_NAME = "value" ;
6461 private static final int MAP_KEY_FIELD_NUMBER = 1 ;
6562 private static final int MAP_VALUE_FIELD_NUMBER = 2 ;
6663
@@ -316,19 +313,52 @@ private Map.Entry<Object, Object> readSingleMapEntry(
316313 */
317314 @ Nullable Object readSingleField (ByteString bytes , FieldLiteDescriptor fieldDescriptor )
318315 throws IOException {
316+ return scanField (bytes , fieldDescriptor , null , null );
317+ }
318+
319+ /** Scans for {@code fieldDescriptor}; null map entry descriptors are looked up in the pool. */
320+ private @ Nullable Object scanField (
321+ ByteString bytes ,
322+ FieldLiteDescriptor fieldDescriptor ,
323+ @ Nullable FieldLiteDescriptor keyDescriptor ,
324+ @ Nullable FieldLiteDescriptor valueDescriptor )
325+ throws IOException {
319326 CodedInputStream inputStream = bytes .newCodedInput ();
320327 int targetFieldNumber = fieldDescriptor .getFieldNumber ();
321328 Object fieldValue = null ;
322329 for (int tag = inputStream .readTag (); tag != 0 ; tag = inputStream .readTag ()) {
323- int fieldNumber = WireFormat .getTagFieldNumber (tag );
324- if (fieldNumber != targetFieldNumber ) {
330+ if (WireFormat .getTagFieldNumber (tag ) != targetFieldNumber ) {
325331 skipWireField (tag , inputStream );
326332 continue ;
327333 }
328334 int tagWireType = WireFormat .getTagWireType (tag );
329- fieldValue = readFieldValue (tagWireType , inputStream , fieldDescriptor , fieldValue );
335+ switch (fieldDescriptor .getEncodingType ()) {
336+ case SINGULAR :
337+ fieldValue = readSingularField (tagWireType , inputStream , fieldDescriptor , fieldValue );
338+ break ;
339+ case LIST :
340+ fieldValue = readRepeatedField (tagWireType , inputStream , fieldDescriptor , fieldValue );
341+ break ;
342+ case MAP :
343+ if (keyDescriptor == null ) {
344+ // Looked up at the first entry since an absent map needs no entry descriptor.
345+ MessageLiteDescriptor entryDescriptor =
346+ descriptorPool .getDescriptorOrThrow (fieldDescriptor .getFieldProtoTypeName ());
347+ keyDescriptor = entryDescriptor .getByFieldNumberOrThrow (MAP_KEY_FIELD_NUMBER );
348+ valueDescriptor = entryDescriptor .getByFieldNumberOrThrow (MAP_VALUE_FIELD_NUMBER );
349+ }
350+ fieldValue =
351+ readMapField (
352+ tagWireType ,
353+ inputStream ,
354+ fieldDescriptor ,
355+ keyDescriptor ,
356+ valueDescriptor ,
357+ fieldValue );
358+ break ;
359+ }
330360 }
331- return fieldValue == null ? null : resolveFieldValue ( finalizeFieldValue (fieldValue ) );
361+ return fieldValue == null ? null : finalizeFieldValue (fieldValue );
332362 }
333363
334364 boolean hasSingleField (ByteString bytes , FieldLiteDescriptor fieldDescriptor ) throws IOException {
@@ -394,71 +424,37 @@ boolean hasFieldByNumber(ByteString bytes, SelectField field) throws IOException
394424
395425 private @ Nullable Object readFieldByNumber (ByteString bytes , SelectField field )
396426 throws IOException {
397- FieldLiteDescriptor fieldDescriptor = newFieldDescriptor (field );
398427 SelectField .MapEntrySpec mapEntrySpec = field .mapEntrySpec ();
399428 if (mapEntrySpec == null ) {
400- return readSingleField (bytes , fieldDescriptor );
429+ return readSingleField (bytes , newFieldDescriptor ( field ) );
401430 }
402431 // The map entry type has no descriptor either, so its key and value are described by the spec.
403- FieldLiteDescriptor keyDescriptor =
432+ return scanField (
433+ bytes ,
434+ newFieldDescriptor (field ),
404435 newFieldDescriptor (
405- MAP_KEY_FIELD_NUMBER ,
406- MAP_KEY_FIELD_NAME ,
407- EncodingType .SINGULAR ,
408- mapEntrySpec .keyTypeCode (),
409- /* protoTypeName= */ "" );
410- FieldLiteDescriptor valueDescriptor =
436+ MAP_KEY_FIELD_NUMBER , "key" , EncodingType .SINGULAR , mapEntrySpec .keyTypeCode (), "" ),
411437 newFieldDescriptor (
412438 MAP_VALUE_FIELD_NUMBER ,
413- MAP_VALUE_FIELD_NAME ,
439+ "value" ,
414440 EncodingType .SINGULAR ,
415441 mapEntrySpec .valueTypeCode (),
416- field .protoTypeName ());
417- CodedInputStream inputStream = bytes .newCodedInput ();
418- Map <Object , Object > mapValues = null ;
419- for (int tag = inputStream .readTag (); tag != 0 ; tag = inputStream .readTag ()) {
420- if (WireFormat .getTagFieldNumber (tag ) != field .fieldNumber ()) {
421- skipWireField (tag , inputStream );
422- continue ;
423- }
424- mapValues =
425- readMapField (
426- WireFormat .getTagWireType (tag ),
427- inputStream ,
428- fieldDescriptor ,
429- keyDescriptor ,
430- valueDescriptor ,
431- mapValues );
432- }
433- return mapValues == null ? null : resolveFieldValue (finalizeFieldValue (mapValues ));
442+ field .protoTypeName ()));
434443 }
435444
436445 /** Describes {@code field} by the type information it carries. */
437446 private static FieldLiteDescriptor newFieldDescriptor (SelectField field ) {
438- if (field .mapEntrySpec () != null ) {
439- // SelectField doesn't name the map entry type; its protoTypeName() is the map's value type.
440- return newFieldDescriptor (
441- field .fieldNumber (),
442- field .fieldName (),
443- EncodingType .MAP ,
444- SelectField .MESSAGE_TYPE_CODE ,
445- /* protoTypeName= */ "" );
446- }
447- if (field .typeCode () == SelectField .NO_TYPE_CODE ) {
448- // Only presence tests omit the type code. Their presence check doesn't depend on the type,
449- // and the fields they navigate through are always messages.
450- return newFieldDescriptor (
451- field .fieldNumber (),
452- field .fieldName (),
453- EncodingType .SINGULAR ,
454- SelectField .MESSAGE_TYPE_CODE ,
455- /* protoTypeName= */ "" );
456- }
447+ // Only presence tests omit the type code: their presence check doesn't depend on the type, and
448+ // the fields they navigate through are messages, as are map entries.
449+ boolean isMap = field .mapEntrySpec () != null ;
450+ boolean isMessage = isMap || field .typeCode () == SelectField .NO_TYPE_CODE ;
457451 return newFieldDescriptor (
458452 field .fieldNumber (),
459453 field .fieldName (),
460- field .defaultValue () instanceof List ? EncodingType .LIST : EncodingType .SINGULAR ,
461- field .typeCode (),
454+ isMap
455+ ? EncodingType .MAP
456+ : (field .defaultValue () instanceof List ? EncodingType .LIST : EncodingType .SINGULAR ),
457+ isMessage ? SelectField .MESSAGE_TYPE_CODE : field .typeCode (),
462458 field .protoTypeName ());
463459 }
464460
@@ -480,59 +476,29 @@ private static FieldLiteDescriptor newFieldDescriptor(
480476 protoTypeName );
481477 }
482478
483- /** Returns the CEL value of a scanned field, completing any conversion that was deferred. */
484- private Object resolveFieldValue (Object fieldValue ) {
485- if (fieldValue instanceof DeferredConversion ) {
486- return toRuntimeValue (((DeferredConversion ) fieldValue ).value );
487- }
488- return fieldValue ;
489- }
490-
491479 /**
492480 * Converts a value accumulated while scanning a field into its final immutable form.
493481 *
494482 * <p>Repeated and map fields accumulate into mutable containers, which are copied into immutable
495483 * ones. Well-known types other than FieldMask (see {@link #isStructLike}) are kept as parsed
496- * {@link MessageLite}s until the scan completes so that split occurrences can be merged, and
497- * values holding them are wrapped in a {@link DeferredConversion} . All other messages are wrapped
498- * as CEL values as soon as they are read.
484+ * {@link MessageLite}s until the scan completes, so that split occurrences can be merged and map
485+ * values replaced by a repeated key are never converted . All other messages are wrapped as CEL
486+ * values as soon as they are read.
499487 */
500- private static Object finalizeFieldValue (Object accumulatedValue ) {
488+ private Object finalizeFieldValue (Object accumulatedValue ) {
501489 if (accumulatedValue instanceof List ) {
502490 ImmutableList <?> list = ImmutableList .copyOf ((List <?>) accumulatedValue );
503- return Iterables .any (list , MessageLite .class ::isInstance )
504- ? new DeferredConversion (list )
505- : list ;
491+ return Iterables .any (list , MessageLite .class ::isInstance ) ? toRuntimeValue (list ) : list ;
506492 }
507493 if (accumulatedValue instanceof Map ) {
508494 ImmutableMap <?, ?> map = ImmutableMap .copyOf ((Map <?, ?>) accumulatedValue );
509- return Iterables .any (map .values (), MessageLite .class ::isInstance )
510- ? new DeferredConversion (map )
511- : map ;
495+ return Iterables .any (map .values (), MessageLite .class ::isInstance ) ? toRuntimeValue (map ) : map ;
512496 }
513497 return accumulatedValue instanceof MessageLite
514- ? new DeferredConversion (accumulatedValue )
498+ ? toRuntimeValue (accumulatedValue )
515499 : accumulatedValue ;
516500 }
517501
518- private @ Nullable Object readFieldValue (
519- int tagWireType ,
520- CodedInputStream inputStream ,
521- FieldLiteDescriptor fieldDescriptor ,
522- @ Nullable Object existingValue )
523- throws IOException {
524- EncodingType encodingType = fieldDescriptor .getEncodingType ();
525- switch (encodingType ) {
526- case SINGULAR :
527- return readSingularField (tagWireType , inputStream , fieldDescriptor , existingValue );
528- case LIST :
529- return readRepeatedField (tagWireType , inputStream , fieldDescriptor , existingValue );
530- case MAP :
531- return readMapField (tagWireType , inputStream , fieldDescriptor , existingValue );
532- }
533- throw new IllegalStateException ("Unexpected encoding type: " + encodingType );
534- }
535-
536502 private Object readSingularField (
537503 int tagWireType ,
538504 CodedInputStream inputStream ,
@@ -589,23 +555,6 @@ private Object readSingularField(
589555 return repeatedValues ;
590556 }
591557
592- private Map <Object , Object > readMapField (
593- int tagWireType ,
594- CodedInputStream inputStream ,
595- FieldLiteDescriptor fieldDescriptor ,
596- @ Nullable Object existingValue )
597- throws IOException {
598- MessageLiteDescriptor entryDescriptor =
599- descriptorPool .getDescriptorOrThrow (fieldDescriptor .getFieldProtoTypeName ());
600- return readMapField (
601- tagWireType ,
602- inputStream ,
603- fieldDescriptor ,
604- entryDescriptor .getByFieldNameOrThrow (MAP_KEY_FIELD_NAME ),
605- entryDescriptor .getByFieldNameOrThrow (MAP_VALUE_FIELD_NAME ),
606- existingValue );
607- }
608-
609558 // Safe because MAP fields only ever store a LinkedHashMap as their accumulated value.
610559 @ SuppressWarnings ("unchecked" )
611560 private Map <Object , Object > readMapField (
@@ -654,34 +603,13 @@ private static boolean isPackable(FieldLiteDescriptor fieldDescriptor) {
654603 return fieldDescriptor .getProtoFieldType ().toWireFormatFieldType ().isPackable ();
655604 }
656605
657- @ VisibleForTesting
658- static void skipWireField (int tag , CodedInputStream inputStream ) throws IOException {
606+ private static void skipWireField (int tag , CodedInputStream inputStream ) throws IOException {
659607 int tagWireType = WireFormat .getTagWireType (tag );
660- switch (tagWireType ) {
661- case WireFormat .WIRETYPE_VARINT :
662- case WireFormat .WIRETYPE_FIXED64 :
663- case WireFormat .WIRETYPE_LENGTH_DELIMITED :
664- case WireFormat .WIRETYPE_FIXED32 :
665- inputStream .skipField (tag );
666- return ;
667- case WireFormat .WIRETYPE_START_GROUP :
668- case WireFormat .WIRETYPE_END_GROUP :
669- throw new UnsupportedOperationException ("Groups are not supported" );
670- default :
671- throw new IllegalArgumentException ("Unknown wire type: " + tagWireType );
672- }
673- }
674-
675- /**
676- * A field value holding well-known type messages, whose conversion to CEL values is deferred
677- * until {@link #resolveFieldValue}.
678- */
679- private static final class DeferredConversion {
680- private final Object value ;
681-
682- private DeferredConversion (Object value ) {
683- this .value = checkNotNull (value );
608+ if (tagWireType == WireFormat .WIRETYPE_START_GROUP
609+ || tagWireType == WireFormat .WIRETYPE_END_GROUP ) {
610+ throw new UnsupportedOperationException ("Groups are not supported" );
684611 }
612+ inputStream .skipField (tag );
685613 }
686614
687615 private ProtoLiteCelValueConverter (CelLiteDescriptorPool celLiteDescriptorPool ) {
0 commit comments