From d6c550a646b932905742044878cff224f87f4674 Mon Sep 17 00:00:00 2001 From: Sokwhan Huh Date: Fri, 25 Apr 2025 12:53:31 -0700 Subject: [PATCH] Add ProtoMessageLiteValueProvider PiperOrigin-RevId: 751526691 --- .../java/dev/cel/common/values/BUILD.bazel | 18 +++++ .../values/ProtoMessageLiteValueProvider.java | 75 +++++++++++++++++++ .../java/dev/cel/common/values/BUILD.bazel | 1 + .../ProtoMessageLiteValueProviderTest.java | 54 +++++++++++++ common/values/BUILD.bazel | 5 ++ 5 files changed, 153 insertions(+) create mode 100644 common/src/main/java/dev/cel/common/values/ProtoMessageLiteValueProvider.java create mode 100644 common/src/test/java/dev/cel/common/values/ProtoMessageLiteValueProviderTest.java diff --git a/common/src/main/java/dev/cel/common/values/BUILD.bazel b/common/src/main/java/dev/cel/common/values/BUILD.bazel index 0f3d8b077..0cd575617 100644 --- a/common/src/main/java/dev/cel/common/values/BUILD.bazel +++ b/common/src/main/java/dev/cel/common/values/BUILD.bazel @@ -184,3 +184,21 @@ java_library( "@maven_android//:com_google_protobuf_protobuf_javalite", ], ) + +java_library( + name = "proto_message_lite_value_provider", + srcs = ["ProtoMessageLiteValueProvider.java"], + tags = [ + ], + deps = [ + ":cel_value", + ":cel_value_provider", + ":proto_message_lite_value", + "//common/internal:cel_lite_descriptor_pool", + "//common/internal:default_lite_descriptor_pool", + "//protobuf:cel_lite_descriptor", + "@maven//:com_google_errorprone_error_prone_annotations", + "@maven//:com_google_guava_guava", + "@maven_android//:com_google_protobuf_protobuf_javalite", + ], +) diff --git a/common/src/main/java/dev/cel/common/values/ProtoMessageLiteValueProvider.java b/common/src/main/java/dev/cel/common/values/ProtoMessageLiteValueProvider.java new file mode 100644 index 000000000..bc8e588d8 --- /dev/null +++ b/common/src/main/java/dev/cel/common/values/ProtoMessageLiteValueProvider.java @@ -0,0 +1,75 @@ +// Copyright 2025 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.ImmutableSet; +import com.google.errorprone.annotations.Immutable; +import com.google.protobuf.MessageLite; +import dev.cel.common.internal.CelLiteDescriptorPool; +import dev.cel.common.internal.DefaultLiteDescriptorPool; +import dev.cel.protobuf.CelLiteDescriptor; +import dev.cel.protobuf.CelLiteDescriptor.MessageLiteDescriptor; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +/** + * {@code ProtoMessageValueProvider} constructs new instances of protobuf lite-message given its + * fully qualified name and its fields to populate. + */ +@Immutable +public class ProtoMessageLiteValueProvider implements CelValueProvider { + private final CelLiteDescriptorPool descriptorPool; + private final ProtoLiteCelValueConverter protoLiteCelValueConverter; + + public ProtoLiteCelValueConverter getProtoLiteCelValueConverter() { + return protoLiteCelValueConverter; + } + + @Override + public Optional newValue(String structType, Map fields) { + MessageLiteDescriptor descriptor = descriptorPool.findDescriptor(structType).orElse(null); + if (descriptor == null) { + return Optional.empty(); + } + + if (!fields.isEmpty()) { + // TODO: Add support for this + throw new UnsupportedOperationException( + "Message creation with prepopulated fields is not supported yet."); + } + + MessageLite message = descriptor.newMessageBuilder().build(); + return Optional.of(protoLiteCelValueConverter.fromProtoMessageToCelValue(structType, message)); + } + + public static ProtoMessageLiteValueProvider newInstance(CelLiteDescriptor... descriptors) { + return newInstance(ImmutableSet.copyOf(descriptors)); + } + + public static ProtoMessageLiteValueProvider newInstance(Set descriptors) { + DefaultLiteDescriptorPool descriptorPool = + DefaultLiteDescriptorPool.newInstance(ImmutableSet.copyOf(descriptors)); + ProtoLiteCelValueConverter protoLiteCelValueConverter = + ProtoLiteCelValueConverter.newInstance(descriptorPool); + return new ProtoMessageLiteValueProvider(protoLiteCelValueConverter, descriptorPool); + } + + private ProtoMessageLiteValueProvider( + ProtoLiteCelValueConverter protoLiteCelValueConverter, CelLiteDescriptorPool descriptorPool) { + this.protoLiteCelValueConverter = protoLiteCelValueConverter; + this.descriptorPool = descriptorPool; + } +} diff --git a/common/src/test/java/dev/cel/common/values/BUILD.bazel b/common/src/test/java/dev/cel/common/values/BUILD.bazel index dee44225a..19cdf7204 100644 --- a/common/src/test/java/dev/cel/common/values/BUILD.bazel +++ b/common/src/test/java/dev/cel/common/values/BUILD.bazel @@ -28,6 +28,7 @@ java_library( "//common/values:cel_value", "//common/values:cel_value_provider", "//common/values:proto_message_lite_value", + "//common/values:proto_message_lite_value_provider", "//common/values:proto_message_value", "//common/values:proto_message_value_provider", "//testing:test_all_types_cel_java_proto3", diff --git a/common/src/test/java/dev/cel/common/values/ProtoMessageLiteValueProviderTest.java b/common/src/test/java/dev/cel/common/values/ProtoMessageLiteValueProviderTest.java new file mode 100644 index 000000000..ced4724ee --- /dev/null +++ b/common/src/test/java/dev/cel/common/values/ProtoMessageLiteValueProviderTest.java @@ -0,0 +1,54 @@ +// Copyright 2025 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 static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.ImmutableMap; +import com.google.testing.junit.testparameterinjector.TestParameterInjector; +import dev.cel.common.types.StructTypeReference; +import dev.cel.expr.conformance.proto3.TestAllTypes; +import dev.cel.expr.conformance.proto3.TestAllTypesCelDescriptor; +import java.util.Optional; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(TestParameterInjector.class) +public class ProtoMessageLiteValueProviderTest { + private static final ProtoMessageLiteValueProvider VALUE_PROVIDER = + ProtoMessageLiteValueProvider.newInstance(TestAllTypesCelDescriptor.getDescriptor()); + + @Test + public void newValue_unknownType_returnsEmpty() { + assertThat(VALUE_PROVIDER.newValue("unknownType", ImmutableMap.of())).isEmpty(); + } + + @Test + public void newValue_emptyFields_success() { + Optional value = + VALUE_PROVIDER.newValue("cel.expr.conformance.proto3.TestAllTypes", ImmutableMap.of()); + ProtoMessageLiteValue protoMessageLiteValue = (ProtoMessageLiteValue) value.get(); + + assertThat(protoMessageLiteValue.value()).isEqualTo(TestAllTypes.getDefaultInstance()); + assertThat(protoMessageLiteValue.isZeroValue()).isTrue(); + assertThat(protoMessageLiteValue.celType()) + .isEqualTo(StructTypeReference.create("cel.expr.conformance.proto3.TestAllTypes")); + } + + @Test + public void getProtoLiteCelValueConverter() { + assertThat(VALUE_PROVIDER.getProtoLiteCelValueConverter()).isNotNull(); + } +} diff --git a/common/values/BUILD.bazel b/common/values/BUILD.bazel index fc31c9994..6b8cd5066 100644 --- a/common/values/BUILD.bazel +++ b/common/values/BUILD.bazel @@ -45,3 +45,8 @@ java_library( name = "proto_message_lite_value", exports = ["//common/src/main/java/dev/cel/common/values:proto_message_lite_value"], ) + +java_library( + name = "proto_message_lite_value_provider", + exports = ["//common/src/main/java/dev/cel/common/values:proto_message_lite_value_provider"], +)