Monday, March 21, 2011

Useless Flow Managed Persistence

Spring Webflow has some interesting feature called Flow Managed Persistence. In short: it allows you to change some persistent entity during the flow, and merge the state of entity into persistence context at the end of the flow.

Sounds interesting, and is worth trying for sure :) - but you have to be aware, that Spring Webflow guys have overlooked something very important. The JpaFlowExecutionListener, which is involved in the Flow Managed Persistence handling, binds an Entity Manager instance to the flow scope, when a flow execution starts.

So what? - you may say :) - hm, let's look at the Spring Webflow documentation: "any objects stored in flow scope need to be Serializable" - and now back to the Entity Manager interface - nope - it doesn't extend Serializable, so we have no guarantee that it will be.

Indeed when you use the EclipseLink as JPA provider you'll get beautiful "SnapshotCreationException: Could not serialize flow execution; make sure all objects stored in flow or flash scope are serializable".

I've reported this problem in Spring Webflow JIRA - see JpaFlowExecutionListener shouldn't assume that EntityManager is Serializable

You may also find this problem in Community Forum - EclipseLink, Toplink NotSerializableException - mentioned first on August 28th, 2008.

I'm waiting eagerly for the fix :)

Saturday, March 5, 2011

Spring @Autowired, JUnit and Mockito

Few days ago I've encountered interesting problem with autowiring Mockito based Spring Framework beans, let me share it with you :)

Everything started when I've made JUnit test for some business logic code.
...
import static junit.framework.Assert.assertNotNull;
...
@ContextConfiguration({ "classpath:.../business-logic.xml", "classpath:.../orm-jpa.xml",
"classpath:.../test/mockito.xml", ... })
public class MockitoTest extends AbstractJUnit4SpringContextTests {

    @Autowired
    private EmployeeManager employeeManager;

    @Test
    public void test01() {
        assertNotNull(employeeManager.get(Long.valueOf(1L)));
    }
}
Default EmployeeManager implementation used by me delegates the entity fetching to EmployeeDAO:
@Component("business-logic.EmployeeManager")
public class DefaultEmployeeManager implements EmployeeManager {

    @Autowired
    private EmployeeDAO employeeDAO;

    public Employee get(Long identifier) {
        return employeeDAO.get(identifier);
    }
}
EmployeeDAO in this example is a mock created using Mockito:
<bean id="persistence.EmployeeDAO" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="....dao.EmployeeDAO" />
</bean>
When I tried to run the test, it responded with beautiful exception:
java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'business-logic.EmployeeManager': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private ... .dao.EmployeeDAO ... .logic.impl.DefaultEmployeeManager.employeeDAO; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [... .dao.EmployeeDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
...
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private ... .dao.EmployeeDAO ... .logic.impl.DefaultEmployeeManager.employeeDAO; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [... .dao.EmployeeDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. 
My first thoughts were - Why the heck it doesn't work?! There is a bean which can be used for autowiring! - but after few seconds I realized that I'm wrong :) - Here is the explanation why ;)

When Spring Framework creates the beans, and tries to autowire the EmployeeManager properties it seeks for the bean having class EmployeeDAO, but at this point our Mockito based bean is still a Factory, not concrete instance, therefore Spring Framework checks the mock method of our Factory, to determine the type of returned objects. As you may see below it has signature:
public static <T> T mock(Class<T> classToMock)
and thus the determined type is Object, which of course doesn't match the desired one (EmployeeDAO).

Let me read your mind at this point ;) - You think: What can we do with it? - Well, we have to assure that EmployeeDAO bean will be turned into real instance before it will be requested for autowiring.
In other words EmployeeDAO bean should be defined BEFORE the beans using it for autowiring.

We can do it in following ways:
  1. Change the @ContextConfiguration annotation to move the file defining this bean (mockito.xml) in front of all others (very naive solution, but sometimes sufficient ;) )
  2. Define for all beans referring EmployeeDAO that they depend on it
The last one can be achieved in following way:
@Component("business-logic.EmployeeManager")
@DependsOn("persistence.EmployeeDAO")
public class DefaultEmployeeManager implements EmployeeManager ...
when you define your beans using context scanning, or if you simple define them in XML, using depends-on attribute of the bean.

PS: Libraries/Frameworks used in the above example: Spring Framework - 3.0.4, Mockito - 1.8.5 and JUnit 4.8.1