cancel
Showing results for 
Search instead for 
Did you mean: 

What are the reasons when expressions are not injected (null) in a service task delegate expression (Spring bean) ?

viorelhojda
Champ in-the-making
Champ in-the-making

I'm trying to use a simple ServiceTask with a delegateExpression (a Spring bean) and to inject simple Expressions using activiti fields, I'm following the tutorial from official page : Activiti User Guide  .

The Spring bean is correctly initialized by Spring and I have other beans and services correctly configured. The problem is that I can't inject any Expressions, they are all NULL when executing the Service Task. I'm using Activiti 5.9, so I just just the expressions as private members in my bean class.

I want to mention that it works when using a Java class (activiti:class), it doens't work with delegate expression(activiti:delegateExpression). I need the second approach because I need the Spring context available, I don't know how to get it and if it's possible to obtain it in the simple POJO Class using the first approach.

The code is the one from the User Guide, so I don't think I should post it, but I can if needed.

So, what can be the reasons why these Expressions are not injected ? Am I missing something when configuring the Spring context? Also I couldn't find delegateExpressionFieldInjectionMode  setting, I've looked in the Activiti code from different versions and from 2.23 I think it was removed, but the default one should not be DISABLED.

Thank you in advance, I really don't know what I've done wrong, it really should work, I've found multiple examples over the net and it's pretty straightforward.

Thanks in advance for help!

1 ACCEPTED ANSWER

I think the better workaround would be to use the expression attribute of the servicetask. There you could call the method with the two parameters of the spring bean. Something like this:

<serviceTask id="serviceTask" activiti:expression="${springBean.handleNotification(execution, &quot;hallo&quotSmiley Wink}"/>

Niklas

View answer in original post

9 REPLIES 9

gdharley
Elite Collaborator
Elite Collaborator

Please provide a unit test to demonstrate your problem.

Thanks,

Greg

viorelhojda
Champ in-the-making
Champ in-the-making

Hello, thank you for the interest. I haven't configured a JUnit environment (yet) , so I can't provide on the spot the use case scenario, but I can lay down all the needed data, it will certainly contain all the needed data.

So:

1.a Spring bean in the Spring context availlable and instantiated by Spring

<bean id="simpleServiceTaskDelegate" class="atraxo.acc.activiti.SimpleServiceTaskDelegate" />

2.The Activiti BPM process:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlnsSmiley Surprisedmgdc="http://www.omg.org/spec/DD/20100524/DC" xmlnsSmiley Surprisedmgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://activiti.org/bpmn20" id="definitions">
   <process id="sone_email" name="Send Sone Email" isExecutable="true">
   <startEvent id="theStart"></startEvent>
   <endEvent id="theEnd"></endEvent>
   <serviceTask id="servicetask1" name="Simple Service Task"       activiti:delegateExpression="${simpleServiceTaskDelegate}">
      <extensionElements>
         <activiti:field name="fieldA">
            <activiti:string><![CDATA[AAA]]></activiti:string>
         </activiti:field>
      </extensionElements>
   </serviceTask>
   <sequenceFlow id="flow1" sourceRef="theStart" targetRef="servicetask1"></sequenceFlow>
   <sequenceFlow id="flow2" sourceRef="servicetask1" targetRef="theEnd"></sequenceFlow>
</process>
</definitions>

3.The delegate: SimpleServiceTaskDelegate.java class

public class SimpleServiceTaskDelegate implements JavaDelegate {

   private Expression fieldA;

   @Override
   public void execute(DelegateExecution execution) {
      System.out.println("FIELD:" + this.fieldA);// null
   }
}

4.Just deploy and start the process

//deploy

InputStream is = this.getStream(workflowResourceName);

this.activitiBpmService.getRepositoryService().createDeployment().addInputStream(workflowResourceName, is).deploy()

//start

this.activitiBpmService.getRuntimeService().startProcessInstanceByKey("sone_email");

Basically, in the simpleServiceTaskDelegate bean I inject an Expression fieldA, which is null always. If I use the class to inject expressions, then it works:

<serviceTask id="servicetask1" name="Simple Service Task" activiti:class="atraxo.acc.activiti.SimpleServiceTaskDelegate">

If needed, I will setup the JUnit along with Spring context, h2 DB and Activiti and came up with a more functionl test.

Thanks in advance for all the help !

Hi,

maybe you should define the scope of your bean as prototype.

Niklas

viorelhojda
Champ in-the-making
Champ in-the-making

Hello, I tried that already, that "only" means the bean won't be a Singleton with the implications regarding instantiating objects and therefore thread-safety. This doesn't solve the problem , the fields (Expressions) won't be injected in the bean, they will still be null.

Hi,

yes i know. My thought was that the setter might not be called because the object was initialized before. The behaviour with a prototyped bean should be the same as using the class attribute of the service task.

I have tested your code now with my engine. With version 6.0.0.Beta4 there is no problem getting your inserted value. Maybe you should consider to update your engine to a newer version than 5.9.

Niklas

viorelhojda
Champ in-the-making
Champ in-the-making

Thank you again for the interest, I will consider upgrading to 6 (I did try that also), the problem is I have to refactor a lot. Thanks again !

viorelhojda
Champ in-the-making
Champ in-the-making

Hello again, I did find a "workaround" though:

1.create a "dummy" Spring Bean simpleServiceBean  with a method with 2 params, let's say callMethod(Object a, Object b); also, make sure the object t's serializable

2.add the bean to the process instance variables map when starting the process

Object simpleServiceBean = this.getApplicationContext().getBean("simpleServiceBean");
vars.put("simpleServiceBean", simpleServiceBean);

3.use the delegate class as before, SimpleServiceTaskDelegate

4.in the execute method in SimpleServiceTaskDelegate, take the injected Expressions (members of the class), extract the SimpleServiceTaskDelegate from the execution and call the method with params:

Object fa = this.fieldA.getValue(execution);
Object fb = this.fieldB.getValue(execution);

Object obj = execution.getVariable("simpleServiceBean");
SimpleServiceBean ssb = (SimpleServiceBean) obj;
ssb.callMethod(fa, fb);

This works, but it isn't so pretty Smiley Sad

I think the better workaround would be to use the expression attribute of the servicetask. There you could call the method with the two parameters of the spring bean. Something like this:

<serviceTask id="serviceTask" activiti:expression="${springBean.handleNotification(execution, &quot;hallo&quotSmiley Wink}"/>

Niklas

viorelhojda
Champ in-the-making
Champ in-the-making

Yes, I think it's a better approach, it's lighter since I don't have to put the Spring bean in the process instance variables.

It seems I have 3 options:

1.Activiti 6 with Java class delegate

2.Facade Spring Bean with Expression delegate and delegate Java class

3.Call Spring bean code with Expression

Thanks again !