Skip to content

Commit 39a99ef

Browse files
l46kokcopybara-github
authored andcommitted
Add an adapter for legacy runtime to consume CelValueProvider. Add interpreter test for CelValues.
PiperOrigin-RevId: 563598718
1 parent aa6875c commit 39a99ef

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1411
-180
lines changed

bundle/src/test/java/dev/cel/bundle/CelImplTest.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,24 @@ public void program_withVars() throws Exception {
526526
assertThat(program.eval(ImmutableMap.of("variable", "hello"))).isEqualTo(true);
527527
}
528528

529+
@Test
530+
public void program_withCelValue() throws Exception {
531+
Cel cel =
532+
standardCelBuilderWithMacros()
533+
.setOptions(CelOptions.current().enableCelValue(true).build())
534+
.addDeclarations(
535+
Decl.newBuilder()
536+
.setName("variable")
537+
.setIdent(IdentDecl.newBuilder().setType(CelTypes.STRING))
538+
.build())
539+
.setResultType(SimpleType.BOOL)
540+
.build();
541+
542+
CelRuntime.Program program = cel.createProgram(cel.compile("variable == 'hello'").getAst());
543+
544+
assertThat(program.eval(ImmutableMap.of("variable", "hello"))).isEqualTo(true);
545+
}
546+
529547
@Test
530548
public void program_withProtoVars() throws Exception {
531549
Cel cel =
@@ -1285,6 +1303,26 @@ public void programAdvanceEvaluation_nestedSelect() throws Exception {
12851303
.isEqualTo(CelUnknownSet.create(CelAttribute.fromQualifiedIdentifier("com.google.a")));
12861304
}
12871305

1306+
@Test
1307+
public void programAdvanceEvaluation_nestedSelect_withCelValue() throws Exception {
1308+
Cel cel =
1309+
standardCelBuilderWithMacros()
1310+
.setOptions(
1311+
CelOptions.current().enableUnknownTracking(true).enableCelValue(true).build())
1312+
.addVar("com", MapType.create(SimpleType.STRING, SimpleType.DYN))
1313+
.addFunctionBindings()
1314+
.setResultType(SimpleType.BOOL)
1315+
.build();
1316+
CelRuntime.Program program = cel.createProgram(cel.compile("com.google.a || false").getAst());
1317+
1318+
assertThat(
1319+
program.advanceEvaluation(
1320+
UnknownContext.create(
1321+
fromMap(ImmutableMap.of()),
1322+
ImmutableList.of(CelAttributePattern.fromQualifiedIdentifier("com.google.a")))))
1323+
.isEqualTo(CelUnknownSet.create(CelAttribute.fromQualifiedIdentifier("com.google.a")));
1324+
}
1325+
12881326
@Test
12891327
public void programAdvanceEvaluation_argumentMergeErrorPriority() throws Exception {
12901328
Cel cel =

common/src/main/java/dev/cel/common/CelOptions.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ public abstract class CelOptions {
8787

8888
public abstract boolean enableUnknownTracking();
8989

90+
public abstract boolean enableCelValue();
91+
9092
public abstract int comprehensionMaxIterations();
9193

9294
public abstract Builder toBuilder();
@@ -176,6 +178,7 @@ public static Builder newBuilder() {
176178
.errorOnDuplicateMapKeys(false)
177179
.resolveTypeDependencies(true)
178180
.enableUnknownTracking(false)
181+
.enableCelValue(false)
179182
.comprehensionMaxIterations(-1);
180183
}
181184

@@ -428,6 +431,15 @@ public abstract static class Builder {
428431
*/
429432
public abstract Builder enableUnknownTracking(boolean value);
430433

434+
/**
435+
* Enables the usage of {@code CelValue} for the runtime. It is a native value representation of
436+
* CEL that wraps Java native objects, and comes with extended capabilities, such as allowing
437+
* value constructs not understood by CEL (ex: POJOs).
438+
*
439+
* <p>Warning: This option is experimental.
440+
*/
441+
public abstract Builder enableCelValue(boolean value);
442+
431443
/**
432444
* Limit the total number of iterations permitted within comprehension loops.
433445
*

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ java_library(
181181
],
182182
deps = [
183183
"//common/annotations",
184+
"@maven//:com_google_guava_guava",
184185
"@maven//:com_google_protobuf_protobuf_java",
185186
],
186187
)

common/src/main/java/dev/cel/common/internal/DynamicProto.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ public static DynamicProto create(ProtoMessageFactory protoMessageFactory) {
4646
this.protoMessageFactory = checkNotNull(protoMessageFactory);
4747
}
4848

49+
/**
50+
* Gets the underlying message factory used to construct new protobuf messages upon unpacking an
51+
* Any message.
52+
*/
53+
public ProtoMessageFactory getProtoMessageFactory() {
54+
return protoMessageFactory;
55+
}
56+
4957
/** Attempts to unpack an Any message. */
5058
public Optional<Message> maybeUnpackAny(Message msg) {
5159
try {

common/src/main/java/dev/cel/common/internal/ProtoAdapter.java

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
import static com.google.common.base.Preconditions.checkNotNull;
1818
import static com.google.common.collect.ImmutableMap.toImmutableMap;
19-
import static java.util.Arrays.stream;
2019

2120
import dev.cel.expr.ExprValue;
2221
import com.google.common.collect.ImmutableList;
@@ -25,7 +24,7 @@
2524
import com.google.common.primitives.UnsignedInts;
2625
import com.google.common.primitives.UnsignedLong;
2726
import com.google.errorprone.annotations.CheckReturnValue;
28-
import javax.annotation.concurrent.ThreadSafe;
27+
import com.google.errorprone.annotations.Immutable;
2928
import com.google.protobuf.Any;
3029
import com.google.protobuf.BoolValue;
3130
import com.google.protobuf.ByteString;
@@ -60,7 +59,6 @@
6059
import java.util.List;
6160
import java.util.Map;
6261
import java.util.Optional;
63-
import java.util.function.Function;
6462
import org.jspecify.nullness.Nullable;
6563

6664
/**
@@ -73,7 +71,7 @@
7371
*
7472
* <p>CEL Library Internals. Do Not Use.
7573
*/
76-
@ThreadSafe
74+
@Immutable
7775
@CheckReturnValue
7876
@Internal
7977
public final class ProtoAdapter {
@@ -139,10 +137,6 @@ public final class ProtoAdapter {
139137
public static final BidiConverter<Number, Number> DOUBLE_CONVERTER =
140138
BidiConverter.of(Number::doubleValue, Number::floatValue);
141139

142-
private static final ImmutableMap<String, WellKnownProto> WELL_KNOWN_PROTOS =
143-
stream(WellKnownProto.values())
144-
.collect(toImmutableMap(WellKnownProto::typeName, Function.identity()));
145-
146140
private final DynamicProto dynamicProto;
147141
private final boolean enableUnsignedLongs;
148142

@@ -163,7 +157,8 @@ public Object adaptProtoToValue(MessageOrBuilder proto) {
163157
}
164158
// If the proto is not a well-known type, then the input Message is what's expected as the
165159
// output return value.
166-
WellKnownProto wellKnownProto = WELL_KNOWN_PROTOS.get(typeName(proto.getDescriptorForType()));
160+
WellKnownProto wellKnownProto =
161+
WellKnownProto.getByDescriptorName(typeName(proto.getDescriptorForType()));
167162
if (wellKnownProto == null) {
168163
return proto;
169164
}
@@ -328,7 +323,7 @@ private BidiConverter fieldToValueConverter(FieldDescriptor fieldDescriptor) {
328323
* considered, such as a packing an {@code google.protobuf.StringValue} into a {@code Any} value.
329324
*/
330325
public Optional<Message> adaptValueToProto(Object value, String protoTypeName) {
331-
WellKnownProto wellKnownProto = WELL_KNOWN_PROTOS.get(protoTypeName);
326+
WellKnownProto wellKnownProto = WellKnownProto.getByDescriptorName(protoTypeName);
332327
if (wellKnownProto == null) {
333328
if (value instanceof Message) {
334329
return Optional.of((Message) value);
@@ -644,7 +639,7 @@ private static boolean isWrapperType(FieldDescriptor fieldDescriptor) {
644639
return false;
645640
}
646641
String fieldTypeName = fieldDescriptor.getMessageType().getFullName();
647-
WellKnownProto wellKnownProto = WELL_KNOWN_PROTOS.get(fieldTypeName);
642+
WellKnownProto wellKnownProto = WellKnownProto.getByDescriptorName(fieldTypeName);
648643
return wellKnownProto != null && wellKnownProto.isWrapperType();
649644
}
650645

common/src/main/java/dev/cel/common/internal/WellKnownProto.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414

1515
package dev.cel.common.internal;
1616

17+
import static com.google.common.collect.ImmutableMap.toImmutableMap;
18+
import static java.util.Arrays.stream;
19+
20+
import com.google.common.collect.ImmutableMap;
1721
import com.google.protobuf.Any;
1822
import com.google.protobuf.BoolValue;
1923
import com.google.protobuf.BytesValue;
@@ -31,6 +35,7 @@
3135
import com.google.protobuf.UInt64Value;
3236
import com.google.protobuf.Value;
3337
import dev.cel.common.annotations.Internal;
38+
import java.util.function.Function;
3439

3540
/**
3641
* WellKnownProto types used throughout CEL. These types are specially handled to ensure that
@@ -58,6 +63,14 @@ public enum WellKnownProto {
5863
private final Descriptor descriptor;
5964
private final boolean isWrapperType;
6065

66+
private static final ImmutableMap<String, WellKnownProto> WELL_KNOWN_PROTO_MAP;
67+
68+
static {
69+
WELL_KNOWN_PROTO_MAP =
70+
stream(WellKnownProto.values())
71+
.collect(toImmutableMap(WellKnownProto::typeName, Function.identity()));
72+
}
73+
6174
WellKnownProto(Descriptor descriptor) {
6275
this(descriptor, /* isWrapperType= */ false);
6376
}
@@ -75,7 +88,11 @@ public String typeName() {
7588
return descriptor.getFullName();
7689
}
7790

78-
boolean isWrapperType() {
91+
public boolean isWrapperType() {
7992
return isWrapperType;
8093
}
94+
95+
public static WellKnownProto getByDescriptorName(String name) {
96+
return WELL_KNOWN_PROTO_MAP.get(name);
97+
}
8198
}

common/src/main/java/dev/cel/common/types/TypeType.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@
2626
@Immutable
2727
public abstract class TypeType extends CelType {
2828

29-
static final TypeType TYPE = create(SimpleType.DYN);
30-
3129
@Override
3230
public CelKind kind() {
3331
return CelKind.TYPE;
@@ -38,6 +36,16 @@ public String name() {
3836
return "type";
3937
}
4038

39+
/** Retrieves the underlying type name of the type-kind held. */
40+
public String containingTypeName() {
41+
CelType containingType = type();
42+
if (containingType.kind() == CelKind.DYN) {
43+
return "type";
44+
}
45+
46+
return containingType.name();
47+
}
48+
4149
@Override
4250
public abstract ImmutableList<CelType> parameters();
4351

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ CEL_VALUES_SOURCES = [
2424
"NullValue.java",
2525
"OpaqueValue.java",
2626
"OptionalValue.java",
27+
"SelectableValue.java",
2728
"StringValue.java",
2829
"StructValue.java",
2930
"TimestampValue.java",
@@ -49,6 +50,20 @@ java_library(
4950
],
5051
)
5152

53+
java_library(
54+
name = "cel_value_provider",
55+
srcs = [
56+
"CelValueProvider.java",
57+
],
58+
tags = [
59+
],
60+
deps = [
61+
":cel_value",
62+
"@maven//:com_google_errorprone_error_prone_annotations",
63+
"@maven//:com_google_guava_guava",
64+
],
65+
)
66+
5267
java_library(
5368
name = "values",
5469
srcs = CEL_VALUES_SOURCES,
@@ -58,7 +73,9 @@ java_library(
5873
":cel_byte_string",
5974
":cel_value",
6075
"//:auto_value",
76+
"//common:error_codes",
6177
"//common:options",
78+
"//common:runtime_exception",
6279
"//common/annotations",
6380
"//common/types",
6481
"//common/types:type_providers",
@@ -104,3 +121,23 @@ java_library(
104121
"@maven//:org_jspecify_jspecify",
105122
],
106123
)
124+
125+
java_library(
126+
name = "proto_message_value_provider",
127+
srcs = ["ProtoMessageValueProvider.java"],
128+
tags = [
129+
],
130+
deps = [
131+
":cel_value",
132+
":cel_value_provider",
133+
":proto_message_value",
134+
"//common:error_codes",
135+
"//common:options",
136+
"//common:runtime_exception",
137+
"//common/annotations",
138+
"//common/internal:dynamic_proto",
139+
"//common/internal:proto_message_factory",
140+
"@maven//:com_google_errorprone_error_prone_annotations",
141+
"@maven//:com_google_protobuf_protobuf_java",
142+
],
143+
)

0 commit comments

Comments
 (0)