Skip to content

Commit

Permalink
Add a converter to handle bi-directional conversion between CelValue …
Browse files Browse the repository at this point in the history
…to Java native objects

PiperOrigin-RevId: 584757169
  • Loading branch information
l46kok authored and copybara-github committed Nov 23, 2023
1 parent 67b96ad commit 0834708
Show file tree
Hide file tree
Showing 12 changed files with 765 additions and 26 deletions.
18 changes: 18 additions & 0 deletions common/src/main/java/dev/cel/common/types/CelTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,24 @@ public static Type createWrapper(Type type) {
return createWrapper(type.getPrimitive());
}

/** Checks if the fully-qualified protobuf type name is a wrapper type. */
public static boolean isWrapperType(String typeName) {
switch (typeName) {
case BOOL_WRAPPER_MESSAGE:
case BYTES_WRAPPER_MESSAGE:
case DOUBLE_WRAPPER_MESSAGE:
case FLOAT_WRAPPER_MESSAGE:
case INT32_WRAPPER_MESSAGE:
case INT64_WRAPPER_MESSAGE:
case STRING_WRAPPER_MESSAGE:
case UINT32_WRAPPER_MESSAGE:
case UINT64_WRAPPER_MESSAGE:
return true;
default:
return false;
}
}

/**
* Create an abstract type indicating that the parameterized type may be contained within the
* object.
Expand Down
10 changes: 10 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 @@ -11,6 +11,7 @@ package(
CEL_VALUES_SOURCES = [
"BoolValue.java",
"BytesValue.java",
"CelValueConverter.java",
"DoubleValue.java",
"DurationValue.java",
"EnumValue.java",
Expand All @@ -32,6 +33,7 @@ CEL_VALUES_SOURCES = [

# keep sorted
PROTO_MESSAGE_VALUE_SOURCES = [
"ProtoCelValueConverter.java",
"ProtoMessageValue.java",
]

Expand All @@ -56,6 +58,7 @@ java_library(
":cel_byte_string",
":cel_value",
"//:auto_value",
"//common:options",
"//common/annotations",
"//common/types",
"//common/types:type_providers",
Expand Down Expand Up @@ -85,12 +88,19 @@ java_library(
":cel_value",
":values",
"//:auto_value",
"//common:options",
"//common/annotations",
"//common/internal:cel_descriptor_pools",
"//common/internal:dynamic_proto",
"//common/internal:well_known_proto",
"//common/types",
"//common/types:cel_types",
"//common/types:type_providers",
"//common/values:cel_byte_string",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
"@maven//:com_google_protobuf_protobuf_java",
"@maven//:com_google_protobuf_protobuf_java_util",
"@maven//:org_jspecify_jspecify",
],
)
101 changes: 101 additions & 0 deletions common/src/main/java/dev/cel/common/values/CelValueConverter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// 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.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;

/**
* {@code CelValueConverter} handles bidirectional conversion between native Java objects to {@link
* CelValue}.
*
* <p>CEL Library Internals. Do Not Use.
*/
@SuppressWarnings("unchecked") // Unchecked cast of generics due to type-erasure (ex: MapValue).
@Internal
abstract class CelValueConverter {

protected final CelOptions celOptions;

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

if (value instanceof Iterable) {
return toListValue((Iterable<Object>) value);
} else if (value instanceof Map) {
return toMapValue((Map<Object, Object>) value);
}

return fromJavaPrimitiveToCelValue(value);
}

/** Adapts a plain old Java Object that are considered primitives to a {@link CelValue}. */
protected CelValue fromJavaPrimitiveToCelValue(Object value) {
if (value instanceof Boolean) {
return BoolValue.create((Boolean) value);
} else if (value instanceof Long) {
return IntValue.create((Long) value);
} else if (value instanceof Integer) {
return IntValue.create((Integer) value);
} else if (value instanceof String) {
return StringValue.create((String) value);
} else if (value instanceof byte[]) {
return BytesValue.create(CelByteString.of((byte[]) value));
} else if (value instanceof Double) {
return DoubleValue.create((Double) value);
} else if (value instanceof Float) {
return DoubleValue.create(Double.valueOf((Float) value));
} else if (value instanceof UnsignedLong) {
return UintValue.create((UnsignedLong) value);
}

// Fall back to an Opaque value, as a custom class was supplied in the runtime. The legacy
// interpreter allows this but this should not be allowed when a new runtime is introduced.
// TODO: Migrate consumers to directly supply an appropriate CelValue.
return OpaqueValue.create(value.toString(), value);
}

private ListValue<CelValue> toListValue(Iterable<Object> iterable) {
ImmutableList.Builder<CelValue> listBuilder = ImmutableList.builder();
for (Object entry : iterable) {
listBuilder.add(fromJavaObjectToCelValue(entry));
}

return ImmutableListValue.create(listBuilder.build());
}

private MapValue<CelValue, CelValue> toMapValue(Map<Object, Object> map) {
ImmutableMap.Builder<CelValue, CelValue> mapBuilder = ImmutableMap.builder();
for (Entry<Object, Object> entry : map.entrySet()) {
CelValue mapKey = fromJavaObjectToCelValue(entry.getKey());
CelValue mapValue = fromJavaObjectToCelValue(entry.getValue());
mapBuilder.put(mapKey, mapValue);
}

return ImmutableMapValue.create(mapBuilder.buildOrThrow());
}

protected CelValueConverter(CelOptions celOptions) {
this.celOptions = celOptions;
}
}
2 changes: 2 additions & 0 deletions common/src/main/java/dev/cel/common/values/NullValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,6 @@ public CelType celType() {
public boolean isZeroValue() {
return true;
}

private NullValue() {}
}
Loading

0 comments on commit 0834708

Please sign in to comment.