Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -193,14 +193,29 @@ private static Object decodeWireField(
fieldDescriptor != null
? fieldDescriptor.getEncodingType() == EncodingType.LIST
: field.defaultValue() instanceof List;
String protoTypeName =
fieldDescriptor != null
? fieldDescriptor.getFieldProtoTypeName()
: UNKNOWN_MESSAGE_TYPE_NAME;
String protoTypeName = resolveProtoTypeName(field, fieldDescriptor);

return decodeWireEntries(unknowns, typeCode, protoTypeName, isRepeated, converter);
}

/**
* Resolves the protobuf message type name for a field.
*
* <p>Prefers the descriptor's message type name when present. Under runtime version skew (where
* the descriptor is omitted), falls back to the type name preserved in {@link SelectField} from
* the optimizer, or {@link #UNKNOWN_MESSAGE_TYPE_NAME} if unspecified.
*/
private static String resolveProtoTypeName(
SelectField field, @Nullable FieldLiteDescriptor fieldDescriptor) {
if (fieldDescriptor != null) {
return fieldDescriptor.getFieldProtoTypeName();
}
if (!field.protoTypeName().isEmpty()) {
return field.protoTypeName();
}
return UNKNOWN_MESSAGE_TYPE_NAME;
}

private static Object resolveDefault(
SelectField field,
@Nullable FieldLiteDescriptor fieldDescriptor,
Expand All @@ -211,7 +226,8 @@ private static Object resolveDefault(

if (fieldDescriptor == null) {
if (field.typeCode() == FieldLiteDescriptor.Type.MESSAGE.getNumber()) {
return create(ByteString.EMPTY, UNKNOWN_MESSAGE_TYPE_NAME, converter);
return create(
ByteString.EMPTY, resolveProtoTypeName(field, /* fieldDescriptor= */ null), converter);
}
throw CelAttributeNotFoundException.forFieldResolution(field.fieldName());
}
Expand Down Expand Up @@ -249,6 +265,9 @@ static boolean isPresentInWire(
? fieldDescriptor.getProtoFieldType().getNumber()
: field.typeCode();

// In protobuf wire format, a zero-length entry for a singular field (e.g. empty string,
// bytes, or empty submessage) represents explicit presence on the wire. Only packed repeated
// fields with empty payload represent an empty/absent collection.
if (!isRepeated) {
return true;
}
Expand Down
37 changes: 35 additions & 2 deletions common/src/main/java/dev/cel/common/values/SelectField.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ public abstract class SelectField {
*/
public abstract @Nullable Object defaultValue();

/**
* Protobuf message type name of this hop (e.g. {@code "google.protobuf.Duration"}, {@code
* "com.example.User"}), or empty string if unknown or not a message field.
*/
public abstract String protoTypeName();

/**
* Creates a presence-test qualifier hop.
*
Expand All @@ -83,7 +89,11 @@ public static SelectField create(long fieldNumber, String fieldName) {
fieldNumber);
checkNotNull(fieldName);
return new AutoValue_SelectField(
(int) fieldNumber, fieldName, NO_TYPE_CODE, /* defaultValue= */ null);
(int) fieldNumber,
fieldName,
NO_TYPE_CODE,
/* defaultValue= */ null,
/* protoTypeName= */ "");
}

/**
Expand All @@ -98,13 +108,36 @@ public static SelectField create(long fieldNumber, String fieldName) {
*/
public static SelectField create(
long fieldNumber, String fieldName, long typeCode, @Nullable Object defaultValue) {
return create(fieldNumber, fieldName, typeCode, defaultValue, /* protoTypeName= */ "");
}

/**
* Creates a fully-specified field selection hop with type code, optional default value, and
* protobuf type name.
*
* @param fieldNumber Protobuf field number. Takes {@code long} for compatibility with CEL's int64
* constant representations.
* @param fieldName Protobuf field name.
* @param typeCode Protobuf wire type code or {@link #CEL_MAP_TYPE_CODE}. Takes {@code long} for
* compatibility with CEL's int64 constant representations.
* @param defaultValue Default value for the field, or null if unspecified.
* @param protoTypeName Protobuf message type name, or empty string if unspecified.
*/
public static SelectField create(
long fieldNumber,
String fieldName,
long typeCode,
@Nullable Object defaultValue,
String protoTypeName) {
checkArgument(
fieldNumber >= 1 && fieldNumber <= MAX_FIELD_NUMBER,
"Field number out of protobuf range: %s",
fieldNumber);
checkNotNull(fieldName);
checkArgument(isSupportedTypeCode(typeCode), "Invalid protobuf type code: %s", typeCode);
return new AutoValue_SelectField((int) fieldNumber, fieldName, (int) typeCode, defaultValue);
checkNotNull(protoTypeName);
return new AutoValue_SelectField(
(int) fieldNumber, fieldName, (int) typeCode, defaultValue, protoTypeName);
}

/**
Expand Down
Loading
Loading