Execute Custom queries in Activiti

(This will probably end up in the user guide of the Activiti 5.15 release, but I wanted to share it already)

The Activiti API allows for interacting with the database using a high level API. For example, for retrieving data the Query API and the Native Query API are powerful in its usage. However, for some use cases they might not be flexible enough. The following section described how a completely custom SQL statement (select, insert, updated and deletes are possible) can be executed against the Activiti data store, but completely within the configured Process Engine (and thus levering the transaction setup for example).

To define custom SQL statements, the Activiti engine leverages the capabilities of its underlying framework, MyBatis. The first thing to do when using custom SQL, is to create a MyBatis mapper class. More info can be read in the MyBatis user guide. For example, suppose that for some use case not the whole task data is needed, but only a small subset of it. A Mapper that could do this, looks as follows:

public interface MyTestMapper {

  @Select("SELECT ID_ as id, NAME_ as name, CREATE_TIME_ as createTime FROM ACT_RU_TASK")
  List<Map<String, Object>> selectTasks();


This mapper must be provided to the Process Engine configuration as follows:

<property name="customMybatisMappers">

Notice that this is an interface. The underlying MyBatis framework will make an instance of it that can be used at runtime. Also notice that the return value of the method is not typed, but a list of maps (which corresponds to the list of rows with column values). Typing is possible with the MyBatis mappers if wanted.

To execute the query above, the managementService.executeCustomSql method must be used. This method takes in a CustomSqlExecution instance. This is a wrapper that hides the internal bits of the engine otherwise needed to make it work.

Unfortunately, Java generics make it a bit less readable than it could have been. The two generic types below are the mapper class and the return type class. However, the actual logic is simply to call the mapper method and return its results (if applicable).

CustomSqlExecution<MyTestMapper, List<Map<String, Object>>> customSqlExecution =
    new AbstractCustomSqlExecution<MyTestMapper, List<Map<String, Object>>>(MyTestMapper.class) {

  public List<Map<String, Object>> execute(MyTestMapper customMapper) {
    return customMapper.selectTasks();


List<Map<String, Object>> results = managementService.executeCustomSql(customSqlExecution);

The Map entries in the list above will only contain id, name and create time in this case and not the full task object.

Any SQL is possible when using the approach above. Another more complex example:

    "SELECT task.ID_ as taskId, variable.LONG_ as variableValue FROM ACT_RU_VARIABLE variable",
    "inner join ACT_RU_TASK task on variable.TASK_ID_ = task.ID_",
    "where variable.NAME_ = #{variableName}"
  List<Map<String, Object>> selectTaskWithSpecificVariable(String variableName);

Using this method, the task table will be joined with the variables table. Only where the variable has a certain name is retained, and the task id and the corresponding numerical value is returned.

This will be possible in Activiti 5.15. However, the code (and more specifically the Command implementation and the wrapper interface) can be used in any older version of Activiti.


  1. Hugo Robayo February 25, 2014

    Dear Joram.

    I am using the Identity link feature for control purposes (auto asign of task), but the problem rises when i try to delete a identity link from Process Instance, I read in the forum (http://forums.activiti.org/content/no-delete-user-identity-link-runtime-service) that could be easily implemented but, if it possible to guide me how to do a delete of indentitylin by hand, I have activiti 5.14, and I found de class IdentityLinkManager.delete(…), how to get the reference for IdentityLinkManager and delete a row….

    Tanks in advandce for your help.



  2. Joram Barrez February 26, 2014

    Hi Hugo,

    I saw your jira issue. But the post you are referring to is for LDAP, not for the database version.

    However, you can easily create your own Activiti Command and get a reference to the identityLinkManager through the Context.

  3. Phil Mittleman August 16, 2014

    In the last example (List<Map> selectTaskWithSpecificVariable(String variableName);), how do you pass the parameter (variableName) into the execute method of the AbstractCustomSqlExecution?

  4. Anonymous August 19, 2014

    How do you mean? You can just reference java variables and pass them into the anonymous class method (if you make them final)

  5. Anonymous December 16, 2014


  6. Prvoslav Obrad Savic February 9, 2015

    Hello Joram,
    thank you for this nice tutorial on how to execute custom queries. It works great!


  7. Sandro June 27, 2016


    Thanks for the nice tutorial.
    I just have one problem: I do not have a Process Engine configuration file in my project because I am using Activiti together with SpringBoot, so where could I can put this mapper configuration?

    Thanks in advance.

  8. Joram Barrez June 28, 2016
  9. Sandro June 28, 2016

    Hi Joram,

    Thanks for the answer.
    I implement the interface and add my mapper, however I still receiving exception saying that
    my mapper is not registered. (Type interface com.activiti.CustomQueryHistoricScreen is not known to the MapperRegistry.)
    Please see my code below, there are something I am doing wrong?

    public class ProcessEngineConfiguration implements ProcessEngineConfigurationConfigurer {

    public void configure(SpringProcessEngineConfiguration processEngineConfiguration) {
    Set<Class> customMybatisMappers = new HashSet();

    public interface CustomQueryHistoricScreen {

    @Select({“select proc.ID_, proc.PROC_DEF_ID_, proc.START_TIME_,proc.END_TIME_,proc.START_ACT_ID_,var.TEXT_ as parameter”,
    “from act_hi_procinst proc”,
    “join act_hi_varinst var on var.PROC_INST_ID_ = proc.ID_”,
    “where var.NAME_ = ‘startParam'”
    List<Map> selectProcessWithStartParameter();


    CustomSqlExecution<CustomQueryHistoricScreen, List<Map>> customSqlExecution =
    new AbstractCustomSqlExecution<CustomQueryHistoricScreen, List<Map>>(CustomQueryHistoricScreen.class) {

    public List<Map> execute(CustomQueryHistoricScreen customMapper) {
    return customMapper.selectProcessWithStartParameter();


    List<Map> results = managementService.executeCustomSql(customSqlExecution);

  10. Joram Barrez June 28, 2016

    And you did put that class as an @Bean in a Configuration class?

  11. Sandro June 28, 2016

    Yes, I did.
    public ProcessEngineConfiguration processEngineConfiguration(){
    return new ProcessEngineConfiguration();

  12. Sandro June 28, 2016

    I put a break point in configure method but it is never triggered.

  13. Sandro June 28, 2016

    I made some corrections and some simplifications in the above code, you can see everything here -> https://codeshare.io/8ZLpF

    However the Configure method is never triggered and my mapper is not added in CustomMapper set :(…
    Any help would be very nice, I tried to change a lot of things but I still receiving exception saying that the interface type is not known to the MapperRegistry.

    Thanks for your help.
    Best regards,

  14. Joram Barrez June 28, 2016

    I’m not sure if I’m reading it righ, but are you copying the interface from Activiti into your own package (package com.core.activiti.mapper)?
    That’s never going to work, as it’s a different type from what the Spring Boot classes are looking for.

    This is the miniml setup proving it works (‘configure called’ is shown in the console): https://gist.github.com/jbarrez/f1b0873aa2fb18bad0cb03b760be343b

  15. Sandro June 30, 2016

    Hi Joram,

    I am sorry for that. After your last answer I understand what you mean and I realize that I was using the version 5.19.0 which does not have the ProcessEngineConfigurationConfigurer interface, so I update the Activiti to version and it worked perfectly.

    Thank you very much for your help

  16. Sandro July 26, 2016

    Hi Joram,

    Do you know if is it possible to create queries DB independent using MyBatis (Just like JPA approach)?

    I’ve implemented some MYSQL queries by using this tutorial, however now I am using some queries that will be executed in different data bases, such as Oracle and H2.

Leave a Reply

Your email address will not be published.