Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions common/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,11 @@ java_library(
exports = ["//common/src/main/java/dev/cel/common:proto_json_adapter"],
)

cel_android_library(
name = "proto_json_adapter_android",
exports = ["//common/src/main/java/dev/cel/common:proto_json_adapter_android"],
)

java_library(
name = "source",
visibility = ["//:internal"],
Expand Down
5 changes: 5 additions & 0 deletions common/internal/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ java_library(
exports = ["//common/src/main/java/dev/cel/common/internal:proto_lite_adapter"],
)

cel_android_library(
name = "proto_lite_adapter_android",
exports = ["//common/src/main/java/dev/cel/common/internal:proto_lite_adapter_android"],
)

java_library(
name = "proto_equality",
exports = ["//common/src/main/java/dev/cel/common/internal:proto_equality"],
Expand Down
16 changes: 16 additions & 0 deletions common/src/main/java/dev/cel/common/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,22 @@ java_library(
],
)

cel_android_library(
name = "proto_json_adapter_android",
srcs = ["CelProtoJsonAdapter.java"],
tags = [
],
deps = [
"//common/internal:date_time_helpers_android",
"//common/internal:proto_time_utils_android",
"//common/values:cel_byte_string",
"//common/values:values_android",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven_android//:com_google_guava_guava",
"@maven_android//:com_google_protobuf_protobuf_javalite",
],
)

java_library(
name = "source_location",
srcs = ["CelSourceLocation.java"],
Expand Down
21 changes: 20 additions & 1 deletion common/src/main/java/dev/cel/common/internal/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,6 @@ java_library(
":well_known_proto",
"//common:options",
"//common/annotations",
"//common/exceptions:numeric_overflow",
"//common/values",
"//common/values:cel_byte_string",
"@maven//:com_google_code_findbugs_annotations",
Expand Down Expand Up @@ -214,6 +213,26 @@ java_library(
],
)

cel_android_library(
name = "proto_lite_adapter_android",
srcs = ["ProtoLiteAdapter.java"],
tags = [
],
deps = [
":well_known_proto_android",
"//common:options",
"//common:proto_json_adapter_android",
"//common/annotations",
"//common/exceptions:numeric_overflow",
"//common/internal:proto_time_utils_android",
"//common/values:cel_byte_string",
"//common/values:values_android",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven_android//:com_google_guava_guava",
"@maven_android//:com_google_protobuf_protobuf_javalite",
],
)

java_library(
name = "proto_equality",
srcs = ["ProtoEquality.java"],
Expand Down
36 changes: 8 additions & 28 deletions common/src/main/java/dev/cel/common/internal/ProtoAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
package dev.cel.common.internal;

import static com.google.common.base.Preconditions.checkNotNull;
import static dev.cel.common.internal.ProtoLiteAdapter.intCheckedCast;
import static dev.cel.common.internal.ProtoLiteAdapter.unsignedIntCheckedCast;

import com.google.common.primitives.Ints;
import com.google.common.primitives.UnsignedInts;
import com.google.common.primitives.UnsignedLong;
import com.google.errorprone.annotations.CheckReturnValue;
Expand All @@ -33,7 +34,6 @@
import com.google.protobuf.MessageOrBuilder;
import dev.cel.common.CelOptions;
import dev.cel.common.annotations.Internal;
import dev.cel.common.exceptions.CelNumericOverflowException;
import dev.cel.common.values.CelByteString;
import dev.cel.common.values.NullValue;
import java.util.ArrayList;
Expand Down Expand Up @@ -347,14 +347,10 @@ private BidiConverter fieldToValueConverter(FieldDescriptor fieldDescriptor) {
case ENUM:
return BidiConverter.<Object, Long>of(
value -> (long) ((EnumValueDescriptor) value).getNumber(),
number -> {
if (number > Integer.MAX_VALUE || number < Integer.MIN_VALUE) {
throw new IllegalArgumentException("Enum value out of int32 range: " + number);
}
return fieldDescriptor
.getEnumType()
.findValueByNumberCreatingIfUnknown(number.intValue());
});
number ->
fieldDescriptor
.getEnumType()
.findValueByNumberCreatingIfUnknown(intCheckedCast(number)));
case MESSAGE:
return BidiConverter.<MessageOrBuilder, Object>of(
this::adaptProtoToValue,
Expand Down Expand Up @@ -401,9 +397,9 @@ public Message adaptValueToProto(Object value, String protoTypeName) {
switch (wellKnownProto) {
case ANY_VALUE:
if (value instanceof Message) {
protoTypeName = ((Message) value).getDescriptorForType().getFullName();
return Any.pack((Message) value);
}
return protoLiteAdapter.adaptValueToAny(value, protoTypeName);
return protoLiteAdapter.adaptValueToAny(value);
default:
return (Message) protoLiteAdapter.adaptValueToWellKnownProto(value, wellKnownProto);
}
Expand All @@ -430,22 +426,6 @@ private static String typeName(Descriptor protoType) {
return protoType.getFullName();
}

private static int intCheckedCast(long value) {
try {
return Ints.checkedCast(value);
} catch (IllegalArgumentException e) {
throw new CelNumericOverflowException(e);
}
}

private static int unsignedIntCheckedCast(long value) {
try {
return UnsignedInts.checkedCast(value);
} catch (IllegalArgumentException e) {
throw new CelNumericOverflowException(e);
}
}

private Object maybeUnwrap(Object value) {
if (value instanceof Message) {
return adaptProtoToValue((MessageOrBuilder) value);
Expand Down
35 changes: 11 additions & 24 deletions common/src/main/java/dev/cel/common/internal/ProtoLiteAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import com.google.protobuf.Int32Value;
import com.google.protobuf.Int64Value;
import com.google.protobuf.ListValue;
import com.google.protobuf.Message;
import com.google.protobuf.MessageLite;
import com.google.protobuf.MessageLiteOrBuilder;
import com.google.protobuf.NullValue;
Expand Down Expand Up @@ -110,11 +109,7 @@ public MessageLite adaptValueToWellKnownProto(Object value, WellKnownProto wellK
}
}

public Any adaptValueToAny(Object value, String typeName) {
if (value instanceof MessageLite) {
return packAnyMessage((MessageLite) value, typeName);
}

public Any adaptValueToAny(Object value) {
if (value instanceof dev.cel.common.values.NullValue) {
return packAnyMessage(
Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build(), WellKnownProto.JSON_VALUE);
Expand Down Expand Up @@ -234,7 +229,7 @@ private ImmutableMap<String, Object> adaptJsonStructToValue(Struct struct) {
.collect(toImmutableMap(Entry::getKey, e -> adaptJsonToValue(e.getValue())));
}

private Message adaptValueToDouble(Object value) {
private MessageLite adaptValueToDouble(Object value) {
if (value instanceof Double) {
return DoubleValue.of((Double) value);
}
Expand All @@ -244,7 +239,7 @@ private Message adaptValueToDouble(Object value) {
throw new IllegalArgumentException("Unexpected value type: " + value);
}

private Message adaptValueToFloat(Object value) {
private MessageLite adaptValueToFloat(Object value) {
if (value instanceof Double) {
return FloatValue.of(((Double) value).floatValue());
}
Expand All @@ -254,7 +249,7 @@ private Message adaptValueToFloat(Object value) {
throw new IllegalArgumentException("Unexpected value type: " + value);
}

private Message adaptValueToInt32(Object value) {
private MessageLite adaptValueToInt32(Object value) {
if (value instanceof Integer) {
return Int32Value.of((Integer) value);
}
Expand All @@ -264,7 +259,7 @@ private Message adaptValueToInt32(Object value) {
throw new IllegalArgumentException("Unexpected value type: " + value);
}

private Message adaptValueToInt64(Object value) {
private MessageLite adaptValueToInt64(Object value) {
if (value instanceof Integer) {
return Int64Value.of(((Integer) value).longValue());
}
Expand All @@ -275,30 +270,22 @@ private Message adaptValueToInt64(Object value) {
throw new IllegalArgumentException("Unexpected value type: " + value);
}

private Message adaptValueToUint32(Object value) {
private MessageLite adaptValueToUint32(Object value) {
if (value instanceof Integer) {
return UInt32Value.of((Integer) value);
}
// Per the spec, an int isn't a uint, unless unsigned longs are disabled.
if (!celOptions.enableUnsignedLongs() && value instanceof Long) {
try {
return UInt32Value.of(unsignedIntCheckedCast((Long) value));
} catch (IllegalArgumentException e) {
throw new CelNumericOverflowException(e);
}
return UInt32Value.of(unsignedIntCheckedCast((Long) value));
}
if (value instanceof UnsignedLong) {
try {
return UInt32Value.of(unsignedIntCheckedCast(((UnsignedLong) value).longValue()));
} catch (IllegalArgumentException e) {
throw new CelNumericOverflowException(e);
}
return UInt32Value.of(unsignedIntCheckedCast(((UnsignedLong) value).longValue()));
}

throw new IllegalArgumentException("Unexpected value type: " + value);
}

private Message adaptValueToUint64(Object value) {
private MessageLite adaptValueToUint64(Object value) {
if (value instanceof Integer) {
return UInt64Value.of(UnsignedInts.toLong((Integer) value));
}
Expand All @@ -312,15 +299,15 @@ private Message adaptValueToUint64(Object value) {
throw new IllegalArgumentException("Unexpected value type: " + value);
}

private static int intCheckedCast(long value) {
static int intCheckedCast(long value) {
try {
return Ints.checkedCast(value);
} catch (IllegalArgumentException e) {
throw new CelNumericOverflowException(e);
}
}

private static int unsignedIntCheckedCast(long value) {
static int unsignedIntCheckedCast(long value) {
try {
return UnsignedInts.checkedCast(value);
} catch (IllegalArgumentException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ private Object mergeOrReadMessageField(
ByteString bytes, String fieldProtoTypeName, @Nullable Object existingValue, boolean isView) {
MessageLiteDescriptor descriptor =
descriptorPool.findDescriptor(fieldProtoTypeName).orElse(null);
if (descriptor == null) {
// An Any can name a map entry, which can't be built.
if (descriptor == null || descriptor.isMapEntry()) {
if (existingValue instanceof RawProtoMessageLiteValue) {
bytes = ((RawProtoMessageLiteValue) existingValue).toByteString().concat(bytes);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,18 @@ public void toRuntimeValue_anyWithUnregisteredMessage_returnsRawValueOfPackedTyp
assertThat(rawValue.toByteString()).isEqualTo(msg.toByteString());
}

@Test
public void toRuntimeValue_anyWithMapEntry_returnsRawValueOfPackedType() {
String mapEntryTypeName = PROTO3_TEST_ALL_TYPES + ".MapStringStringEntry";
Any any = Any.newBuilder().setTypeUrl("type.googleapis.com/" + mapEntryTypeName).build();

Object adaptedValue = PROTO_LITE_CEL_VALUE_CONVERTER.toRuntimeValue(any);

assertThat(adaptedValue).isInstanceOf(RawProtoMessageLiteValue.class);
assertThat(((RawProtoMessageLiteValue) adaptedValue).protoTypeName())
.isEqualTo(mapEntryTypeName);
}

@Test
public void toRuntimeValue_anyNestedToMaxDepth_unpacks() {
Object adaptedValue = PROTO_LITE_CEL_VALUE_CONVERTER.toRuntimeValue(nestedAny(100));
Expand Down
10 changes: 9 additions & 1 deletion protobuf/src/main/java/dev/cel/protobuf/CelLiteDescriptor.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ public abstract class CelLiteDescriptor {
Collections.unmodifiableSet(
new HashSet<>(Arrays.asList(false, 0, 0L, 0.0f, 0.0d, "", ByteString.EMPTY)));

// Map entries have no generated class to build.
private static final Supplier<MessageLite.Builder> NO_BUILDER = () -> null;

@SuppressWarnings("Immutable") // Copied to unmodifiable map
private final Map<String, MessageLiteDescriptor> protoFqnToDescriptors;

Expand Down Expand Up @@ -121,6 +124,11 @@ public MessageLite.Builder newMessageBuilder() {
return messageBuilderSupplier.get();
}

/** Whether this describes a map field's entry, which has no message builder. */
public boolean isMapEntry() {
return messageBuilderSupplier.equals(NO_BUILDER);
}

/** Whether {@link #getFieldValue} reads this message's fields with their generated getters. */
public boolean hasGetters() {
return owner != null;
Expand Down Expand Up @@ -415,7 +423,7 @@ protected static MessageLiteDescriptor mapEntry(
valueType,
false,
valueTypeName)),
() -> null);
NO_BUILDER);
}

protected CelLiteDescriptor(String version, List<MessageLiteDescriptor> messageInfoList) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,16 @@ public void plan_createStruct_oneofSetTwice_lastFieldWins(
assertThat(result.getKindCase()).isEqualTo(expectedCase);
}

@Test
public void plan_createStruct_enumOutOfRange_throwsNumericOverflow() throws Exception {
CelAbstractSyntaxTree ast = compile("TestAllTypes{standalone_enum: 5000000000}");
Program program = PLANNER.plan(ast);

CelEvaluationException e = assertThrows(CelEvaluationException.class, program::eval);

assertThat(e.getErrorCode()).isEqualTo(CelErrorCode.NUMERIC_OVERFLOW);
}

@Test
public void plan_call_zeroArgs() throws Exception {
CelAbstractSyntaxTree ast = compile("zero()");
Expand Down
Loading