Showing posts with label spring. Show all posts
Showing posts with label spring. Show all posts

Friday, June 21, 2013

How to return a file, a stream or a classpath resource from a Spring MVC controller

     You can use AbstractResource subclasses as return values from the controller methods, combining them with the @ResponseBody method annotation.

     Consequently, as soon as you know the filesystem path of the file or have its URI, returning a file from a Spring MVC controller is as easy as:
    @RequestMapping(value = "/file", method = RequestMethod.GET, 
                produces = MediaType.IMAGE_JPEG_VALUE)
    @ResponseBody
    public Resource getFile() throws FileNotFoundException {
        return new FileSystemResource("/Users/forketyfork/cat.jpg");
    }
     The code to return a classpath resource is quite similar:
    @RequestMapping(value = "/classpath", method = RequestMethod.GET, 
                produces = MediaType.IMAGE_JPEG_VALUE)
    @ResponseBody
    public Resource getFromClasspath() {
        return new ClassPathResource("cat.jpg");
    }
     But how about outputting data from a stream? A common advice is to inject HttpServletResponse as a method parameter and write directly to the output stream of the response. But this badly breaks the abstraction, not to mention the testability. Technically we can write to a Writer introduced as a method parameter, like this:
    @RequestMapping(value = "/writer", method = RequestMethod.GET, 
                produces = MediaType.TEXT_PLAIN_VALUE)
    @ResponseBody
    public void getStream(Writer writer) throws IOException {
        writer.write("Hello World!");
    }
     A seemingly simple one-liner. But if you consider serving a large chunk of binary data, this approach appears to be quite slow, memory-consuming and not very handy as it uses the Writer which deals in chars. Moreover, Spring MVC is not able to set the Content-Length header until the output is finished. Here's a slightly more verbose solution, which however does not break the abstraction and is fast and testable.
    @RequestMapping(value = "/stream", method = RequestMethod.GET, 
                produces = MediaType.TEXT_PLAIN_VALUE)
    @ResponseBody
    public Resource getStream() {

        String string = "Hello World!";
        // acquiring the stream
        InputStream stream = new ByteArrayInputStream(string.getBytes());
        // counting the length of data
        final long contentLength = string.length();

        return new InputStreamResource(stream){
            @Override
            public long contentLength() throws IOException {
                return contentLength;
            }
        };

    }
     First, we acquire the stream. Then we count the length of the content we need to output. This may be done in some optimized fashion so as not to process the content entirely. Spring MVC first calls the contentLength() method of the InputStreamResource, sets the Content-Length header and then pipes the stream to the client.

     Here we touch on a bit of inconsistency in Spring API. The class InputStreamResource extends the AbstractResource, which in turn implements the method contentLength() by processing the whole incapsulated stream to count its length. InputStreamResource does not override the contentLength() method, but does override the getInputStream() method, prohibiting to call it more than once, which effectively does not allow for direct usage of this class as a controller method return value. In the example above we override the contentLength() method and provide the correct functionality.

Tuesday, May 28, 2013

"stack shape inconsistent" error during Spring/Jackson application initialization

I have a JSON-service client that's implemented in Spring and Jackson and deployed on WebSphere Application Server. The client worked properly, but on a single machine I encountered a strange classloading issue during Spring initialization:
java.lang.VerifyError: JVMVRFY012 stack shape inconsistent; class=org/codehaus/jackson/map/ObjectMapper
The reason was having two incompatible dependencies in the effective pom of the project:

    org.codehaus.jackson
    jackson-mapper-asl
    1.4.2



    org.codehaus.jackson
    jackson-mapper-lgpl
    1.9.12

Both of those jars had ObjectMapper class defined, and both ended up in WEB-INF/lib directory. The error was unstable, because on some machines the correct (latest) versions of the libraries took precedence during classloading.

Monday, March 26, 2012

Integrating DBUnit with Spring TestContext Framework

The Spring Framework 2.5 came with a new TestContext framework which made integration testing of database code a lot easier. It provided annotations to declaratively specify the application context to execute your test in, annotations to mark the transactions for test methods, and also some base test classes for JUnit and TestNG. In the following article I will describe an approach for integrating the TestContext framework with the DBUnit framework, which in turn allows you to initialize the test database before test and verify its condition with the expected dataset after the test is complete.

Here’s a simple example. We are about to test the correctness of persisting a domain object.
@Entity
public class Person {

    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    
    private String name;
...
Here’s DAO that does the saving:
public class JpaPersonDao implements PersonDao {

    @PersistenceContext
    private EntityManager em;

    public void save(Person person) {
        em.persist(person);
    }

}
It’s worth mentioning that integration testing of DAO implies testing the DAO itself in complex with domain object mappings as well as the underlying persistence provider. In our test case we shall use Hibernate. Let’s create a Spring application context named testContext.xml with the following content (headers and beans tag omitted):
    <!-- For declarative transactions via @Transactional annotation -->
    <tx:annotation-driven/>

    <!-- we’ll use embedded HSQLDB database -->
    <jdbc:embedded-database id="dataSource" />

    <!-- persistence unit configuration -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/>
        <property name="dataSource" ref="dataSource"/>
        <property name="packagesToScan" value="ru.kacit.commons.test.dbunit"/> <!-- package with domain classes -->
        <property name="jpaPropertyMap">
            <map>
                <entry key="hibernate.show_sql" value="true"/>
                <entry key="hibernate.format_sql" value="true"/>
                <entry key="hibernate.hbm2ddl.auto" value="create"/>
            </map>
        </property>
    </bean>

    <!-- generic transaction manager -->
    <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>
    
    <!-- DAO under test -->
    <bean class="ru.kacit.commons.test.dbunit.JpaPersonDao" />
Now let’s create a test class by subclassing a standard Spring TestContext Framework class for transactional tests with JUnit. The @ContextConfiguration annotation specifies the context file (in our case, it’s located on classpath) that shall host the current test. This allows for injecting the DAO under test using @Autowired annotation.
@ContextConfiguration("classpath:testContext.xml")
public class JunitDbunitTest extends AbstractTransactionalJUnit4SpringContextTests {

    @Autowired
    public PersonDao personDao;

    @Test
    public void test1() {
        personDao.save(new Person("Chip"));
        personDao.save(new Person("Dale"));
        personDao.save(new Person("Gadget"));
    }
}
The base class AbstractTransactionalJUnit4SpringContextTests is configured for running each test method in a transaction that gets rollbacked after the test is over.

Now we have to verify that the data actually got persisted into the database. We could simply inject EntityManager in our test class and use it right after persisting the data to make the asserts we need. In most cases of testing a DAO that would be enough to verify the correctness of mappings and DAO logic. The transaction will rollback after the test, and all side effects of the test will be successfully eliminated.

There are cases though when we have to commit the transaction after the test, to ensure its correct ending and to check the data that actually got saved in the database, down to specific fields of tables. It’s worth mentioning that such verifications are likely to tightly couple the test to physical structure of the database, thus increasing its sensitivity. Moreover, the test may fail when executed against another persistence provider due to differences in exported database structure or table naming.

The base test classes provided by Spring only allow you to execute SQL statements against the test database. Let’s see how DBUnit may help us here, and how to integrate it with Spring TestContext Framework.

DBUnit allows you to describe the condition of the database as a generic XML dataset, with no binding to underlying physical data types. Here’s an initial dataset for our test. It is empty, there’s a single ‘persons’ table with two fields in it. It corresponds to the domain class we’ve defined earlier.

<!DOCTYPE dataset SYSTEM "dataset.dtd">
<dataset>
<table name="person">
    <column>id</column>
    <column>name</column>
</table>
</dataset>
Here’s the expected dataset. The ‘persons’ table contains three records.
<source lang="xml">
<!DOCTYPE dataset SYSTEM "dataset.dtd">
<dataset>
    <table name="person">
        <column>id</column>
        <column>name</column>
        <row>
            <value>1</value>
            <value>Chip</value>
        </row>
        <row>
            <value>2</value>
            <value>Dale</value>
        </row>
        <row>
            <value>3</value>
            <value>Gadget</value>
        </row>
    </table>
</dataset>
There’s also a shortened notation in DBUnit in which tags correspond to table names and attributes to fields. But the full-sized format oftentimes appears to be more handy.

Let’s create an annotation for a test method that will specify the datasets to load before starting the test (‘before’ attribute) and to verify against after the test is completed (‘after’ attribute):

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DbunitDataSets {

    String before();
    
    String after();
    
}
To process this annotation, we shall extend the base test class AbstractTransactionalJUnit4SpringContextTests.
@TestExecutionListeners(
        AbstractDbunitTransactionalJUnit4SpringContextTests.DbunitTestExecutionListener.class
)
public abstract class AbstractDbunitTransactionalJUnit4SpringContextTests
        extends AbstractTransactionalJUnit4SpringContextTests {

    /** DBUnit tester */
    private IDatabaseTester databaseTester;

    /** expected dataset file name */
    private String afterDatasetFileName;

    /** method to execute after the test transaction is completed — verification */
    @AfterTransaction
    public void assertAfterTransaction() throws Exception {
        if (databaseTester == null || afterDatasetFileName == null) {
            return;
        }
        IDataSet databaseDataSet = databaseTester.getConnection().createDataSet();
        IDataSet expectedDataSet = 
            new XmlDataSet(ClassLoader.getSystemResourceAsStream(afterDatasetFileName));
        Assertion.assertEquals(expectedDataSet, databaseDataSet);
        databaseTester.onTearDown();
    }

    private static class DbunitTestExecutionListener extends AbstractTestExecutionListener {

        /** method to execute before the test method — initialization */
        public void beforeTestMethod(TestContext testContext) throws Exception {
            AbstractDbunitTransactionalJUnit4SpringContextTests testInstance = (AbstractDbunitTransactionalJUnit4SpringContextTests) testContext.getTestInstance();
            Method method = testContext.getTestMethod();

            DbunitDataSets annotation = method.getAnnotation(DbunitDataSets.class);
            if (annotation == null) {
                return;
            }

            DataSource dataSource = testContext.getApplicationContext().getBean(DataSource.class);
            IDatabaseTester databaseTester = new DataSourceDatabaseTester(dataSource);
            databaseTester.setDataSet(
                new XmlDataSet(ClassLoader.getSystemResourceAsStream(annotation.before())));
            databaseTester.onSetup();
            testInstance.databaseTester = databaseTester;
            testInstance.afterDatasetFileName = annotation.after();
        }
    }
}
The static nested class DbunitTestExecutionListener extends the AbstractExecutionListener — a part of the TestContext Framework. It is bound to the test lifecycle using the @TestExecutionListeners annotation on the test class.

Our basic test class binds to the test lifecycle using two pointcuts. The first is the DbunitTestExecutionListener#beforeTestMethod that gets executed before each test method. It checks for the @DbunitDataSets annotation on the current test method. If the annotation is present, DBUnit database tester is initialized, and the ‘before’ dataset gets loaded into the database. The ‘after’ attribute value and the database tester are saved into the fields of the test class for later use.

The second pointcut is the assertAfterTransaction() method that is marked with @AfterTransaction annotation which is also a part of TestContext framework. This annotation ensures execution of the annotated method after the transaction of the @Transactional-marked test method is completed. Here we apply our previously saved databaseTester and afterDatasetFileName to compare the database condition to the expected dataset using the DBUnit functionality.

Now let’s see what our test looks like.
@ContextConfiguration("classpath:testContext.xml")
public class JunitDbunitTest extends AbstractDbunitTransactionalJUnit4SpringContextTests {

    @Autowired
    private PersonDao personDao;

    @Test
    @Rollback(false)
    @DbunitDataSets(before = "initialDataset.xml", after = "expectedDataset.xml")
    @DirtiesContext
    public void test1() {
        personDao.save(new Person("Chip"));
        personDao.save(new Person("Dale"));
        personDao.save(new Person("Gadget"));
    }
    
}
The @Rollback(false) annotation ensures that the transaction is committed after the test. The @DirtiesContext annotation states that the Spring application context has to be recreated before starting the text test in the class. Our custom @DbunitDataSets annotation defines the names of the files containing the initial and expected DBUnit datasets.

The drawback of this approach is the need to recreate the heavy Spring application context before each test method. After the test is finished, the database is polluted not only with business data (which we can easily purge with DBUnit as well as using the AbstractTransactionalJUnit4SpringContextTests#deleteFromTables method) but also with auxiliary tables and sequences of the persistence provider. Thus, each test method has to be marked with @DirtiesContext annotation which ensures recreating the Spring context and re-exporting the database schema before each sequential test.

To skip the context refresh we could re-export the database schema in a @Before method, thus eliminating need for @DirtiesContext annotation. But I decided not to do that in the base class mostly to keep it uncoupled with Hibernate. Also, even such an aggressive database purgation would keep me unsure if I really eliminated all of the side effects of the test, like Hibernate caching.

An abstract TestNG base test class is absolutely identical to the one I’ve presented here, except for extending the AbstractTransactionalTestNGSpringContextTests class. For my own purposes I’ve extracted the DbunitTestExecutionListener into a separate class and implemented two base classes for these two test frameworks.

The source code for the article is available on GitHub: https://github.com/forketyfork/spring-dao-test-demo