Spring Finance > Part 3: DDD, JPA & Transaction Support
This entry is part 3 of 6 in the series Spring Finance

Before we start digging into DDD, JPA and transaction management - the main topics of this article, I should note that I am planning to release a new version of the Spring Finance Manager sample application with each article. However, this article is the exception to the rule :-). The code for this article was already realeased with the previous article on the Google code project website. This was needed to get get the sample application running to show the new Spring 3 REST features.

Domain

While this article series is not in particular about Domain Driven Design (DDD), I would still like to mention a few domain related thoughts here and there. As seen in part 2 of this series, I have started the sample application with a rather simple domain model so that the reader can concentrate on the main features of Spring @MVC and Spring 3.0 REST support.

With the release of Spring 2.5, new component marker annotations (also called ‘’stereotype annotations”) were introduced. These make it really convenient to separate concerns by clearly marking the different conceptual boundaries in your architecture. These stereotype annotations include @Service, @Repository (which was actually introduced in Spring 2.0) and @Controller. These annotations fit well with the DDD principles of clear layering of your design:

  • The @Controller is responsible for responding to HTTP requests sent from the view technology (in our case by exposing a REST interface). It (pre-)populates forms, registers custom editors for translation between domain (or DTO) objects and literals coming from the view. The controller does not contain any business logic. The controller has access to the service layer in order to process and retrieve data.
  • The (domain) service layer (marked with @Service) acts either as a facade which hides the repository, or, it may contain business behavior which is common among several domain objects and does not fit into a single domain object. The service layer is very use-case oriented and will access the repository when appropriate without exposing it to the world. The service layer is typically a good point for transaction and security boundaries. This facade layer may wrap multiple DAOs.
  • The @Repository provides the infrastructure part of the application. In the Spring Finance Manager sample application, the repository interface is implemented by a DAO which takes care of the ORM mappings using the JPA standard. More info on this below.
  • The domain model itself is a collection of annotated POJOs which contain some JPA mappings and a number of validation annotations. Domain objects are not managed by the Spring container since they are not marked with a Spring specific component marker annotation. However, if you wish to inject resources into a domain object you can annotate it with @Configurable to make the Spring container aware of it.

To make the Spring container aware of these marker annotations all you need to do is include component scanning into the relevant application context configuration:

<context:component-scan
    base-package="net.stsmedia.financemanager">
    <context:exclude-filter expression="org.springframework.stereotype.Controller"
        type="annotation"/>
</context:component-scan>

You can see that I am separating out the detection of @Controllers as they have their own application context. This is rather a design choice on my side than a necessity.

It should be noted that, conceptually, Person and Address are of different nature when following DDD design principles.

While Person is a normal entity, Address could be seen more as a value object (as described in DDD by Evans p.97). However, since I am using my domain objects directly as form backing objects rather than using the Data Transfer Object (DTO) pattern, I need to have public mutators for the Address object. Strictly speaking Address is therefore not a value object (VO).

In the context of my simple application it makes sense exposing domain objects directly to the view. To me, this seems to be a reasonable concession in order to avoid the effort of creating and maintaining DTOs. This comes, of course, at the price of a ‘compromised’ Address VO.

Of course this approach is more suitable for smaller projects such as the Spring Finance Manager application. For larger code bases where possibly different view technologies are used (think Web Services, Flex, GWT, pure Dojo with JSON, or other Ajax based front-ends) the extra work of mapping DTOs actually saves effort in the long run. Of course you have mappers like Dozer which help with some of the work there as well.

JPA

For the persistence of this application I wanted to use a convenient approach for generating SQL tables from my domain model. So an Object Relational Mapping (ORM) based persistence comes to mind. In the Java world there are several ORM solutions such as OpenJPA, EclipseLink or Hibernate available. I have chosen Hibernate for the simple reason that it is a quite stable tool and plays well with Spring. For example, I don’t need to configure a Java agent which enables load-time weaving in Tomcat and I will not get into trouble when I start playing more with AspectJ later in this series.

Anyway, whatever ORM solution you choose, when using it with the JPA standard, you should be able to just swap it out for one of the alternatives later on - should you wish to do so.

The configuration of JPA is quite straight forward for Spring applications. Beside a DataSource:

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="${database.driverClassName}"/>
    <property name="url" value="${database.url}"/>
    <property name="username" value="${database.username}"/>
    <property name="password" value="${database.password}"/>
</bean>

you also need an EntityManagerFactory:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="FinanceManager"/>
    <property name="dataSource" ref="dataSource"/>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="databasePlatform" value="${database.platform}"/>
            <property name="showSql" value="${database.showSql}"/>
            <property name="generateDdl" value="${database.generateDdl}"/>
        </bean>
    </property>
[...]
</bean>

and finally JPA requires you to create a META-INF/persistence.xml:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="FinanceManager" transaction-type="RESOURCE_LOCAL">
    <class>net.stsmedia.financemanager.domain.Person</class>
</persistence-unit>
</persistence>

This configuration file makes JPA aware of the domain objects marked with @Entity.

The next step is to annotate your domain model with the common JPA annotations such as @Entity, @Embeddable, @Id, etc:

@Entity
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;

    @Version
    @Column(name = "version")
    private Integer version;

    @NotNull
    private String firstName;

    @Embedded
    private Address address;
    [...]
}

As you can see I am also using the Hibernate validator (@NotNull and more later on) which I am planning to exchange with the JSR 303: Bean Validation API and Hibernate Validator 4 which is the only available implementation to this new standard.

Due to the simplicity of my chosen sample application, the service layer will most likely not contain much business logic but rather act as a facade in front of the repository. As mentioned above, the main purpose of the service layer in the Spring Finance Manager application is to define boundaries for transactions and security. Since these boundaries can be defined via Annotations in the respective service interfaces, I decided to merge the repository with the implementation of the service interfaces:

The service interface:

public interface PersonService {

    List<Person> findAll();

    List<Person> findByLastName(String lastName);

    @Transactional
    void persist(Person entity);

    @Transactional
    void merge(Person entity);

    @Transactional
    void remove(Person entity);

    Person find(Long id);
}

As you can see the service interface selects the methods that need to be exposed from the GenericDAOWithJPA and adds further repository or business logic methods which are needed. In this case all methods are implemented by GenericDAOWithJPA except the findByLastName(..) method. Hence this is the only one that needs to be implemented in the PersonServiceImpl class:

@Service
@Repository
public class PersonServiceImpl extends GenericDAOWithJPA<Person,Long> implements PersonService{

    //custom repository method
    public List<Person> findByLastName(String lastName) {
    return super.entityManager.createQuery("Select p from Person p where p.lastName = :lastName")
        .setParameter("lastName", lastName).getResultList();
    }
}

Note, the @Service marker annotation is actually not needed in this case as the @Repository annotation already makes sure that this class becomes a Spring managed bean. The reason I put it in there is to emphasize that this class is actually a mix between a service implementation and a repository. When using the @Repository annotation exception translation will be applied transparently.

Transactions

The PersonService also represents the boundary for transactions. I am using a simple @Transactional on all persist(), merge(), and delete() functions. When using @Transactional without any qualifier it will default to Propagation.REQUIRED which will support any current transaction or create a new one if none exists.

If you expect dirty reads and the like you should also consider adding @Transactional(readOnly = true) for the find*(..) methods. To enable your transactions in the Spring container simply add:

<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

Using the @Transactional annotation on the interface rather than the concrete class gives us the freedom to define transactional boundaries per service method even if the implementation is inherited from GenericDAOWithJPA.

However, it should be noted that it is generally recommended to use @Transactional on concrete classes. If you are using it on interface-based proxies, like me, you need to keep in mind to configure weaving-based aspects (mode=”aspectj”) because only then the transaction settings will be recognized by the proxying/weaving infrastructure and the object will be wrapped in a transactional proxy.

Conclusion

In this article I explained my choices, configuration and code with regards to domain driven design, object relational mapping and transaction management. For these topics there are always many details one could mention (or even better - write separate, more detailed articles) but I wanted to keep this series as focussed as possible without deviating too much into details.

As stated in various places throughout the article, the choice of ORM vendor, middle-tier application design and transaction model depends very much on the individual requirements of the application you are developing. I think my design fits well for the Spring Finance Manager application but it may be problematic for other applications. Indeed, I may change some parts of the backend when I start demonstrating some other features in future articles in this series to accommodate for the needs of these specific features.

In the next part of this series, I am planning release a new version of the Spring Finance Manager application with a complete the domain model as indicated in [http://link article 1] of this series. Furthermore, the view layer will be enriched with some Spring JS and Dojo validation and effects for good measure. Stay tuned!

Series Navigation«Spring Finance > Part 2: Spring @MVC & Spring 3.0 REST integrationSpring Finance > Part 4: Spring JS, Dojo & Bean Validation»
  • Share/Save/Bookmark

One Response Subscribe to comments


  1. Daily del.icio.us for March 29th through April 3rd | Vinny Carpenter's blog

    [...] Spring Finance > Part 3: DDD, JPA & Transaction Support | StSMedia - Before we start digging into DDD, JPA and transaction management - the main topics of this article, I should note that I am planning to release a new version of the Spring Finance Manager sample application with each article. However, this article is the exception to the rule :-). The code for this article was already realeased with the previous article on the Google code project website. This was needed to get get the sample application running to show the new Spring 3 REST features. [...]

    Apr 04, 2009 @ 12:02

Reply

Gallery
_mg_4492-1.jpg _mg_1244.jpg _mg_8531.jpg _mg_2945.jpg