Spring integration: Assign User dynamically using TaskListener

Hi
I have created a UserTask and I want to dynamically assign candidate users to it.
So I created a Java TaskListener

public class UserAssignmentService implements TaskListener
In the notify method I want to use the EntityManager/PersistanceContext of Spring
to read candidateUsers from database.
But since the JavaDelegate is automatically instanciated by the runtime engine,
autowiring the entityManager does not work

public class UserAssignmentService implements TaskListener {
@PersistenceContext
protected EntityManager entityManager;
@Override
public void notify(DelegateTask delegateTask) {
// ← entityManager is null
}
}

The documentation (User Task | docs.camunda.org)
tells me
public class MyAssignmentHandler implements TaskListener {
public void notify(DelegateTask delegateTask) {
// Execute custom identity lookups here
// and then for example call following methods:
delegateTask.setAssignee(“kermit”);
delegateTask.addCandidateUser(“fozzie”);
delegateTask.addCandidateGroup(“management”);

}
}

How can “custom identity lookups” be done using an EntityManager/PersistenceContext?
Does anyone have a suggestion, how to solve this?

Thanks, ROland

Hi Roland,

You need to define UserAssignmentService as a Spring bean, such that Spring manages the bean and wires its dependencies. Then make sure, you use the Camunda Spring integration so that the process engine is able to resolve the bean.

Cheers,
Thorben

Hi Thorben
thanks for your reply.

I already defined the UserAssignmentService as Spring Bean. I use a configuration class
@Configuration
@ComponentScan({“com.n”})
@Import(Common_Configuration.class)
@PropertySource(“classpath:application.co.bpm.properties”)
public class Co_Configuration {

@Bean
UserAssignmentService userAssignmentService() {
	return new UserAssignmentService();
}

}

During bootstrapping I can see in the debugger, that the UserAssignmentService class is successfully instantiated by Spring. But when the Camunda runtime calls the Delegate, another instance is created, not the one that was created by Spring

What do you mean with “use Camunda Spring Integration”?
I put the following dependencies to the POM (see screenshot)

, is that what you mean?

Hi
i’ve done some additional investigations

During bootstrapping Spring creates an instance of UserAssignmentService

Now I’ve created an additional expression in the modeller where I call another method of the userAssignmentService

This method is called successfully, as you can see in the next screenshot, the Bean that was created by Spring is executed, the entityManager is available

But afterwards when the runtime engine executes the Delegate a different UserAssignmentService object is executed, (see the id in the screenshot)

Any ideas?

You use the TaskListener based on “JavaClass”. That leads to camunda creating a new instance of that class for you, it does not know about the spring context. Think if it as if you created an instance via “new” in a container managed environment …
Switch to expression and you should be fine.

2 Likes

Hi
thanks, that’s the solution.

1 of 3) I changed the listener type to “Delegate Expression”

2 of 3) The UserAssignmentService is defined in a Spring Configuration Bean

@Configuration
public class Cu_Configuration {

@Bean
UserAssignmentService userAssignmentService() {
return new UserAssignmentService();
}

3 of 3) The class itself has to implement the TaskListener interface and the corresponding notify method.

public class UserAssignmentService implements TaskListener {
protected EntityManager entityManager;

@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
    this.entityManager = entityManager;
}

@Override
public void notify(DelegateTask delegateTask) {

Now the process context is available via the DelegateTask and the Spring autowiring also works