2525import dev .cel .common .values .CelValueConverter ;
2626import dev .cel .runtime .GlobalResolver ;
2727import java .util .NoSuchElementException ;
28+ import org .jspecify .annotations .Nullable ;
2829
2930@ Immutable
3031final class NamespacedAttribute implements Attribute {
@@ -34,6 +35,14 @@ final class NamespacedAttribute implements Attribute {
3435 private final CelValueConverter celValueConverter ;
3536 private final CelTypeProvider typeProvider ;
3637
38+ ImmutableList <Qualifier > qualifiers () {
39+ return qualifiers ;
40+ }
41+
42+ ImmutableSet <String > candidateVariableNames () {
43+ return namespacedNames ;
44+ }
45+
3746 @ Override
3847 public Object resolve (GlobalResolver ctx , ExecutionFrame frame ) {
3948 GlobalResolver inputVars = ctx ;
@@ -59,41 +68,56 @@ public Object resolve(GlobalResolver ctx, ExecutionFrame frame) {
5968 }
6069 }
6170
62- CelType type = typeProvider .findType (name ).orElse (null );
63- if (type != null ) {
64- if (qualifiers .isEmpty ()) {
65- // Resolution of a fully qualified type name: foo.bar.baz
66- return TypeType .create (type );
67- } else {
68- // This is potentially a fully qualified reference to an enum value
69- if (type instanceof EnumType && qualifiers .size () == 1 ) {
70- EnumType enumType = (EnumType ) type ;
71- String strQualifier = (String ) qualifiers .get (0 ).value ();
72- return enumType
73- .findNumberByName (strQualifier )
74- .orElseThrow (
75- () ->
76- new NoSuchElementException (
77- String .format (
78- "Field %s was not found on enum %s" ,
79- enumType .name (), strQualifier )));
80- }
81- }
82-
83- throw new IllegalStateException (
84- "Unexpected type resolution when there were remaining qualifiers: " + type .name ());
71+ // Attempt to resolve the qualify type name if the name is not a variable identifier
72+ value = findIdent (name );
73+ if (value != null ) {
74+ return value ;
8575 }
8676 }
8777
8878 return MissingAttribute .newMissingAttribute (namespacedNames );
8979 }
9080
91- ImmutableList <Qualifier > qualifiers () {
92- return qualifiers ;
81+ private @ Nullable Object findIdent (String name ) {
82+ CelType type = typeProvider .findType (name ).orElse (null );
83+ // If the name resolves directly, this is a fully qualified type name
84+ // (ex: 'int' or 'google.protobuf.Timestamp')
85+ if (type != null ) {
86+ if (qualifiers .isEmpty ()) {
87+ // Resolution of a fully qualified type name: foo.bar.baz
88+ return TypeType .create (type );
89+ }
90+
91+ throw new IllegalStateException (
92+ "Unexpected type resolution when there were remaining qualifiers: " + type .name ());
93+ }
94+
95+ // The name itself could be a fully qualified reference to an enum value
96+ // (e.g: my.enum_type.BAR)
97+ int lastDotIndex = name .lastIndexOf ('.' );
98+ if (lastDotIndex > 0 ) {
99+ String enumTypeName = name .substring (0 , lastDotIndex );
100+ String enumValueQualifier = name .substring (lastDotIndex + 1 );
101+
102+ return typeProvider
103+ .findType (enumTypeName )
104+ .filter (EnumType .class ::isInstance )
105+ .map (EnumType .class ::cast )
106+ .map (enumType -> getEnumValue (enumType , enumValueQualifier ))
107+ .orElse (null );
108+ }
109+
110+ return null ;
93111 }
94112
95- ImmutableSet <String > candidateVariableNames () {
96- return namespacedNames ;
113+ private static Long getEnumValue (EnumType enumType , String field ) {
114+ return enumType
115+ .findNumberByName (field )
116+ .map (Integer ::longValue )
117+ .orElseThrow (
118+ () ->
119+ new NoSuchElementException (
120+ String .format ("Field %s was not found on enum %s" , enumType .name (), field )));
97121 }
98122
99123 private GlobalResolver unwrapToNonLocal (GlobalResolver resolver ) {
0 commit comments