Delegate expressions not found for processes running in v5 compatibility

After upgrading to Flowable6 with Flowable5CompatibilityEnabled set to true and using SpringFlowable5CompatibilityHandlerFactory, we’re unable to start processes which call certain custom delegate expressions which used to work before.

When redeploying the same BPM, the instances running in v6 can resolve the delegate expression.

23:24:12.657 [http-nio-8080-exec-4] ERROR org.flowable.common.rest.exception.BaseExceptionHandlerAdvice - Unhandled exception
org.flowable.common.engine.api.FlowableException: Unknown property used in expression: ${FixBooleanVariablesDelegate}
        at org.flowable.compatibility.DefaultFlowable5CompatibilityHandler.handleActivitiException(DefaultFlowable5CompatibilityHandler.java:1174) ~[flowable-inuits-lib-6.4.2.jar:?]
        at org.flowable.compatibility.DefaultFlowable5CompatibilityHandler.startProcessInstance(DefaultFlowable5CompatibilityHandler.java:372) ~[flowable-inuits-lib-6.4.2.jar:?]
        at org.flowable.engine.impl.util.ProcessInstanceHelper.createProcessInstance(ProcessInstanceHelper.java:81) ~[flowable-engine-6.4.2.13.jar:6.4.2.13]

Are we missing something or do we need to adjust some configurations?

Where does the FixBooleanVariablesDelegate come from? Is it a Spring bean? Or something else?

Not 100% sure about this, but what happens if you set the ‘beans’ property of the v5 engine configuration to the same value as the one in v6?

Yes this is a spring bean, instantiated in (one of) our custom auto configurators:

@Bean(name = "FixBooleanVariablesDelegate")
FixBooleanVariablesDelegate fixBooleanVariablesDelegate() {
    return new FixBooleanVariablesDelegate();
}

But what you are asking i actually what we were wondering: is there a dedicated v5 engine configuration? And if so, how do we set the ‘beans’ property in there?
If there is a separate v5 engine configuration, then that might actually be the issue

We only do following concerning v5:

        configuration.setFlowable5CompatibilityEnabled(enableV5Compatibility);
        if (enableV5Compatibility) {
            configuration.setFlowable5CompatibilityHandlerFactory(new SpringFlowable5CompatibilityHandlerFactory());
        }

We see there is a setFlowable6ProcessEngineConfiguration in the DefaultFlowable5CompatibilityHandler, but we’re not sure if this happens somewhere already or whether we should still do this

@joram,
you have an idea about the additional v5 engine config? Do we need to initialize the delegates somewhere in the v5 configuration?

tx,
Tom

There is indeed a v5 config for the engine (it can be retrieved from the processEngine in the DefaultFlowable5CompatibilityHandler instance)

However, looking into the code, this call to copy the beans gets done: flowable-engine/DefaultProcessEngineFactory.java at main · flowable/flowable-engine · GitHub

Can you perhaps debug this to see what is passed?

Another thing to look into is the ServiceTaskDelegateExpressionActivityBehavior class, esp. line 91

Lastly, this class should be hit when resolving the expression: flowable-engine/SpringExpressionManager.java at main · flowable/flowable-engine · GitHub (or the Flowable v6 equivalent): this class does the actual lookup in Spring through the ApplicationContextElResolver.

We will try to debug this.
Since the beans are copied, the problem could also reside in the fact that we are using multiple auto configuration classes from different libraries;
the one that enables the v5 engine is probably executed first, which could explain that the delegates added via the other configurator are not known in v5

@joram,
we debugged this is the meanwhile and it appears that the beans collection is still empty at the moment the v5 engine is enabled, so nothing can be copied at that moment van v6 to v5. Even when we get the beans afterwards via the default engine configuration while running, getBeans() is still empty. Still the delegates work in v6

We did find out that the delegate expressions and beans do work in v5 if we manually set the required beans right before enabling the v5 engine

@Bean
public EngineConfigurationConfigurer<SpringProcessEngineConfiguration> processEngineV5CompatibilityConfigurer() {
    return configuration -> {
        LOGGER.info("Flowable v5 compatibility enabled: {}", enableV5Compatibility);

        // The beans declared below are not recognized by the SpringProcessEngineConfiguration.
        // This is why the copy of the beans will not work if we do not set them manually.
        Map<Object, Object> beans = new HashMap<>();
        if(configuration != null && configuration.getBeans() != null) {
            beans = configuration.getBeans();
        }
        beans.put("UpdateIndexDelegate", updateIndexDelegate());
        beans.put("FixBooleanVariablesDelegate", fixBooleanVariablesDelegate());
        configuration.setBeans(beans);

        configuration.setFlowable5CompatibilityEnabled(enableV5Compatibility);
        if (enableV5Compatibility) {
            configuration.setFlowable5CompatibilityHandlerFactory(new SpringFlowable5CompatibilityHandlerFactory());
        }
    };
}

Is this expected behavior?

It is, the expression resolver will always look in that beans map in case it can’t find a match through any of the other mechanism.

However, this doesn’t fix the original issue, as this should work out of the box (but it is a good workaround, of course). You’re comment made me look deeper into how the expressionManager gets set when using compatibility and found that it’s not properly initialized. Fixed it here: Fix expressionManager creation when using v5 embedded engine (see htt… · flowable/flowable-engine@c08b192 · GitHub

With this fix, there’s no need for the workaround