2525import com .google .protobuf .ByteString ;
2626import com .google .protobuf .CodedInputStream ;
2727import com .google .protobuf .ExtensionRegistryLite ;
28+ import com .google .protobuf .Internal .EnumLite ;
2829import com .google .protobuf .InvalidProtocolBufferException ;
2930import com .google .protobuf .MessageLite ;
3031import com .google .protobuf .WireFormat ;
3132import dev .cel .common .annotations .Internal ;
3233import dev .cel .common .internal .CelLiteDescriptorPool ;
3334import dev .cel .common .internal .WellKnownProto ;
35+ import dev .cel .protobuf .CelLiteDescriptor ;
3436import dev .cel .protobuf .CelLiteDescriptor .FieldLiteDescriptor ;
3537import dev .cel .protobuf .CelLiteDescriptor .FieldLiteDescriptor .EncodingType ;
3638import dev .cel .protobuf .CelLiteDescriptor .FieldLiteDescriptor .JavaType ;
@@ -118,34 +120,39 @@ private Object readLengthDelimitedField(
118120 return CelByteString .of (inputStream .readByteArray ());
119121 case MESSAGE :
120122 return mergeOrReadMessageField (
121- inputStream .readBytes (), fieldDescriptor .getFieldProtoTypeName (), existingValue );
123+ inputStream .readBytes (),
124+ fieldDescriptor .getFieldProtoTypeName (),
125+ existingValue ,
126+ /* isView= */ true );
122127 case STRING :
123128 return inputStream .readStringRequireUtf8 ();
124129 default :
125130 throw new IllegalStateException ("Unexpected field type: " + fieldType );
126131 }
127132 }
128133
134+ // Reads bytes of their own, not a view of another message's.
129135 private Object readMessageField (ByteString bytes , String fieldProtoTypeName ) {
130- return mergeOrReadMessageField (bytes , fieldProtoTypeName , /* existingValue= */ null );
136+ return mergeOrReadMessageField (
137+ bytes , fieldProtoTypeName , /* existingValue= */ null , /* isView= */ false );
131138 }
132139
133140 private Object mergeOrReadMessageField (
134- ByteString bytes , String fieldProtoTypeName , @ Nullable Object existingValue ) {
141+ ByteString bytes , String fieldProtoTypeName , @ Nullable Object existingValue , boolean isView ) {
135142 MessageLiteDescriptor descriptor =
136143 descriptorPool .findDescriptor (fieldProtoTypeName ).orElse (null );
137144 if (descriptor == null ) {
138145 if (existingValue instanceof RawProtoMessageLiteValue ) {
139146 bytes = ((RawProtoMessageLiteValue ) existingValue ).toByteString ().concat (bytes );
140147 }
141- return RawProtoMessageLiteValue .create (bytes , fieldProtoTypeName , this , /* isView= */ true );
148+ return RawProtoMessageLiteValue .create (bytes , fieldProtoTypeName , this , isView );
142149 }
143150 WellKnownProto wellKnownProto = WellKnownProto .getByTypeName (fieldProtoTypeName ).orElse (null );
144151 if (isStructLike (wellKnownProto )) {
145152 if (existingValue instanceof ProtoMessageLiteValue ) {
146153 bytes = ((ProtoMessageLiteValue ) existingValue ).toByteString ().concat (bytes );
147154 }
148- return ProtoMessageLiteValue .create (bytes , fieldProtoTypeName , this );
155+ return ProtoMessageLiteValue .create (bytes , descriptor , this );
149156 }
150157 if (existingValue instanceof MessageLite ) {
151158 return mergeMessageLite (((MessageLite ) existingValue ).toBuilder (), bytes , fieldProtoTypeName );
@@ -169,18 +176,7 @@ private Optional<FieldLiteDescriptor> findFieldDescriptor(String protoTypeName,
169176 .flatMap (desc -> desc .findByFieldNumber (fieldNumber ));
170177 }
171178
172- Optional <FieldLiteDescriptor > findFieldDescriptor (String protoTypeName , String fieldName ) {
173- return descriptorPool
174- .findDescriptor (protoTypeName )
175- .flatMap (desc -> desc .findByFieldName (fieldName ));
176- }
177-
178- MessageLite parseMessageLite (ByteString bytes , String protoTypeName ) {
179- MessageLiteDescriptor descriptor = descriptorPool .getDescriptorOrThrow (protoTypeName );
180- return parseMessageLite (bytes , descriptor );
181- }
182-
183- private static MessageLite parseMessageLite (ByteString bytes , MessageLiteDescriptor descriptor ) {
179+ static MessageLite parseMessageLite (ByteString bytes , MessageLiteDescriptor descriptor ) {
184180 if (bytes .isEmpty ()) {
185181 return descriptor .newMessageBuilder ().getDefaultInstanceForType ();
186182 }
@@ -216,7 +212,7 @@ private Object toRuntimeValue(MessageLite msg, MessageLiteDescriptor descriptor)
216212 WellKnownProto wellKnownProto =
217213 WellKnownProto .getByTypeName (descriptor .getProtoTypeName ()).orElse (null );
218214 if (isStructLike (wellKnownProto )) {
219- return ProtoMessageLiteValue .create (msg , descriptor . getProtoTypeName () , this );
215+ return ProtoMessageLiteValue .create (msg , descriptor , this );
220216 }
221217
222218 return fromWellKnownProto (msg , checkNotNull (wellKnownProto ));
@@ -464,6 +460,120 @@ boolean hasFieldByNumber(ByteString bytes, String protoTypeName, SelectField fie
464460 return false ;
465461 }
466462
463+ /**
464+ * Reads {@code fieldDescriptor} of {@code message} with its generated getter rather than from
465+ * wire bytes: its CEL value, null if it's absent, or {@link CelLiteDescriptor#NO_GETTER} if it
466+ * can't be read that way.
467+ */
468+ @ SuppressWarnings ("ReferenceEquality" ) // NO_GETTER is a sentinel instance.
469+ @ Nullable Object readFieldByGetter (
470+ ProtoMessageLiteValue message , FieldLiteDescriptor fieldDescriptor ) {
471+ MessageLite msg = message .rawValue ();
472+ if (msg == null ) {
473+ return CelLiteDescriptor .NO_GETTER ;
474+ }
475+ Object value = message .descriptor ().getFieldValue (msg , fieldDescriptor .getFieldNumber ());
476+ if (value == null || value == CelLiteDescriptor .NO_GETTER ) {
477+ return value ;
478+ }
479+ switch (fieldDescriptor .getEncodingType ()) {
480+ case LIST :
481+ List <?> list = (List <?>) value ;
482+ if (list .isEmpty ()) {
483+ return null ;
484+ }
485+ switch (fieldDescriptor .getProtoFieldType ()) {
486+ case INT64 :
487+ case SINT64 :
488+ case SFIXED64 :
489+ case DOUBLE :
490+ case BOOL :
491+ case STRING :
492+ // These elements are their own CEL values, so the immutable list needn't be copied.
493+ return CelPreAdaptedList .wrap (list );
494+ default :
495+ break ;
496+ }
497+ ImmutableList .Builder <Object > listBuilder =
498+ ImmutableList .builderWithExpectedSize (list .size ());
499+ for (int i = 0 ; i < list .size (); i ++) {
500+ listBuilder .add (fromGetterValue (list .get (i ), fieldDescriptor ));
501+ }
502+ return listBuilder .build ();
503+ case MAP :
504+ Map <?, ?> map = (Map <?, ?>) value ;
505+ if (map .isEmpty ()) {
506+ return null ;
507+ }
508+ MessageLiteDescriptor entryDescriptor =
509+ descriptorPool .getDescriptorOrThrow (fieldDescriptor .getFieldProtoTypeName ());
510+ FieldLiteDescriptor keyDescriptor =
511+ entryDescriptor .getByFieldNumberOrThrow (MAP_KEY_FIELD_NUMBER );
512+ FieldLiteDescriptor valueDescriptor =
513+ entryDescriptor .getByFieldNumberOrThrow (MAP_VALUE_FIELD_NUMBER );
514+ ImmutableMap .Builder <Object , Object > mapBuilder =
515+ ImmutableMap .builderWithExpectedSize (map .size ());
516+ for (Map .Entry <?, ?> entry : map .entrySet ()) {
517+ mapBuilder .put (
518+ fromGetterValue (entry .getKey (), keyDescriptor ),
519+ fromGetterValue (entry .getValue (), valueDescriptor ));
520+ }
521+ return mapBuilder .buildOrThrow ();
522+ case SINGULAR :
523+ return fromGetterValue (value , fieldDescriptor );
524+ }
525+ throw new IllegalStateException (
526+ "Unexpected encoding type: " + fieldDescriptor .getEncodingType ());
527+ }
528+
529+ /** Like {@link #hasFieldByNumber}, through the field's generated getter if it has one. */
530+ @ SuppressWarnings ("ReferenceEquality" ) // NO_GETTER is a sentinel instance.
531+ Object hasByGetter (ProtoMessageLiteValue message , SelectField field ) {
532+ MessageLite msg = message .rawValue ();
533+ if (msg == null ) {
534+ return CelLiteDescriptor .NO_GETTER ;
535+ }
536+ Object value = message .descriptor ().getFieldValue (msg , field .fieldNumber ());
537+ if (value == CelLiteDescriptor .NO_GETTER ) {
538+ return value ;
539+ }
540+ if (value instanceof List ) {
541+ return !((List <?>) value ).isEmpty ();
542+ }
543+ if (value instanceof Map ) {
544+ return !((Map <?, ?>) value ).isEmpty ();
545+ }
546+ return value != null ;
547+ }
548+
549+ /** Converts a field's (or element's) Java value as returned by its getter to its CEL value. */
550+ private Object fromGetterValue (Object value , FieldLiteDescriptor fieldDescriptor ) {
551+ switch (fieldDescriptor .getProtoFieldType ()) {
552+ case UINT32 :
553+ case FIXED32 :
554+ return UnsignedLong .fromLongBits (Integer .toUnsignedLong ((Integer ) value ));
555+ case UINT64 :
556+ case FIXED64 :
557+ return UnsignedLong .fromLongBits ((Long ) value );
558+ case ENUM :
559+ // Open enums are read as their numbers; closed ones as enum constants.
560+ return value instanceof Integer
561+ ? ((Integer ) value ).longValue ()
562+ : (long ) ((EnumLite ) value ).getNumber ();
563+ case MESSAGE :
564+ MessageLite message = (MessageLite ) value ;
565+ MessageLiteDescriptor descriptor = descriptorPool .findDescriptor (message ).orElse (null );
566+ // A submessage whose class has no descriptor is read from its own bytes, not its root's:
567+ // by its type's descriptor if the pool has one for another class (such as an older
568+ // version of it), or else descriptorless.
569+ return descriptor != null
570+ ? toRuntimeValue (message , descriptor )
571+ : readMessageField (message .toByteString (), fieldDescriptor .getFieldProtoTypeName ());
572+ default :
573+ return super .toRuntimeValue (value );
574+ }
575+ }
576+
467577 /** Describes {@code field} by the type information it carries, built once and kept on it. */
468578 private static FieldLiteDescriptor newFieldDescriptor (SelectField field ) {
469579 Object cached = field .liteFieldDescriptor ();
0 commit comments