A few weeks ago I was trying to implement custom functions in Camunda DMN engine. I wanted to extend the expression language Java Unified Expression Language (JUEL), which is supported in Camunda. Here’s how I did it.

Implementation

In this example I used Camunda in Spring Boot application (Spring Boot Starter for Camunda).

Core Java classes of EL engine in Camunda are:

FunctionMapper — interface to a map between EL function names and methods. A FunctionMapper maps ${prefix:name()} style functions to a static method that can execute that function (source).

— interface to a map between EL function names and methods. A maps style functions to a static method that can execute that function (source). ExpressionManager — central manager for all expressions. Process parsers will use this to build expression objects that are stored in the process definitions. This class is also used as an entry point for runtime evaluation of the expressions (source).

— central manager for all expressions. Process parsers will use this to build expression objects that are stored in the process definitions. This class is also used as an entry point for runtime evaluation of the expressions (source). SpringExpressionManager — ExpressionManager that exposes the full application-context or a limited set of beans in expressions (source).

But how can this method can be implemented in Java and called in DMN using expression language? There are two ways to do it:

Spring beans — they are registered as expression language extensions in SpringExpressionManager by default. It allows for calling methods from beans in DMN. Function mappers — they are registered in ExpressionManager manually and they map EL functions into static Java methods.

First solution

The business logic of the custom function needs to be implemented first:

Then register Spring bean with the name transactionService :

Now the function can be called in DMN:

Second solution

As before, business logic implementation goes first:

ComplicanceFunctions class is used as a domain methods aggregator:

Next step is implementation of FunctionMapper which maps string expression of JUEL into Java static method:

The last step is registering the function mapper in ExpressionManager . In this case I’m using Camunda DMN in Spring Boot application, so the basic ExpressionManager is SpringExpressionManager :

Now the function can be called in DMN:

Summary

This idea for extending expression language can solve a lot of problems. It helps to hide complex business logic under functions and makes the logic easier to maintain. All new functions should be described in documentation so that other developers know they exist and can use them if needed.

While the proposed solution is helpful in many cases, it should be deployed with care. If a custom function uses external service to get data, e.g by API calls, there is a danger that something will break and decision evaluation will fail. Therefore it’s best to carefully test any third party integrations at regular intervals.