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/internal/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,8 @@ cel_android_library(
name = "date_time_helpers_android",
exports = ["//common/src/main/java/dev/cel/common/internal:date_time_helpers_android"],
)

java_library(
name = "reflection_util",
exports = ["//common/src/main/java/dev/cel/common/internal:reflection_util"],
)
4 changes: 4 additions & 0 deletions common/src/main/java/dev/cel/common/internal/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -398,8 +398,12 @@ java_library(
java_library(
name = "reflection_util",
srcs = ["ReflectionUtil.java"],
tags = [
"alt_dep=//common/internal:reflection_util",
],
deps = [
"//common/annotations",
"@maven//:com_google_guava_guava",
],
)

Expand Down
49 changes: 49 additions & 0 deletions common/src/main/java/dev/cel/common/internal/ReflectionUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,15 @@

package dev.cel.common.internal;

import com.google.common.reflect.TypeToken;
import dev.cel.common.annotations.Internal;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
* Utility class for invoking Java reflection.
Expand Down Expand Up @@ -48,5 +54,48 @@ public static Object invoke(Method method, Object object, Object... params) {
}
}

/**
* Extracts the element type of a container type (List, Map, or Optional). Returns the type itself
* if it's not a container or if generic type info is missing.
*/
public static Class<?> getElementType(Class<?> type, Type genericType) {
TypeToken<?> token = TypeToken.of(genericType);

if (List.class.isAssignableFrom(type)) {
return token.resolveType(List.class.getTypeParameters()[0]).getRawType();
}
if (Map.class.isAssignableFrom(type)) {
return token.resolveType(Map.class.getTypeParameters()[1]).getRawType();
}
if (type == Optional.class) {
return token.resolveType(Optional.class.getTypeParameters()[0]).getRawType();
}

return type;
}

/**
* Extracts the raw Class from a Type. Handles Class, ParameterizedType, and WildcardType (returns
* upper bound). Returns Object.class as fallback.
*/
public static Class<?> getRawType(Type type) {
return TypeToken.of(type).getRawType();
}

/**
* Extracts the actual type arguments from a ParameterizedType, if it has at least the expected
* minimum number of arguments. Returns Optional.empty() if the type is not parameterized or has
* fewer arguments than expected.
*/
public static Optional<Type[]> getTypeArguments(Type type, int minArgs) {
if (type instanceof ParameterizedType) {
Type[] args = ((ParameterizedType) type).getActualTypeArguments();
if (args.length >= minArgs) {
return Optional.of(args);
}
}
return Optional.empty();
}

private ReflectionUtil() {}
}
5 changes: 5 additions & 0 deletions extensions/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,8 @@ java_library(
name = "comprehensions",
exports = ["//extensions/src/main/java/dev/cel/extensions:comprehensions"],
)

java_library(
name = "native",
exports = ["//extensions/src/main/java/dev/cel/extensions:native"],
)
24 changes: 24 additions & 0 deletions extensions/src/main/java/dev/cel/extensions/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ java_library(
":encoders",
":lists",
":math",
":native",
":optional_library",
":protos",
":regex",
Expand Down Expand Up @@ -318,3 +319,26 @@ java_library(
"@maven//:com_google_guava_guava",
],
)

java_library(
name = "native",
srcs = ["CelNativeTypesExtensions.java"],
tags = [
],
deps = [
"//checker:checker_builder",
"//common/exceptions:attribute_not_found",
"//common/internal:reflection_util",
"//common/types",
"//common/types:type_providers",
"//common/values",
"//common/values:cel_byte_string",
"//common/values:cel_value",
"//common/values:cel_value_provider",
"//compiler:compiler_builder",
"//runtime",
"@maven//:com_google_errorprone_error_prone_annotations",
"@maven//:com_google_guava_guava",
"@maven//:org_jspecify_jspecify",
],
)
29 changes: 20 additions & 9 deletions extensions/src/main/java/dev/cel/extensions/CelExtensions.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
package dev.cel.extensions;

import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static java.util.Arrays.stream;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Streams;
import com.google.errorprone.annotations.InlineMe;
import dev.cel.common.CelOptions;
import dev.cel.extensions.CelMathExtensions.Function;
import java.util.EnumSet;
import java.util.Set;

/**
Expand Down Expand Up @@ -350,6 +350,18 @@ public static CelComprehensionsExtensions comprehensions() {
return COMPREHENSIONS_EXTENSIONS;
}

/**
* Extensions for supporting native Java types (POJOs) in CEL.
*
* <p>Refer to README.md for details on property discovery, type mapping, and limitations.
*
* <p>Note: Passing classes with unsupported types or anonymous/local classes will result in an
* {@link IllegalArgumentException} when the runtime is built.
*/
public static CelNativeTypesExtensions nativeTypes(Class<?>... classes) {
return CelNativeTypesExtensions.nativeTypes(classes);
}

/**
* Retrieves all function names used by every extension libraries.
*
Expand All @@ -359,18 +371,17 @@ public static CelComprehensionsExtensions comprehensions() {
*/
public static ImmutableSet<String> getAllFunctionNames() {
return Streams.concat(
stream(CelMathExtensions.Function.values())
.map(CelMathExtensions.Function::getFunction),
stream(CelStringExtensions.Function.values())
EnumSet.allOf(Function.class).stream().map(CelMathExtensions.Function::getFunction),
EnumSet.allOf(CelStringExtensions.Function.class).stream()
.map(CelStringExtensions.Function::getFunction),
stream(SetsFunction.values()).map(SetsFunction::getFunction),
stream(CelEncoderExtensions.Function.values())
EnumSet.allOf(SetsFunction.class).stream().map(SetsFunction::getFunction),
EnumSet.allOf(CelEncoderExtensions.Function.class).stream()
.map(CelEncoderExtensions.Function::getFunction),
stream(CelListsExtensions.Function.values())
EnumSet.allOf(CelListsExtensions.Function.class).stream()
.map(CelListsExtensions.Function::getFunction),
stream(CelRegexExtensions.Function.values())
EnumSet.allOf(CelRegexExtensions.Function.class).stream()
.map(CelRegexExtensions.Function::getFunction),
stream(CelComprehensionsExtensions.Function.values())
EnumSet.allOf(CelComprehensionsExtensions.Function.class).stream()
.map(CelComprehensionsExtensions.Function::getFunction))
.collect(toImmutableSet());
}
Expand Down
Loading
Loading