diff --git a/core/src/main/java/org/projectnessie/cel/common/types/pb/FieldDescription.java b/core/src/main/java/org/projectnessie/cel/common/types/pb/FieldDescription.java index 06bf0ab4..fbfd2a3b 100644 --- a/core/src/main/java/org/projectnessie/cel/common/types/pb/FieldDescription.java +++ b/core/src/main/java/org/projectnessie/cel/common/types/pb/FieldDescription.java @@ -271,6 +271,9 @@ public Object getFrom(Db db, Object target) { if (fieldVal instanceof Message) { return maybeUnwrapDynamic(db, (Message) fieldVal); } + if (fd.isMapField() && fieldVal instanceof Map) { + return fieldVal; + } throw new UnsupportedOperationException("IMPLEMENT ME"); // TODO implement this // if (field) @@ -468,18 +471,22 @@ public static Object getValueFromField(FieldDescriptor desc, Message message) { if (v instanceof List) { List lst = (List) v; Map map = new HashMap<>(lst.size() * 4 / 3 + 1); + FieldDescriptor keyDesc = desc.getMessageType().findFieldByNumber(1); + FieldDescriptor valueDesc = desc.getMessageType().findFieldByNumber(2); for (Object e : lst) { Object key; Object value; if (e instanceof MapEntry) { - key = ((MapEntry) e).getKey(); - value = ((MapEntry) e).getValue(); + key = normalizeUnsignedValue(keyDesc, ((MapEntry) e).getKey()); + value = normalizeUnsignedValue(valueDesc, ((MapEntry) e).getValue()); } else if (e instanceof DynamicMessage) { DynamicMessage dynMsg = (DynamicMessage) e; List fields = dynMsg.getDescriptorForType().getFields(); if (fields.size() == 2) { - key = dynMsg.getField(fields.get(0)); - value = dynMsg.getField(fields.get(1)); + FieldDescriptor dynKeyDesc = fields.get(0); + FieldDescriptor dynValueDesc = fields.get(1); + key = normalizeUnsignedValue(dynKeyDesc, dynMsg.getField(dynKeyDesc)); + value = normalizeUnsignedValue(dynValueDesc, dynMsg.getField(dynValueDesc)); } else { throw new IllegalArgumentException( String.format( @@ -514,6 +521,18 @@ public static Object getValueFromField(FieldDescriptor desc, Message message) { return v; } + private static Object normalizeUnsignedValue(FieldDescriptor desc, Object value) { + FieldDescriptor.Type type = desc.getType(); + if (value instanceof Number + && (type == FieldDescriptor.Type.UINT32 + || type == FieldDescriptor.Type.UINT64 + || type == FieldDescriptor.Type.FIXED32 + || type == FieldDescriptor.Type.FIXED64)) { + return ULong.valueOf(((Number) value).longValue()); + } + return value; + } + private static boolean isWellKnownType(FieldDescriptor desc) { if (desc.getJavaType() != JavaType.MESSAGE) { return false; diff --git a/core/src/test/java/org/projectnessie/cel/common/types/pb/FieldDescriptionTest.java b/core/src/test/java/org/projectnessie/cel/common/types/pb/FieldDescriptionTest.java index 329f2cbb..4f16f048 100644 --- a/core/src/test/java/org/projectnessie/cel/common/types/pb/FieldDescriptionTest.java +++ b/core/src/test/java/org/projectnessie/cel/common/types/pb/FieldDescriptionTest.java @@ -25,6 +25,7 @@ import com.google.api.expr.v1alpha1.Type; import com.google.protobuf.BoolValue; import com.google.protobuf.Duration; +import com.google.protobuf.DynamicMessage; import com.google.protobuf.Int32Value; import com.google.protobuf.Message; import com.google.protobuf.NullValue; @@ -33,6 +34,7 @@ import com.google.protobuf.Value; import java.time.Instant; import java.util.Arrays; +import java.util.Collections; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -145,6 +147,37 @@ void getFrom(GetFromTestCase tc) { assertThat(got).isEqualTo(tc.want); } + @Test + void getFromUnsignedMapEntries() { + Db pbdb = newDb(); + TestAllTypes msg = + TestAllTypes.newBuilder() + .putMapStringUint64("large", -1L) + .putMapUint64String(-1L, "large") + .putMapUint64Uint64(-1L, Long.MIN_VALUE) + .build(); + String msgName = msg.getDescriptorForType().getFullName(); + pbdb.registerMessage(msg); + PbTypeDescription td = pbdb.describeType(msgName); + assertThat(td).isNotNull(); + + assertThat(td.fieldByName("map_string_uint64").getFrom(pbdb, msg)) + .isEqualTo(Collections.singletonMap("large", ULong.valueOf(-1L))); + assertThat(td.fieldByName("map_uint64_string").getFrom(pbdb, msg)) + .isEqualTo(Collections.singletonMap(ULong.valueOf(-1L), "large")); + assertThat(td.fieldByName("map_uint64_uint64").getFrom(pbdb, msg)) + .isEqualTo(Collections.singletonMap(ULong.valueOf(-1L), ULong.valueOf(Long.MIN_VALUE))); + + DynamicMessage dynMsg = + DynamicMessage.newBuilder(msg.getDescriptorForType()).mergeFrom(msg).build(); + assertThat(td.fieldByName("map_string_uint64").getFrom(pbdb, dynMsg)) + .isEqualTo(Collections.singletonMap("large", ULong.valueOf(-1L))); + assertThat(td.fieldByName("map_uint64_string").getFrom(pbdb, dynMsg)) + .isEqualTo(Collections.singletonMap(ULong.valueOf(-1L), "large")); + assertThat(td.fieldByName("map_uint64_uint64").getFrom(pbdb, dynMsg)) + .isEqualTo(Collections.singletonMap(ULong.valueOf(-1L), ULong.valueOf(Long.MIN_VALUE))); + } + static class TestCase { Message msg; String field;