Skip to content

Commit d9a0c2d

Browse files
l46kokcopybara-github
authored andcommitted
Add JSON field name resolution to planner
PiperOrigin-RevId: 872120925
1 parent 1c5e9d9 commit d9a0c2d

File tree

9 files changed

+90
-36
lines changed

9 files changed

+90
-36
lines changed

common/src/main/java/dev/cel/common/values/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ java_library(
191191
":base_proto_cel_value_converter",
192192
":values",
193193
"//:auto_value",
194+
"//common:options",
194195
"//common/annotations",
195196
"//common/internal:cel_descriptor_pools",
196197
"//common/internal:dynamic_proto",

common/src/main/java/dev/cel/common/values/ProtoCelValueConverter.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.google.protobuf.Message;
2727
import com.google.protobuf.MessageLiteOrBuilder;
2828
import com.google.protobuf.MessageOrBuilder;
29+
import dev.cel.common.CelOptions;
2930
import dev.cel.common.annotations.Internal;
3031
import dev.cel.common.internal.CelDescriptorPool;
3132
import dev.cel.common.internal.DynamicProto;
@@ -49,11 +50,12 @@
4950
public final class ProtoCelValueConverter extends BaseProtoCelValueConverter {
5051
private final CelDescriptorPool celDescriptorPool;
5152
private final DynamicProto dynamicProto;
53+
private final CelOptions celOptions;
5254

5355
/** Constructs a new instance of ProtoCelValueConverter. */
5456
public static ProtoCelValueConverter newInstance(
55-
CelDescriptorPool celDescriptorPool, DynamicProto dynamicProto) {
56-
return new ProtoCelValueConverter(celDescriptorPool, dynamicProto);
57+
CelDescriptorPool celDescriptorPool, DynamicProto dynamicProto, CelOptions celOptions) {
58+
return new ProtoCelValueConverter(celDescriptorPool, dynamicProto, celOptions);
5759
}
5860

5961
@Override
@@ -97,7 +99,8 @@ public Object toRuntimeValue(Object value) {
9799
WellKnownProto wellKnownProto =
98100
WellKnownProto.getByTypeName(message.getDescriptorForType().getFullName()).orElse(null);
99101
if (wellKnownProto == null) {
100-
return ProtoMessageValue.create((Message) message, celDescriptorPool, this);
102+
return ProtoMessageValue.create(
103+
message, celDescriptorPool, this, celOptions.enableJsonFieldNames());
101104
}
102105

103106
return fromWellKnownProto(message, wellKnownProto);
@@ -167,10 +170,13 @@ public Object fromProtoMessageFieldToCelValue(Message message, FieldDescriptor f
167170
return toRuntimeValue(result);
168171
}
169172

170-
private ProtoCelValueConverter(CelDescriptorPool celDescriptorPool, DynamicProto dynamicProto) {
173+
private ProtoCelValueConverter(
174+
CelDescriptorPool celDescriptorPool, DynamicProto dynamicProto, CelOptions celOptions) {
171175
Preconditions.checkNotNull(celDescriptorPool);
172176
Preconditions.checkNotNull(dynamicProto);
177+
Preconditions.checkNotNull(celOptions);
173178
this.celDescriptorPool = celDescriptorPool;
174179
this.dynamicProto = dynamicProto;
180+
this.celOptions = celOptions;
175181
}
176182
}

common/src/main/java/dev/cel/common/values/ProtoMessageValue.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ public abstract class ProtoMessageValue extends StructValue<String> {
4040

4141
abstract ProtoCelValueConverter protoCelValueConverter();
4242

43+
abstract boolean enableJsonFieldNames();
44+
4345
@Override
4446
public boolean isZeroValue() {
4547
return value().getDefaultInstanceForType().equals(value());
@@ -75,15 +77,17 @@ public Optional<Object> find(String field) {
7577
public static ProtoMessageValue create(
7678
Message value,
7779
CelDescriptorPool celDescriptorPool,
78-
ProtoCelValueConverter protoCelValueConverter) {
80+
ProtoCelValueConverter protoCelValueConverter,
81+
boolean enableJsonFieldNames) {
7982
Preconditions.checkNotNull(value);
8083
Preconditions.checkNotNull(celDescriptorPool);
8184
Preconditions.checkNotNull(protoCelValueConverter);
8285
return new AutoValue_ProtoMessageValue(
8386
value,
8487
StructTypeReference.create(value.getDescriptorForType().getFullName()),
8588
celDescriptorPool,
86-
protoCelValueConverter);
89+
protoCelValueConverter,
90+
enableJsonFieldNames);
8791
}
8892

8993
private FieldDescriptor findField(
@@ -93,6 +97,14 @@ private FieldDescriptor findField(
9397
return fieldDescriptor;
9498
}
9599

100+
if (enableJsonFieldNames()) {
101+
for (FieldDescriptor fd : descriptor.getFields()) {
102+
if (fd.getJsonName().equals(fieldName)) {
103+
return fd;
104+
}
105+
}
106+
}
107+
96108
return celDescriptorPool
97109
.findExtensionDescriptor(descriptor, fieldName)
98110
.orElseThrow(

common/src/main/java/dev/cel/common/values/ProtoMessageValueProvider.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public class ProtoMessageValueProvider implements CelValueProvider {
3838
private final ProtoAdapter protoAdapter;
3939
private final ProtoMessageFactory protoMessageFactory;
4040
private final ProtoCelValueConverter protoCelValueConverter;
41+
private final CelOptions celOptions;
4142

4243
@Override
4344
public CelValueConverter celValueConverter() {
@@ -72,6 +73,14 @@ private FieldDescriptor findField(Descriptor descriptor, String fieldName) {
7273
return fieldDescriptor;
7374
}
7475

76+
if (celOptions.enableJsonFieldNames()) {
77+
for (FieldDescriptor fd : descriptor.getFields()) {
78+
if (fd.getJsonName().equals(fieldName)) {
79+
return fd;
80+
}
81+
}
82+
}
83+
7584
return protoMessageFactory
7685
.getDescriptorPool()
7786
.findExtensionDescriptor(descriptor, fieldName)
@@ -91,7 +100,9 @@ public static ProtoMessageValueProvider newInstance(
91100
private ProtoMessageValueProvider(CelOptions celOptions, DynamicProto dynamicProto) {
92101
this.protoMessageFactory = dynamicProto.getProtoMessageFactory();
93102
this.protoCelValueConverter =
94-
ProtoCelValueConverter.newInstance(protoMessageFactory.getDescriptorPool(), dynamicProto);
103+
ProtoCelValueConverter.newInstance(
104+
protoMessageFactory.getDescriptorPool(), dynamicProto, celOptions);
95105
this.protoAdapter = new ProtoAdapter(dynamicProto, celOptions);
106+
this.celOptions = celOptions;
96107
}
97108
}

common/src/test/java/dev/cel/common/values/ProtoCelValueConverterTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import static com.google.common.truth.Truth.assertThat;
1818

19+
import dev.cel.common.CelOptions;
1920
import dev.cel.common.internal.DefaultDescriptorPool;
2021
import dev.cel.common.internal.DefaultMessageFactory;
2122
import dev.cel.common.internal.DynamicProto;
@@ -28,7 +29,9 @@ public class ProtoCelValueConverterTest {
2829

2930
private static final ProtoCelValueConverter PROTO_CEL_VALUE_CONVERTER =
3031
ProtoCelValueConverter.newInstance(
31-
DefaultDescriptorPool.INSTANCE, DynamicProto.create(DefaultMessageFactory.INSTANCE));
32+
DefaultDescriptorPool.INSTANCE,
33+
DynamicProto.create(DefaultMessageFactory.INSTANCE),
34+
CelOptions.DEFAULT);
3235

3336
@Test
3437
public void unwrap_nullValue() {

common/src/test/java/dev/cel/common/values/ProtoMessageValueTest.java

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import com.google.testing.junit.testparameterinjector.TestParameterInjector;
3636
import com.google.testing.junit.testparameterinjector.TestParameters;
3737
import dev.cel.common.CelDescriptorUtil;
38+
import dev.cel.common.CelOptions;
3839
import dev.cel.common.internal.CelDescriptorPool;
3940
import dev.cel.common.internal.DefaultDescriptorPool;
4041
import dev.cel.common.internal.DefaultMessageFactory;
@@ -54,15 +55,18 @@ public final class ProtoMessageValueTest {
5455

5556
private static final ProtoCelValueConverter PROTO_CEL_VALUE_CONVERTER =
5657
ProtoCelValueConverter.newInstance(
57-
DefaultDescriptorPool.INSTANCE, DynamicProto.create(DefaultMessageFactory.INSTANCE));
58+
DefaultDescriptorPool.INSTANCE,
59+
DynamicProto.create(DefaultMessageFactory.INSTANCE),
60+
CelOptions.DEFAULT);
5861

5962
@Test
6063
public void emptyProtoMessage() {
6164
ProtoMessageValue protoMessageValue =
6265
ProtoMessageValue.create(
6366
TestAllTypes.getDefaultInstance(),
6467
DefaultDescriptorPool.INSTANCE,
65-
PROTO_CEL_VALUE_CONVERTER);
68+
PROTO_CEL_VALUE_CONVERTER,
69+
/* enableJsonFieldNames= */ false);
6670

6771
assertThat(protoMessageValue.value()).isEqualTo(TestAllTypes.getDefaultInstance());
6872
assertThat(protoMessageValue.isZeroValue()).isTrue();
@@ -74,7 +78,7 @@ public void constructProtoMessage() {
7478
TestAllTypes.newBuilder().setSingleBool(true).setSingleInt64(5L).build();
7579
ProtoMessageValue protoMessageValue =
7680
ProtoMessageValue.create(
77-
testAllTypes, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER);
81+
testAllTypes, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER, false);
7882

7983
assertThat(protoMessageValue.value()).isEqualTo(testAllTypes);
8084
assertThat(protoMessageValue.isZeroValue()).isFalse();
@@ -90,7 +94,7 @@ public void findField_fieldIsSet_fieldExists() {
9094
.build();
9195
ProtoMessageValue protoMessageValue =
9296
ProtoMessageValue.create(
93-
testAllTypes, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER);
97+
testAllTypes, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER, false);
9498

9599
assertThat(protoMessageValue.find("single_bool")).isPresent();
96100
assertThat(protoMessageValue.find("single_int64")).isPresent();
@@ -103,7 +107,8 @@ public void findField_fieldIsUnset_fieldDoesNotExist() {
103107
ProtoMessageValue.create(
104108
TestAllTypes.getDefaultInstance(),
105109
DefaultDescriptorPool.INSTANCE,
106-
PROTO_CEL_VALUE_CONVERTER);
110+
PROTO_CEL_VALUE_CONVERTER,
111+
/* enableJsonFieldNames= */ false);
107112

108113
assertThat(protoMessageValue.find("single_int32")).isEmpty();
109114
assertThat(protoMessageValue.find("single_uint64")).isEmpty();
@@ -116,7 +121,8 @@ public void findField_fieldIsUndeclared_throwsException() {
116121
ProtoMessageValue.create(
117122
TestAllTypes.getDefaultInstance(),
118123
DefaultDescriptorPool.INSTANCE,
119-
PROTO_CEL_VALUE_CONVERTER);
124+
PROTO_CEL_VALUE_CONVERTER,
125+
/* enableJsonFieldNames= */ false);
120126

121127
IllegalArgumentException exception =
122128
assertThrows(IllegalArgumentException.class, () -> protoMessageValue.select("bogus"));
@@ -137,7 +143,7 @@ public void findField_extensionField_success() {
137143
TestAllTypes.newBuilder().setExtension(TestAllTypesExtensions.int32Ext, 1).build();
138144

139145
ProtoMessageValue protoMessageValue =
140-
ProtoMessageValue.create(proto2Message, descriptorPool, PROTO_CEL_VALUE_CONVERTER);
146+
ProtoMessageValue.create(proto2Message, descriptorPool, PROTO_CEL_VALUE_CONVERTER, false);
141147

142148
assertThat(protoMessageValue.find("cel.expr.conformance.proto2.int32_ext")).isPresent();
143149
}
@@ -149,7 +155,7 @@ public void findField_extensionField_throwsWhenDescriptorMissing() {
149155

150156
ProtoMessageValue protoMessageValue =
151157
ProtoMessageValue.create(
152-
proto2Message, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER);
158+
proto2Message, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER, false);
153159

154160
IllegalArgumentException exception =
155161
assertThrows(
@@ -193,7 +199,8 @@ private enum SelectFieldTestCase {
193199
ProtoMessageValue.create(
194200
NestedMessage.getDefaultInstance(),
195201
DefaultDescriptorPool.INSTANCE,
196-
PROTO_CEL_VALUE_CONVERTER)),
202+
PROTO_CEL_VALUE_CONVERTER,
203+
/* enableJsonFieldNames= */ false)),
197204
NESTED_ENUM("standalone_enum", 1L);
198205

199206
private final String fieldName;
@@ -239,7 +246,7 @@ public void selectField_success(@TestParameter SelectFieldTestCase testCase) {
239246

240247
ProtoMessageValue protoMessageValue =
241248
ProtoMessageValue.create(
242-
testAllTypes, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER);
249+
testAllTypes, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER, false);
243250

244251
assertThat(protoMessageValue.select(testCase.fieldName)).isEqualTo(testCase.value);
245252
}
@@ -253,7 +260,8 @@ public void selectField_dynamicMessage_success() {
253260
ProtoMessageValue.create(
254261
DynamicMessage.newBuilder(testAllTypes).build(),
255262
DefaultDescriptorPool.INSTANCE,
256-
PROTO_CEL_VALUE_CONVERTER);
263+
PROTO_CEL_VALUE_CONVERTER,
264+
/* enableJsonFieldNames= */ false);
257265

258266
assertThat(protoMessageValue.select("single_int32_wrapper")).isEqualTo(5);
259267
}
@@ -269,7 +277,7 @@ public void selectField_timestampNanosOutOfRange_success(int nanos) {
269277

270278
ProtoMessageValue protoMessageValue =
271279
ProtoMessageValue.create(
272-
testAllTypes, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER);
280+
testAllTypes, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER, false);
273281

274282
assertThat(protoMessageValue.select("single_timestamp"))
275283
.isEqualTo(Instant.ofEpochSecond(0, nanos));
@@ -289,7 +297,7 @@ public void selectField_durationOutOfRange_success(int seconds, int nanos) {
289297

290298
ProtoMessageValue protoMessageValue =
291299
ProtoMessageValue.create(
292-
testAllTypes, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER);
300+
testAllTypes, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER, false);
293301

294302
assertThat(protoMessageValue.select("single_duration"))
295303
.isEqualTo(Duration.ofSeconds(seconds, nanos));
@@ -334,7 +342,7 @@ public void selectField_jsonValue(@TestParameter SelectFieldJsonValueTestCase te
334342

335343
ProtoMessageValue protoMessageValue =
336344
ProtoMessageValue.create(
337-
testAllTypes, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER);
345+
testAllTypes, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER, false);
338346

339347
assertThat(protoMessageValue.select("single_value")).isEqualTo(testCase.value);
340348
}
@@ -351,7 +359,7 @@ public void selectField_jsonStruct() {
351359

352360
ProtoMessageValue protoMessageValue =
353361
ProtoMessageValue.create(
354-
testAllTypes, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER);
362+
testAllTypes, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER, false);
355363

356364
assertThat(protoMessageValue.select("single_struct")).isEqualTo(ImmutableMap.of("a", false));
357365
}
@@ -368,7 +376,7 @@ public void selectField_jsonList() {
368376

369377
ProtoMessageValue protoMessageValue =
370378
ProtoMessageValue.create(
371-
testAllTypes, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER);
379+
testAllTypes, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER, false);
372380

373381
assertThat(protoMessageValue.select("list_value")).isEqualTo(ImmutableList.of(false));
374382
}
@@ -379,7 +387,8 @@ public void selectField_wrapperFieldUnset_returnsNull() {
379387
ProtoMessageValue.create(
380388
TestAllTypes.getDefaultInstance(),
381389
DefaultDescriptorPool.INSTANCE,
382-
PROTO_CEL_VALUE_CONVERTER);
390+
PROTO_CEL_VALUE_CONVERTER,
391+
/* enableJsonFieldNames= */ false);
383392

384393
assertThat(protoMessageValue.select("single_int64_wrapper")).isEqualTo(NullValue.NULL_VALUE);
385394
}
@@ -390,9 +399,21 @@ public void celTypeTest() {
390399
ProtoMessageValue.create(
391400
TestAllTypes.getDefaultInstance(),
392401
DefaultDescriptorPool.INSTANCE,
393-
PROTO_CEL_VALUE_CONVERTER);
402+
PROTO_CEL_VALUE_CONVERTER,
403+
/* enableJsonFieldNames= */ false);
394404

395405
assertThat(protoMessageValue.celType())
396406
.isEqualTo(StructTypeReference.create(TestAllTypes.getDescriptor().getFullName()));
397407
}
408+
409+
@Test
410+
public void findField_jsonName_success() {
411+
TestAllTypes testAllTypes = TestAllTypes.newBuilder().setSingleInt32(42).build();
412+
413+
ProtoMessageValue protoMessageValue =
414+
ProtoMessageValue.create(
415+
testAllTypes, DefaultDescriptorPool.INSTANCE, PROTO_CEL_VALUE_CONVERTER, true);
416+
417+
assertThat(protoMessageValue.find("singleInt32")).isPresent();
418+
}
398419
}

runtime/src/main/java/dev/cel/runtime/planner/PlannedProgram.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,18 @@ private CelEvaluationException newCelEvaluationException(long exprId, Exception
110110
// Use the localized expr ID (most specific error location)
111111
LocalizedEvaluationException localized = (LocalizedEvaluationException) e;
112112
exprId = localized.exprId();
113-
builder =
114-
CelEvaluationExceptionBuilder.newBuilder((CelRuntimeException) localized.getCause());
113+
Throwable cause = localized.getCause();
114+
if (cause instanceof CelRuntimeException) {
115+
builder =
116+
CelEvaluationExceptionBuilder.newBuilder((CelRuntimeException) localized.getCause());
117+
} else {
118+
builder = CelEvaluationExceptionBuilder.newBuilder(cause.getMessage()).setCause(cause);
119+
}
115120
} else if (e instanceof CelRuntimeException) {
116121
builder = CelEvaluationExceptionBuilder.newBuilder((CelRuntimeException) e);
117122
} else {
118-
// Unhandled function dispatch failures wraps the original exception with a descriptive message
123+
// Unhandled function dispatch failures wraps the original exception with a descriptive
124+
// message
119125
// (e.g: "Function foo failed with...")
120126
// We need to unwrap the cause here to preserve the original exception message and its cause.
121127
Throwable cause = e.getCause() != null ? e.getCause() : e;

runtime/src/test/java/dev/cel/runtime/PlannerInterpreterTest.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,4 @@ public void unknownResultSet() {
4545
// TODO: Unknown support not implemented yet
4646
skipBaselineVerification();
4747
}
48-
49-
@Override
50-
public void jsonFieldNames() throws Exception {
51-
// TODO: Support JSON field names for planner
52-
skipBaselineVerification();
53-
}
5448
}

runtime/src/test/java/dev/cel/runtime/planner/ProgramPlannerTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ public final class ProgramPlannerTest {
9898
private static final CelValueProvider VALUE_PROVIDER =
9999
ProtoMessageValueProvider.newInstance(CEL_OPTIONS, DYNAMIC_PROTO);
100100
private static final CelValueConverter CEL_VALUE_CONVERTER =
101-
ProtoCelValueConverter.newInstance(DESCRIPTOR_POOL, DYNAMIC_PROTO);
101+
ProtoCelValueConverter.newInstance(DESCRIPTOR_POOL, DYNAMIC_PROTO, CelOptions.DEFAULT);
102102
private static final CelContainer CEL_CONTAINER =
103103
CelContainer.newBuilder()
104104
.setName("cel.expr.conformance.proto3")

0 commit comments

Comments
 (0)