Skip to content

Fix CEL bindings for maps for this variable #278

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 1, 2025
Merged
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
17 changes: 0 additions & 17 deletions conformance/expected-failures.yaml
Original file line number Diff line number Diff line change
@@ -1,17 +0,0 @@
custom_rules:
- field_expression/map/enum/invalid
- field_expression/map/enum/valid
- field_expression/map/message/invalid
- field_expression/map/message/valid
- field_expression/map/bool/valid
- field_expression/map/bool/invalid
- field_expression/map/string/valid
- field_expression/map/string/invalid
- field_expression/map/int32/valid
- field_expression/map/int32/invalid
- field_expression/map/uint32/valid
- field_expression/map/uint32/invalid
- field_expression/map/int64/valid
- field_expression/map/int64/invalid
- field_expression/map/uint64/valid
- field_expression/map/uint64/invalid
35 changes: 35 additions & 0 deletions src/main/java/build/buf/protovalidate/ObjectValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ public Message messageValue() {
@Override
public <T> T value(Class<T> clazz) {
Descriptors.FieldDescriptor.Type type = fieldDescriptor.getType();
if (fieldDescriptor.isMapField()) {
return clazz.cast(mapValueAsObject());
}
if (!fieldDescriptor.isRepeated()
&& (type == Descriptors.FieldDescriptor.Type.UINT32
|| type == Descriptors.FieldDescriptor.Type.UINT64
Expand Down Expand Up @@ -93,6 +96,38 @@ public List<Value> repeatedValue() {
return out;
}

// TODO - This should be refactored at some point.
//
// This is essentially the same functionality as `mapValue` except that it
// returns a Map of Objects rather than a Map of protovalidate-java Values.
// It is used for binding to a CEL variable (i.e. `this`).
// Trying to bind a Map of Values to a CEL variable does not work because
// CEL-Java doesn't know how to interpret that proprietary Value object.
//
// Ideally, we should be using CEL-Java's org.projectnessie.cel.common.types.ref.Val
// type instead of our own custom Value abstraction. However, since we are evaluating
// Java CEL implementations, we should probably wait until that decision is made before
// making such a large refactor. This should suffice as a stopgap until then.
private Map<Object, Object> mapValueAsObject() {
List<AbstractMessage> input =
value instanceof List
? (List<AbstractMessage>) value
: Collections.singletonList((AbstractMessage) value);

Descriptors.FieldDescriptor keyDesc = fieldDescriptor.getMessageType().findFieldByNumber(1);
Descriptors.FieldDescriptor valDesc = fieldDescriptor.getMessageType().findFieldByNumber(2);
Map<Object, Object> out = new HashMap<>(input.size());

for (AbstractMessage entry : input) {
Object keyValue = entry.getField(keyDesc);
Object valValue = entry.getField(valDesc);

out.put(keyValue, valValue);
}

return out;
}

@Override
public Map<Value, Value> mapValue() {
List<AbstractMessage> input =
Expand Down