@@ -62,11 +62,10 @@ private CelRule(
6262 }
6363
6464 /**
65- * Concurrent map for caching {@link FieldDescriptor} and their associated List of {@link
66- * AstExpression} .
65+ * Compiled rules keyed by rule field descriptor (e.g. {@code StringRules.min_len}), shared across
66+ * all user fields that reference the same rule. The rule value is bound per call at eval time .
6767 */
68- private static final Map <FieldDescriptor , List <CelRule >> descriptorMap =
69- new ConcurrentHashMap <>();
68+ private final Map <FieldDescriptor , List <CelRule >> descriptorMap = new ConcurrentHashMap <>();
7069
7170 /** The environment to use for evaluation. */
7271 private final Cel cel ;
@@ -123,14 +122,14 @@ List<CompiledProgram> compile(
123122 }
124123 List <CompiledProgram > programs = new ArrayList <>();
125124 for (CelRule rule : completeProgramList ) {
125+ Object fieldValue = message .getField (rule .field );
126126 programs .add (
127127 new CompiledProgram (
128128 rule .program ,
129129 rule .astExpression .source ,
130130 rule .rulePath ,
131- new ObjectValue (rule .field , message .getField (rule .field )),
132- Variable .newRuleVariable (
133- message , ProtoAdapter .toCel (rule .field , message .getField (rule .field )))));
131+ new ObjectValue (rule .field , fieldValue ),
132+ Variable .newRuleVariable (message , ProtoAdapter .toCel (rule .field , fieldValue ))));
134133 }
135134 return Collections .unmodifiableList (programs );
136135 }
@@ -148,8 +147,31 @@ List<CompiledProgram> compile(
148147 }
149148 build .buf .validate .PredefinedRules rules = getFieldRules (ruleFieldDesc );
150149 if (rules == null ) return null ;
150+ try {
151+ return descriptorMap .computeIfAbsent (
152+ ruleFieldDesc ,
153+ key -> {
154+ try {
155+ return buildCelRules (fieldDescriptor , forItems , setOneof , key , message , rules );
156+ } catch (CompilationException e ) {
157+ throw new UncheckedCompilationException (e );
158+ }
159+ });
160+ } catch (UncheckedCompilationException e ) {
161+ throw e .getCompilationException ();
162+ }
163+ }
164+
165+ private List <CelRule > buildCelRules (
166+ FieldDescriptor fieldDescriptor ,
167+ boolean forItems ,
168+ FieldDescriptor setOneof ,
169+ FieldDescriptor ruleFieldDesc ,
170+ Message message ,
171+ build .buf .validate .PredefinedRules rules )
172+ throws CompilationException {
151173 List <Expression > expressions = Expression .fromRules (rules .getCelList ());
152- celRules = new ArrayList <>(expressions .size ());
174+ List < CelRule > celRules = new ArrayList <>(expressions .size ());
153175 Cel ruleCel = getRuleCel (fieldDescriptor , message , ruleFieldDesc , forItems );
154176 for (Expression expression : expressions ) {
155177 FieldPath rulePath =
@@ -167,10 +189,22 @@ List<CompiledProgram> compile(
167189 }
168190 celRules .add (new CelRule (astExpression , program , ruleFieldDesc , rulePath ));
169191 }
170- descriptorMap .put (ruleFieldDesc , celRules );
171192 return celRules ;
172193 }
173194
195+ private static final class UncheckedCompilationException extends RuntimeException {
196+ private final CompilationException compilationException ;
197+
198+ UncheckedCompilationException (CompilationException cause ) {
199+ super (cause );
200+ this .compilationException = cause ;
201+ }
202+
203+ CompilationException getCompilationException () {
204+ return compilationException ;
205+ }
206+ }
207+
174208 private build .buf .validate .@ Nullable PredefinedRules getFieldRules (FieldDescriptor ruleFieldDesc )
175209 throws CompilationException {
176210 DescriptorProtos .FieldOptions options = ruleFieldDesc .getOptions ();
@@ -310,7 +344,7 @@ private ResolvedRule resolveRules(
310344 DynamicMessage .parseFrom (
311345 expectedRuleMessageDescriptor , typeRules .toByteString (), extensionRegistry );
312346 } catch (InvalidProtocolBufferException e ) {
313- throw new RuntimeException ( e );
347+ throw new CompilationException ( "failed to reparse rules with extension registry" , e );
314348 }
315349 }
316350 if (!allowUnknownFields && !typeRules .getUnknownFields ().isEmpty ()) {
0 commit comments