Over a million developers have joined DZone.

Rich Domain Objects and Spring Dependency Injection are Compatible

DZone's Guide to

Rich Domain Objects and Spring Dependency Injection are Compatible

· Java Zone ·
Free Resource

Atomist automates your software deliver experience. It's how modern teams deliver modern software.

I’m currently working in a an environment where most developers are Object-Oriented fanatics. Given that we develop in Java, I think that it is a good thing – save the fanatics part. In particular, I’ve run across a deeply-entrenched meme that states that modeling Rich Domain Objects and using Spring dependency injection at the same time is not possible. Not only is this completely false, it reveals a lack of knowledge of Spring features, one I’ll be trying to correct in this article.

However, my main point is not about Spring but about whatever paradigm one holds most dear, be it Object-Oriented Programming, Functional Programming, Aspect-Oriented Programming or whatever. Those are only meant to give desired properties to software: unit-testable, readable, whatever… So one should always focus on those properties than on the way of getting them. Remember:

When the wise man points at the moon, the idiot looks at the finger.

Back to the problem at hand. The basic idea is to have some bean having reference on some service to do some stuff (notice the real-word notions behind this idea…) so you could call:

The following is exactly what not to do:

public class TopCaller {
    private StuffService stuffService;
    public SomeBean newSomeBean() {
        return new SomeBeanBuilder().with(stuffService).build();
This design should be anathema to developers promoting unit-testing as the new() deeply couples the TopCaller and SomeBeanBuilder classes. There’s no way to stub this dependency in a test, it prevents testing the createSomeBean() method in isolation.

What you need is to inject SomeBean prototypes into the SomeBeanBuilder singleton. This is method injection and is possible within Spring with the help of lookup methods (I’ve already blogged about that some time ago and you should probably have a look at it).

public abstract class TopCaller {
    private StuffService stuffService;
    public SomeBean newSomeBean() {
        return newSomeBeanBuilder().with(stuffService).build();
    public abstract SomeBeanBuilder newSomeBeanBuilder();
With the right configuration, Spring will take care of providing a different SomeBeanBuilder each time the newSomeBeanBuilder() method is called. With this new design, we changed the strong coupling between TopCaller and SomeBeanBuilder to a soft coupling, one that can be stubbed in tests and allow for unit-testing.

In the current design, it seems the only reason for SomeBeanBuilder to exist is to pass the StuffService from the TopCaller to SomeBean instances. There is no need to keep it with method injection.

There are two different possible improvements:

  1. Given our “newfound” knowledge, inject:
    • method newSomeBean() instead of newSomeBeanBuilder() into TopCaller
    • StuffService directly into SomeBean

  2. Keep StuffService as a TopCaller attribute and pass it every time doStuff() is invoked

I would favor the second option since I frown upon a Domain Object keeping references to singleton services, unless there are many parameters to pass at every call. As always, there’s not a single best choice, but only contextual choices.

Also, I would also use explicit dependency management instead of some automagic stuff, but that another debate.

I hope this piece proved beyond any doubt that Spring does not prevent Rich Domain Model, far from it. As a general rule, know about tools you use and go their way instead of following some path just for the sake of it .

Get the open source Atomist Software Delivery Machine and start automating your delivery right there on your own laptop, today!


Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}