@@ -395,4 +395,48 @@ public void testRepeatingCrossBoundary3() {
395395
396396 }
397397
398+ @ Test
399+ @ CmmnDeployment
400+ public void testMultipleEntryCriteriaWithAndWithoutIfPart () {
401+
402+ // A plan item (Stage C) has two entry criteria:
403+ // - sentry1: two onParts (A complete + B complete), no ifPart
404+ // - sentry2: one onPart (B complete) + ifPart (myVar == true), default trigger mode (event deferred)
405+ //
406+ // The ifPart of sentry2 is evaluated proactively and stored as a
407+ // SentryPartInstanceEntity. When later evaluating sentry1 (which has no ifPart), the code iterates
408+ // through all satisfied sentry part instances for the plan item and must not NPE on the ifPart
409+ // instance from sentry2.
410+
411+ CaseInstance caseInstance = cmmnRuntimeService .createCaseInstanceBuilder ()
412+ .caseDefinitionKey ("myCase" )
413+ .variable ("myVar" , true )
414+ .start ();
415+
416+ List <Task > tasks = cmmnTaskService .createTaskQuery ().caseInstanceId (caseInstance .getId ()).orderByTaskName ().asc ().list ();
417+ assertThat (tasks )
418+ .extracting (Task ::getName )
419+ .containsExactly ("A" , "B" );
420+
421+ // Completing A triggers evaluation of sentry1 (no ifPart) while a satisfied ifPart instance
422+ // from sentry2 exists. Before the fix, this caused a NullPointerException.
423+ cmmnTaskService .complete (tasks .get (0 ).getId ());
424+
425+ PlanItemInstance stageCInstance = cmmnRuntimeService .createPlanItemInstanceQuery ()
426+ .planItemInstanceName ("Stage C" ).singleResult ();
427+ assertThat (stageCInstance .getState ()).isEqualTo (PlanItemInstanceState .AVAILABLE );
428+
429+ // Completing B satisfies both sentries, activating Stage C
430+ Task taskB = cmmnTaskService .createTaskQuery ().caseInstanceId (caseInstance .getId ()).singleResult ();
431+ assertThat (taskB .getName ()).isEqualTo ("B" );
432+ cmmnTaskService .complete (taskB .getId ());
433+
434+ stageCInstance = cmmnRuntimeService .createPlanItemInstanceQuery ()
435+ .planItemInstanceName ("Stage C" ).singleResult ();
436+ assertThat (stageCInstance .getState ()).isEqualTo (PlanItemInstanceState .ACTIVE );
437+
438+ Task taskC = cmmnTaskService .createTaskQuery ().caseInstanceId (caseInstance .getId ()).singleResult ();
439+ assertThat (taskC .getName ()).isEqualTo ("C" );
440+ }
441+
398442}
0 commit comments