SQL Zone is brought to you in partnership with:

I am a computer engineer having many years of experience in commercial projects for various sectors like education, insurance, hardware, tourism, finance, IT, and telecommunications. Erdinç has posted 7 posts at DZone. View Full User Profile

A Domain Driven Design Implementation With Spring JDBC templates

05.22.2010
| 14475 views |
  • submit to reddit

Domain Driven Design (DDD) enables you to design your applications in a more object oriented fashion. Current JEE development approaches promote the use of JPA/Hibernate objects as data storage elements and to supplement an extra service layer on top of those JPA objects. This leads you to structure your application in a more procedural manner. DDD allows you to code your business logic mostly in your domain objects. Using DDD techniques minimizes the extra service layer usage and complexity so that you can get a simpler design and speed up the development.

I will discuss about a way to implement DDD with Spring JDBC. Let me explain the main structures in my implementation;

 application-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">


<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:mem:book"/>
<property name="username" value="SA" />
<property name="password" value=""/>
<property name="initialSize" value="1"/>
<property name="maxActive" value="10"/>
</bean>


<bean id="dateUtil" class="dddWithSpringJdbc.DateUtil">
</bean>

<bean id="book" class="dddWithSpringJdbc.Book" scope="prototype">
<property name="dateUtil" ref="dateUtil"></property>
</bean>

<bean id="bookRepository" class="dddWithSpringJdbc.repository.impl.BookRepository">
<property name="dataSource" ref="dataSource"></property>
</bean>

</beans>

This file configures the Spring framework.

Transaction configuration;

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:mem:book"/>
<property name="username" value="SA" />
<property name="password" value=""/>
<property name="initialSize" value="1"/>
<property name="maxActive" value="10"/>
</bean>

The beans "txManager" and "dataSource" set transaction configuration. It is required to use @Transactional annotations for your methods and classes. The bean "dateUtil" is a simple utility class for formatting dates.
"Book" represents a domain object. "bookRepository" is an object to retrieve and save "Book" objects.

Model object, Book.java

public class Book {

private String name;
private int id;
private DateUtil dateUtil;
private Date dateAdded;

public Book() {
dateAdded = new Date();
}

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}

public void setDateUtil(DateUtil dateUtil) {
this.dateUtil = dateUtil;
}

public void setId(int id) {
this.id = id;
}

public int getId() {
return id;
}


public void setName(String name) {
this.name = name;
}

public String getName() {
return name;
}

public String formatDateAdded() {
return dateUtil.formatDate(dateAdded);
}

}

 

 The repository objects;

IBookRepository.java;

public interface IBookRepository {

public List<Book> findBooks();
public void insert(Book book);
public void init();
}

"IBookRepository" is used to get "Book" objects from database and writes them to database. It is a kind of DAO used in JEE platforms.

BaseRepository.java

public abstract class BaseRepository extends NamedParameterJdbcDaoSupport implements BeanFactoryAware{

private BeanFactory bf;

public void setBeanFactory(BeanFactory bf) throws BeansException {
this.bf = bf;
}

protected <T> T createBean(String name) {
return (T)bf.getBean(name);
}

protected NamedParameterJdbcTemplate getTemplate() {
return super.getNamedParameterJdbcTemplate();
}
}

This is used to retrieve beans from Spring and to help performing database operations.  You can get a bean from a Spring context by calling "getBean()" method.

BookRepository.java

@Transactional(propagation=Propagation.REQUIRED)
public class BookRepository extends BaseRepository implements IBookRepository {

@Transactional(readOnly=true)
@Override
public List<Book> findBooks() {
return getTemplate().query("select * from BOOK order by name asc", (Map) null, new ParameterizedRowMapper<Book>() {

@Override
public Book mapRow(ResultSet rs, int index) throws SQLException {
Book book = createBean("book");

book.setId(rs.getInt("id"));
book.setName(rs.getString("name"));

return book;
}

});

}

public void insert(Book book) {
String sql = "insert into BOOK(id, name) values(:id, :name);";


Map<String, Object> params = new HashMap<String, Object>();
params.put("id", book.getId());
params.put("name", book.getName());

getTemplate().update(sql, params);

}

@Override
public void init() {
getTemplate().update("CREATE TABLE BOOK (id int not null primary key, name varchar(256));", (Map) null);
getTemplate().update("insert into BOOK(id, name) values(1, 'Book1');", (Map) null);

}
}

 "BookRepository" is a repository object performing database operations. "findBooks()" fetches all the book information from the database. Please note that in order to do that, it retrieves a "Book" object from Spring context by calling "createBean()" method. Spring creates, inits and returns a managed "Book" bean.
"insert()" just adds another "Book" object to the database. "init()" prepares the database for the application.
    
The sample application starts by calling main method of "Start" class.

Start.java

public class Start {

public static void main(String [] args) {
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext("/application-context.xml");
IBookRepository repository = (IBookRepository)appContext.getBean("bookRepository");

repository.init();

List<Book> bookList = repository.findBooks();

Book firstBook = bookList.get(0);
String formattedString = firstBook.formatDateAdded();

System.out.println("result=" + formattedString);

}
}

The goal of that code snippet is to format "dateAdded" property of a "Book" object. To do that,
a "Book" object uses "DateUtil" object, which is injected to it to format the date. You can get formatted string
by calling "formatDateAdded()" method of a "Book" object without touching any "DateUtil" object.

You can find the related source code as an attached zip file in Resources section.

Legacy
Article Resources: 
Published at DZone with permission of its author, Erdinç Kocaman.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Jocelyn LECOMTE replied on Sat, 2010/05/22 - 10:27am

I don't get the whole article. Let me explain:

  1. At the beginning, you're talking about a rich object model. It's a good point, but implementing such a model has nothing to do with underlying technologies. You can do it with JPA if you want to ! In don't understand why it's easier with JDBC... It seems to me that your repository layer could be implemented with any other persistence technology
  2. When you say : "it retrieves a "Book" object from Spring context by calling "createBean()" method. Spring creates, inits and returns a managed "Book" bean", you're wrong. There is nothing that is managed here, because you don't have any notion of lifecycle.
  3. If you intend to show us a good sample of DDD, at least put one model object in the article. Here we have all the other classes, but not Book ! (Probably it's in the code download though). Your article is more about beginning with Spring JDBC than DDD.

Erdinç Kocaman replied on Sat, 2010/05/22 - 11:10am

Hi,

1- I haven't chosen JDBC because it is better than JPA or another persistency technology.
I preferred it because it is a simple way to implement my DDD technique. As you said,
it can be implemented using other persistency frameworks like Hibernate, Cayenne.

2- Spring is a framework used for managing beans. You said "Book" object is not managed,
but whole Spring concept based on managing beans. And you talked about lifecyce here. It is a "prototype" object
if it is a lifecycle you mean. I didn't understand your notion about bean management.

3. I  forgot to show the code for Book.java. Thank you to remind it.

Ivica Loncar replied on Sat, 2010/05/22 - 2:47pm

 

Let me be a bit harsh:

In the first paragraph you mention some properties of DDD and then in the rest of the article you don't expand on it (you gave us basic CRUD operations and anemic domain model).

Do you plan to write more articles?

 

DDD is more about expressing principles of some domain in our code and less about the technology, but we almost always forget about the ubiquitous model and it's bounded context, probably because we spend so much time writing boilerplate code implementing basic building blocks as a preparation for DDD or fixing discrepancies between Object model and Relational model. We put more technologies in the mix and we usually get anemic domain model mixed with a lot of code implementing transaction script pattern (and there's nothing wrong with that - most of our customers need simple procedural solutions for their problems).

I guess that rethinking about some problem/concept/domain and designing a solution that most naturaly fits into a context of that domain should be the core of articles with DDD in the title. Implementing repository and throwing out DAOs is not enough.

 

 

 

Erdinç Kocaman replied on Sat, 2010/05/22 - 4:01pm

I think you missed the word "implementation" in the title of the article. There can be many things to talk about DDD but I wanted to give an example way to implement DDD in your application. Also, I didn't use anemic model in my example. The model is managed by Spring and the model objects can have many dependencies to perform its job , otherwise there is no point using DDD.

Ivica Loncar replied on Sat, 2010/05/22 - 4:36pm in response to: Erdinç Kocaman

Oh, I didn't miss "implementation" part in the title. I just  hoped that someone will pick a bit more complex domain and  explain how to apply some of the DDD principles.

Can you explain what is your model and what is the behaviour/value that it offers?

Why do you think this isn't an example of an anemic domain model? By definition it's a model that doesn't contain any business logic and I don't see any business logic implemented inside class Book.

 

 

Erdinç Kocaman replied on Sat, 2010/05/22 - 6:07pm

In my example, my model object is "Book" and it has a method formatDateAdded() to format its dateAdded property. It does this by using a DateUtil object which is injected to the model object by Spring container. You can enrich the business logic of the Book model in this way. This is a different approach than anemic model which is the domain objects are just used for keeping the data without applying any logic on them.

Thomas Eichberger replied on Sat, 2010/05/22 - 6:23pm

Well, I don't think that the inclusion of a format method in a model class is sufficient for calling this DDD...

Erdinç Kocaman replied on Sat, 2010/05/22 - 6:41pm

I discussed about a method to enable DDD not the DDD itself.

Thomas Eichberger replied on Sun, 2010/05/23 - 12:49am in response to: Erdinç Kocaman

OK, I understand now ;-)

Bozhidar Bozhanov replied on Sun, 2010/05/23 - 3:35am

Can you create a generic repository (DAO) with this scenario? "createBean" is type-unsafe, because you are passing the bean name and return an Object. If we extend this approach to JPA, we'll have to consider caches, entity manager lifecycle combined with a prototype lifecycle, etc.

My view on DDD with spring is a bit different - you shouldn't use spring to manage your domain objects (if using JPA at least)

 

Ivica Loncar replied on Sun, 2010/05/23 - 4:59am in response to: Bozhidar Bozhanov

 Actually I have to agree: do not put DI inside your core domain model. DI is great when you have to  cross different architectural layers (and it makes your integration testing a lot easier), but I don't think it should be abused inside domain model - it's whole purpose is to be concise hard wired view of the world.

From my experience DI inside core domain reduces readability of code and that could lead to more bugs. 

 

Erdinç Kocaman replied on Sun, 2010/05/23 - 5:06am in response to: Bozhidar Bozhanov

The repository used here is specific to this example. If you want to use another persistency mechanism you must take into account the lifecycle of domain objects managed by that framework. Actually, I use Cayenne ORM as a persistency layer and try to apply DDD principles developing the applications. In Cayenne case, I used Spring as well, but Spring was managing the dependencies not the lifecycle of the domain objects. Maybe, I write an article about it also. I looked at the your blog and I agree with your opinion that business logic and infrastructure logic must be separate. Domain objects shouldn't care of underlying persistency mechanism.

Ori Dar replied on Sun, 2010/05/23 - 2:01pm

Overall, I think it's a nice introduction.

However coupling your domain model with Spring is a big Nay.

No need to manage your Book objects here as prototype beans.

There are few more elegant ways for date formatting I can think of  than injecting a formatting bean to them

 

 

 

 

 

Dapeng Liu replied on Sun, 2010/05/23 - 10:49pm

well, if this is for introduction of DDD, i think it would be a better idea to indicate some alternative design and implementations, so that we can compare and appreciate your implementation.

if this article is for advanced readers, then you should hide most of the boilerplate codes, and focus more on you main points

just my 2 cents

Sudhir Ni replied on Mon, 2010/05/24 - 1:06am

It'a a nice tutorials, however can you explain how will you solve the problems mentioned here http://solveme.wordpress.com/2009/11/11/ddd-without-any-orm-tool-is-it-possible/ Without any ORM tool.

Erdinç Kocaman replied on Mon, 2010/05/24 - 5:26am

The problems you have mentioned can be subject of another article, I don't think they are related to DDD directly.

Carlos Rodríguez replied on Tue, 2010/05/25 - 7:53pm

When you use JPA/Hibernate in your data access layer, you can't use createBean to get a new instance of the prototyped bean. In that case, you can use @Configurable and @Autowired to inject the required dependencies.

Alexander Ashitkin replied on Wed, 2010/06/02 - 1:55pm

all about spring, nothing about ddd

Liezel Jane Jandayan replied on Thu, 2011/08/11 - 6:25am

This class executes SQL queries or updates, initiating iteration over ResultSets and catching JDBC exceptions and translating them to the generic, more informative exception hierarch.

 Senior Healthcare Consultants

Manuel Enrique ... replied on Sat, 2011/08/20 - 2:23am

@Erdinç

I'm agree with some guys about your article, it is not related with DDD methodology at all, your Book class is Value Object like the antipattern Anemic domain model (review Martin Fowler) Maybe you forgot or you didn't know very well how to design an OO application using DDD methodology. (please review Eric Evans book : http://goo.gl/0Deoi) If your Book object would have some behavior (business logic), we could say that your article is a DDD related, but no.

It will be better that you change the content or the title, as you want. I suggest that you should do it.

Manuel Loayza SCEA.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.