An intercession for a Bean

Recently I joined a new project team. We implement a microservice architecture using Spring Boot and several other cutting edge technology. While most team members are experienced programming in Java and Java EE, some of them are new to the Spring Framework and most are not quite familiar with how to structure Spring Beans properly.

In this post I will briefly explain how to implement a „good“ Bean (read Java class) and why following these simple rules will make your life easier. For this we’ll take a look at a basic Java class and then dissect it to understand what details make it a good Bean.

Interfaces 101

Just before we start dismantling a real Spring Bean, let’s have a look at the interface which the Bean implements.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

packagede.flaviait.blog.beans;

/**

* A service to manage {@link User}s.

*

* @author WaldemarBiller

*/

publicinterfaceUserService{

/**

* Persists the given {@link User} into the datastore.

*

* @param user the user to persist, must not be {@literal null}

* @return the persisted user or {@literal null}

* @throws UserExistsException in case when a user with same normalized name already exists

As usual the interface starts with a package declaration. No magic; please just avoid underscores in names.
It’s good style to provide a brief JavaDoc comment which states the general purpose of the interface. Don’t explain the world! The interface name should fit that purpose as well. An established naming pattern is to use an entity name and the kind of Bean type (in terms of Domain Driven Design, which knows Services, Repositories etc). If this doesn’t fit an adjective might be the right thing.

Each method the interface defines should also have a JavaDoc comment. The description usually starts with a verb.
For each parameter give a little description and tell the preconditions the parameter has to fulfill e.g. an integer being positive.
If the method throws a checked exception describe under which circumstances it is supposed to happen. Finally describe every possible kind of value that can be returned.
Following design by contract this JavaDoc is the contract for any implementing class. Implementors are not allowed to break it!

LOG.info("Looking up count of users with normalized name '{}",user.getNormalizedName());

if(repository.countByNormalizedName(user.getNormalizedName())>0){

thrownewUserExistsException(user.getNormalizedName());

}

LOG.info("Persisting user '{}'",user.getNormalizedName());

returnrepository.save(user);

}

@Override

publicUser update(User user){

Assert.notNull(user,"user must not be null");

LOG.info("Persisting user '{}'",user.getNormalizedName());

returnrepository.save(user);

}

@Override

publicbooleandelete(User user){

Assert.notNull(user,"user must not be null");

Integerid=user.getId();

LOG.info("Removing user '{}'",user.getNormalizedName());

repository.delete(user);

return!repository.exists(id);

}

}

Like almost every Java Class file this Spring Bean starts with a package declaration followed by the imports, and also sports a JavaDoc comment. Here you state what makes this implementation special and discriminates it from alternatives.

It’s good practice to divide the class into sections. A good order might be: inner classes, constants, members, dependencies, constructors, property methods, methods. But that’s just my preference.
Each class should have a logger if any necessary. Please declare it private, static and final! That way it has to be instantiated only once per class while still allowing to filter the logs properly.

Dependency Injection

The dependencies section features every dependency of the Bean. If a dependency is mandatory it should also be declared final. Please avoid field injection, as it harms you when you try to test the Spring Bean. Instead of this the constructor is annotated with @Autowired and every mandatory dependency is provided as a parameter. If your parameter list exceeds 5 items you should rethink your class structure and divide the Bean into several parts. Any optional dependency can be set via a setter, which has to be annotated with @Autowired, too.

Assert Parameters

Just like the method declarations in the interface the constructor defines a contract with preconditions. All preconditions can be checked for instance using Spring’s Assert helper class. You could also use Guava’s Preconditions class or some such, as long as it throws an IllegalArgumentException or some domain driven derivative if a precondition is violated. Please make sure to check the preconditions before any calculation!

The methods don’t need to have a JavaDoc comment as long as they just follow the contract which was defined in the interface. Keep it DRY!

That’s it. Spring Beans made easy.

The origin if the title picture is https://commons.wikimedia.org/wiki/File:Roasted_coffee_beans.jpg. It is in the public domain.