Skip to content

Commit

Permalink
Add ProtoMessageProvider
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 563598718
  • Loading branch information
l46kok authored and copybara-github committed Nov 28, 2023
1 parent 5776206 commit 0267b66
Show file tree
Hide file tree
Showing 30 changed files with 812 additions and 53 deletions.
10 changes: 10 additions & 0 deletions common/src/main/java/dev/cel/common/CelOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ public abstract class CelOptions {

public abstract boolean enableUnknownTracking();

public abstract boolean enableCelValue();

public abstract int comprehensionMaxIterations();

public abstract Builder toBuilder();
Expand Down Expand Up @@ -176,6 +178,7 @@ public static Builder newBuilder() {
.errorOnDuplicateMapKeys(false)
.resolveTypeDependencies(true)
.enableUnknownTracking(false)
.enableCelValue(true)
.comprehensionMaxIterations(-1);
}

Expand Down Expand Up @@ -428,6 +431,13 @@ public abstract static class Builder {
*/
public abstract Builder enableUnknownTracking(boolean value);

/**
* Enables the usage of {@code CelValue} for the runtime. It is a native value representation of
* CEL that wraps Java native objects, and comes with extended capabilities, such as allowing
* value constructs not understood by CEL (ex: POJOs).
*/
public abstract Builder enableCelValue(boolean value);

/**
* Limit the total number of iterations permitted within comprehension loops.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import com.google.common.primitives.UnsignedInts;
import com.google.common.primitives.UnsignedLong;
import com.google.errorprone.annotations.CheckReturnValue;
import javax.annotation.concurrent.ThreadSafe;
import com.google.errorprone.annotations.Immutable;
import com.google.protobuf.Any;
import com.google.protobuf.BoolValue;
import com.google.protobuf.ByteString;
Expand Down Expand Up @@ -73,7 +73,7 @@
*
* <p>CEL Library Internals. Do Not Use.
*/
@ThreadSafe
@Immutable
@CheckReturnValue
@Internal
public final class ProtoAdapter {
Expand Down
12 changes: 10 additions & 2 deletions common/src/main/java/dev/cel/common/types/TypeType.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@
@Immutable
public abstract class TypeType extends CelType {

static final TypeType TYPE = create(SimpleType.DYN);

@Override
public CelKind kind() {
return CelKind.TYPE;
Expand All @@ -38,6 +36,16 @@ public String name() {
return "type";
}

/** Retrieves the underlying type name of the type-kind held. */
public String containingTypeName() {
CelType containingType = type();
if (containingType.kind() == CelKind.DYN) {
return "type";
}

return containingType.name();
}

@Override
public abstract ImmutableList<CelType> parameters();

Expand Down
35 changes: 35 additions & 0 deletions common/src/main/java/dev/cel/common/values/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ java_library(
],
)

java_library(
name = "cel_value_provider",
srcs = [
"CelValueProvider.java",
],
tags = [
],
deps = [
":cel_value",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
],
)

java_library(
name = "values",
srcs = CEL_VALUES_SOURCES,
Expand All @@ -58,7 +72,9 @@ java_library(
":cel_byte_string",
":cel_value",
"//:auto_value",
"//common:error_codes",
"//common:options",
"//common:runtime_exception",
"//common/annotations",
"//common/types",
"//common/types:type_providers",
Expand Down Expand Up @@ -104,3 +120,22 @@ java_library(
"@maven//:org_jspecify_jspecify",
],
)

java_library(
name = "proto_message_value_provider",
srcs = ["ProtoMessageValueProvider.java"],
tags = [
],
deps = [
":cel_value",
":cel_value_provider",
":proto_message_value",
"//common:error_codes",
"//common:options",
"//common:runtime_exception",
"//common/internal:dynamic_proto",
"//common/internal:proto_message_factory",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_protobuf_protobuf_java",
],
)
54 changes: 54 additions & 0 deletions common/src/main/java/dev/cel/common/values/CelValueConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@

package dev.cel.common.values;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.primitives.UnsignedLong;
import dev.cel.common.CelOptions;
import dev.cel.common.annotations.Internal;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;

/**
* {@code CelValueConverter} handles bidirectional conversion between native Java objects to {@link
Expand All @@ -34,8 +36,46 @@ abstract class CelValueConverter {

protected final CelOptions celOptions;

/** Adapts a {@link CelValue} to a plain old Java Object. */
public Object fromCelValueToJavaObject(CelValue celValue) {
Preconditions.checkNotNull(celValue);

if (celValue instanceof MapValue) {
MapValue<CelValue, CelValue> mapValue = (MapValue<CelValue, CelValue>) celValue;
ImmutableMap.Builder<Object, Object> mapBuilder = ImmutableMap.builder();
for (Entry<CelValue, CelValue> entry : mapValue.value().entrySet()) {
Object key = fromCelValueToJavaObject(entry.getKey());
Object value = fromCelValueToJavaObject(entry.getValue());
mapBuilder.put(key, value);
}

return mapBuilder.buildOrThrow();
} else if (celValue instanceof ListValue) {
ListValue<CelValue> listValue = (ListValue<CelValue>) celValue;
ImmutableList.Builder<Object> listBuilder = ImmutableList.builder();
for (CelValue element : listValue.value()) {
listBuilder.add(fromCelValueToJavaObject(element));
}
return listBuilder.build();
} else if (celValue instanceof OptionalValue) {
OptionalValue<CelValue> optionalValue = (OptionalValue<CelValue>) celValue;
if (optionalValue.isZeroValue()) {
return Optional.empty();
}

return Optional.of(fromCelValueToJavaObject(optionalValue.value()));
} else if (celValue instanceof UintValue) {
UintValue uintValue = (UintValue) celValue;
return celOptions.enableUnsignedLongs() ? uintValue.value() : uintValue.value().longValue();
}

return celValue.value();
}

/** Adapts a plain old Java Object to a {@link CelValue}. */
public CelValue fromJavaObjectToCelValue(Object value) {
Preconditions.checkNotNull(value);

if (value instanceof CelValue) {
return (CelValue) value;
}
Expand All @@ -44,13 +84,22 @@ public CelValue fromJavaObjectToCelValue(Object value) {
return toListValue((Iterable<Object>) value);
} else if (value instanceof Map) {
return toMapValue((Map<Object, Object>) value);
} else if (value instanceof Optional) {
Optional<?> optionalValue = (Optional<?>) value;
return optionalValue
.map(o -> OptionalValue.create(fromJavaObjectToCelValue(o)))
.orElse(OptionalValue.EMPTY);
} else if (value instanceof Exception) {
return ErrorValue.create((Exception) value);
}

return fromJavaPrimitiveToCelValue(value);
}

/** Adapts a plain old Java Object that are considered primitives to a {@link CelValue}. */
protected CelValue fromJavaPrimitiveToCelValue(Object value) {
Preconditions.checkNotNull(value);

if (value instanceof Boolean) {
return BoolValue.create((Boolean) value);
} else if (value instanceof Long) {
Expand All @@ -76,6 +125,8 @@ protected CelValue fromJavaPrimitiveToCelValue(Object value) {
}

private ListValue<CelValue> toListValue(Iterable<Object> iterable) {
Preconditions.checkNotNull(iterable);

ImmutableList.Builder<CelValue> listBuilder = ImmutableList.builder();
for (Object entry : iterable) {
listBuilder.add(fromJavaObjectToCelValue(entry));
Expand All @@ -85,6 +136,8 @@ private ListValue<CelValue> toListValue(Iterable<Object> iterable) {
}

private MapValue<CelValue, CelValue> toMapValue(Map<Object, Object> map) {
Preconditions.checkNotNull(map);

ImmutableMap.Builder<CelValue, CelValue> mapBuilder = ImmutableMap.builder();
for (Entry<Object, Object> entry : map.entrySet()) {
CelValue mapKey = fromJavaObjectToCelValue(entry.getKey());
Expand All @@ -96,6 +149,7 @@ private MapValue<CelValue, CelValue> toMapValue(Map<Object, Object> map) {
}

protected CelValueConverter(CelOptions celOptions) {
Preconditions.checkNotNull(celOptions);
this.celOptions = celOptions;
}
}
62 changes: 62 additions & 0 deletions common/src/main/java/dev/cel/common/values/CelValueProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dev.cel.common.values;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.Immutable;
import java.util.Map;
import java.util.Optional;

/** CelValueProvider is an interface for constructing new struct values. */
@Immutable
public interface CelValueProvider {

/**
* Constructs a new struct value.
*
* <p>Note that the return type is defined as CelValue rather than StructValue to account for
* special cases such as wrappers where its primitive is returned.
*/
Optional<CelValue> newValue(String structType, Map<String, Object> fields);

/**
* The {@link CombinedCelValueProvider} takes one or more {@link CelValueProvider} instances and
* attempts to create a {@link CelValue} instance for a given struct type name by calling each
* value provider in the order that they are provided to the constructor.
*/
@Immutable
final class CombinedCelValueProvider implements CelValueProvider {
private final ImmutableList<CelValueProvider> celValueProviders;

public CombinedCelValueProvider(CelValueProvider first, CelValueProvider second) {
Preconditions.checkNotNull(first);
Preconditions.checkNotNull(second);
celValueProviders = ImmutableList.of(first, second);
}

@Override
public Optional<CelValue> newValue(String structType, Map<String, Object> fields) {
for (CelValueProvider provider : celValueProviders) {
Optional<CelValue> newValue = provider.newValue(structType, fields);
if (newValue.isPresent()) {
return newValue;
}
}

return Optional.empty();
}
}
}
8 changes: 6 additions & 2 deletions common/src/main/java/dev/cel/common/values/MapValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.DoNotCall;
import com.google.errorprone.annotations.Immutable;
import dev.cel.common.CelErrorCode;
import dev.cel.common.CelRuntimeException;
import dev.cel.common.types.CelType;
import dev.cel.common.types.MapType;
import dev.cel.common.types.SimpleType;
Expand Down Expand Up @@ -53,8 +55,10 @@ public V get(Object key) {

public V get(K key) {
if (!has(key)) {
throw new IllegalArgumentException(
String.format("key '%s' is not present in map.", key.value()));
throw new CelRuntimeException(
new IllegalArgumentException(
String.format("key '%s' is not present in map.", key.value())),
CelErrorCode.ATTRIBUTE_NOT_FOUND);
}
return value().get(key);
}
Expand Down
Loading

0 comments on commit 0267b66

Please sign in to comment.