Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,11 @@
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiFunction;
import org.projectnessie.cel.common.ULong;
import org.projectnessie.cel.common.types.DoubleT;
Expand Down Expand Up @@ -135,8 +136,12 @@ public static Val maybeNativeToValue(TypeAdapter a, Object value) {
if (value instanceof Object[]) {
return newGenericArrayList(a, (Object[]) value);
}
if (value instanceof List) {
return newGenericArrayList(a, ((List<?>) value).toArray());
if (value instanceof Collection) {
return newGenericArrayList(a, ((Collection<?>) value).toArray());
}
if (value instanceof Optional) {
Optional<?> optional = (Optional<?>) value;
return optional.map(a::nativeToValue).orElse(NullT.NullValue);
}
if (value instanceof Map) {
return newMaybeWrappedMap(a, (Map<?, ?>) value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@
import com.google.protobuf.Timestamp;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.projectnessie.cel.checker.Decls;
import org.projectnessie.cel.common.ULong;
import org.projectnessie.cel.common.types.TypeT;
Expand Down Expand Up @@ -103,15 +104,17 @@ com.google.api.expr.v1alpha1.Type findTypeForJacksonType(JavaType type, TypeQuer
|| Instant.class.isAssignableFrom(rawClass)
|| ZonedDateTime.class.isAssignableFrom(rawClass)) {
return Checked.checkedTimestamp;
} else if (Optional.class.isAssignableFrom(rawClass)) {
return findTypeForJacksonType(elementType(type), typeQuery);
} else if (Map.class.isAssignableFrom(rawClass)) {
com.google.api.expr.v1alpha1.Type keyType =
findTypeForJacksonType(type.getKeyType(), typeQuery);
com.google.api.expr.v1alpha1.Type valueType =
findTypeForJacksonType(type.getContentType(), typeQuery);
return Decls.newMapType(keyType, valueType);
} else if (List.class.isAssignableFrom(rawClass)) {
} else if (Collection.class.isAssignableFrom(rawClass)) {
com.google.api.expr.v1alpha1.Type valueType =
findTypeForJacksonType(type.getContentType(), typeQuery);
findTypeForJacksonType(elementType(type), typeQuery);
return Decls.newListType(valueType);
} else if (type.isEnumType()) {
return typeQuery.getType(type);
Expand All @@ -124,6 +127,18 @@ com.google.api.expr.v1alpha1.Type findTypeForJacksonType(JavaType type, TypeQuer
}
}

private JavaType elementType(JavaType type) {
JavaType elementType = type.getContentType();
if (elementType == null && type.containedTypeCount() > 0) {
elementType = type.containedType(0);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just to confirm: even for Maps containedType(0) refers to the value type?
or do Maps always have a non-null getContentType ?
do we support raw maps without type parameters?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch! containedType(0) would indeed be the key type for Map<K,V>.
Jackson map types always have a non-null getContentType() representing the value type, including raw maps, for which Jackson uses Object for both key and value.
So the fallback is not reached here and raw maps behave as before.
Still, using elementType() for maps is misleading, so I’ll switch that line back to type.getContentType().

}
if (elementType == null) {
throw new UnsupportedOperationException(
String.format("Unsupported Java Type '%s' without element type", type));
}
return elementType;
}

boolean hasProperty(String property) {
return fieldTypes.containsKey(property);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.projectnessie.cel.common.ULong;
import org.projectnessie.cel.common.types.Err;
Expand Down Expand Up @@ -218,6 +220,27 @@ void types() {
checkListType(reg, "bytesList", ByteString.class, Checked.checkedBytes);
checkListType(reg, "floatList", Float.class, Checked.checkedDouble);
checkListType(reg, "doubleList", Double.class, Checked.checkedDouble);
checkListType(reg, "stringCollection", String.class, Checked.checkedString);
checkListType(reg, "stringSet", String.class, Checked.checkedString);

// verify optional fields use their contained type

checkFieldType(reg, "optionalString", Checked.checkedString);
checkFieldType(reg, "emptyOptionalString", Checked.checkedString);
checkFieldType(
reg,
"optionalInnerType",
com.google.api.expr.v1alpha1.Type.newBuilder()
.setMessageType(InnerType.class.getName())
.build());
}

private void checkFieldType(
JacksonRegistry reg, String prop, com.google.api.expr.v1alpha1.Type type) {
JacksonFieldType ft =
(JacksonFieldType) reg.findFieldType(CollectionsObject.class.getName(), prop);
assertThat(ft).isNotNull();
assertThat(ft.type).isEqualTo(type);
}

private void checkListType(
Expand Down Expand Up @@ -362,6 +385,8 @@ void collectionsObjectTypeTest() throws Exception {
ByteString.copyFrom(new byte[] {(byte) 3}));
collectionsObject.floatList = asList(1f, 2f, 3f);
collectionsObject.doubleList = asList(1d, 2d, 3d);
collectionsObject.stringCollection = asList("collection-a", "collection-b");
collectionsObject.stringSet = new LinkedHashSet<>(asList("set-a", "set-b"));

// populate inner/nested type list/map

Expand All @@ -374,13 +399,16 @@ void collectionsObjectTypeTest() throws Exception {
inner2.intProp = 3;
inner2.wrappedIntProp = 4;
collectionsObject.innerTypes = asList(inner1, inner2);
collectionsObject.optionalInnerType = Optional.of(inner2);

// populate enum-related fields

collectionsObject.anEnum = AnEnum.ENUM_VALUE_2;
collectionsObject.anEnumList = asList(AnEnum.ENUM_VALUE_2, AnEnum.ENUM_VALUE_3);
collectionsObject.anEnumStringMap = singletonMap(AnEnum.ENUM_VALUE_2, "a");
collectionsObject.stringAnEnumMap = singletonMap("a", AnEnum.ENUM_VALUE_2);
collectionsObject.optionalString = Optional.of("optional-a");
collectionsObject.emptyOptionalString = Optional.empty();

// prepare registry

Expand All @@ -401,7 +429,7 @@ void collectionsObjectTypeTest() throws Exception {
Object fieldObj = CollectionsObject.class.getDeclaredField(field).get(collectionsObject);
if (fieldObj instanceof Map) {
assertThat(fieldVal).isInstanceOf(MapT.class);
} else if (fieldObj instanceof List) {
} else if (fieldObj instanceof Collection) {
assertThat(fieldVal).isInstanceOf(ListT.class);
}

Expand Down Expand Up @@ -434,6 +462,11 @@ void collectionsObjectTypeTest() throws Exception {
l -> l.get(intOf(2)))
.containsExactly(intOf(3), False, True, True, True, uintOf(1), uintOf(2), uintOf(3));

listVal = (ListT) obj.get(stringOf("stringSet"));
assertThat(listVal)
.extracting(ListT::size, l -> l.get(intOf(0)), l -> l.get(intOf(1)))
.containsExactly(intOf(2), stringOf("set-a"), stringOf("set-b"));

mapVal = (MapT) obj.get(stringOf("stringInnerMap"));
assertThat(mapVal)
.extracting(MapT::size, m -> m.contains(stringOf("42")), m -> m.contains(stringOf("a")))
Expand All @@ -454,6 +487,11 @@ void collectionsObjectTypeTest() throws Exception {
.extracting(o -> o.get(stringOf("intProp")), o -> o.get(stringOf("wrappedIntProp")))
.containsExactly(intOf(3), intOf(4));

i = (ObjectT) obj.get(stringOf("optionalInnerType"));
assertThat(i)
.extracting(o -> o.get(stringOf("intProp")), o -> o.get(stringOf("wrappedIntProp")))
.containsExactly(intOf(3), intOf(4));

// verify enums

Val x = obj.get(stringOf("anEnum"));
Expand All @@ -471,5 +509,10 @@ void collectionsObjectTypeTest() throws Exception {
assertThat(mapVal)
.extracting(l -> l.get(stringOf("a")))
.isEqualTo(intOf(AnEnum.ENUM_VALUE_2.ordinal()));

assertThat(obj.isSet(stringOf("optionalString"))).isSameAs(True);
assertThat(obj.get(stringOf("optionalString"))).isEqualTo(stringOf("optional-a"));
assertThat(obj.isSet(stringOf("emptyOptionalString"))).isSameAs(True);
assertThat(obj.get(stringOf("emptyOptionalString"))).isSameAs(NullT.NullValue);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@
import com.google.protobuf.Duration;
import com.google.protobuf.Timestamp;
import java.time.ZonedDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.projectnessie.cel.common.ULong;

public class CollectionsObject {
Expand Down Expand Up @@ -50,14 +53,19 @@ public class CollectionsObject {
public List<ByteString> bytesList;
public List<Float> floatList;
public List<Double> doubleList;
public Collection<String> stringCollection;
public Set<String> stringSet;

public Map<String, InnerType> stringInnerMap;
public List<InnerType> innerTypes;
public Optional<InnerType> optionalInnerType;

public AnEnum anEnum;
public List<AnEnum> anEnumList;
public Map<AnEnum, String> anEnumStringMap;
public Map<String, AnEnum> stringAnEnumMap;
public Optional<String> optionalString;
public Optional<String> emptyOptionalString;

public static final List<String> ALL_PROPERTIES =
asList(
Expand All @@ -84,10 +92,15 @@ public class CollectionsObject {
"bytesList",
"floatList",
"doubleList",
"stringCollection",
"stringSet",
"stringInnerMap",
"innerTypes",
"optionalInnerType",
"anEnum",
"anEnumList",
"anEnumStringMap",
"stringAnEnumMap");
"stringAnEnumMap",
"optionalString",
"emptyOptionalString");
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@
import com.google.protobuf.Timestamp;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.projectnessie.cel.checker.Decls;
import org.projectnessie.cel.common.ULong;
import org.projectnessie.cel.common.types.TypeT;
Expand Down Expand Up @@ -103,15 +104,17 @@ com.google.api.expr.v1alpha1.Type findTypeForJacksonType(JavaType type, TypeQuer
|| Instant.class.isAssignableFrom(rawClass)
|| ZonedDateTime.class.isAssignableFrom(rawClass)) {
return Checked.checkedTimestamp;
} else if (Optional.class.isAssignableFrom(rawClass)) {
return findTypeForJacksonType(elementType(type), typeQuery);
} else if (Map.class.isAssignableFrom(rawClass)) {
com.google.api.expr.v1alpha1.Type keyType =
findTypeForJacksonType(type.getKeyType(), typeQuery);
com.google.api.expr.v1alpha1.Type valueType =
findTypeForJacksonType(type.getContentType(), typeQuery);
return Decls.newMapType(keyType, valueType);
} else if (List.class.isAssignableFrom(rawClass)) {
} else if (Collection.class.isAssignableFrom(rawClass)) {
com.google.api.expr.v1alpha1.Type valueType =
findTypeForJacksonType(type.getContentType(), typeQuery);
findTypeForJacksonType(elementType(type), typeQuery);
return Decls.newListType(valueType);
} else if (type.isEnumType()) {
return typeQuery.getType(type);
Expand All @@ -124,6 +127,18 @@ com.google.api.expr.v1alpha1.Type findTypeForJacksonType(JavaType type, TypeQuer
}
}

private JavaType elementType(JavaType type) {
JavaType elementType = type.getContentType();
if (elementType == null && type.containedTypeCount() > 0) {
elementType = type.containedType(0);
}
if (elementType == null) {
throw new UnsupportedOperationException(
String.format("Unsupported Java Type '%s' without element type", type));
}
return elementType;
}

boolean hasProperty(String property) {
return fieldTypes.containsKey(property);
}
Expand Down
Loading
Loading