Just like what we did with the entities the same approach can be used when creating the repository classes. And that is by grouping and extracting common functions into their own abstract classes. For repositories we just have to follow what we did with the entities, that means we will have an abstract repository class for each abstract entity. How does that look?
[show the categoryRepository class upward to its parent classes]
Here is our category repository class, it’s extending a businessEntity which is parameterized by Category – the entity it’s managing; and String – the primary key type of the entity. Going up we have EnableRepository, AuditableRepository – we can define functions here, and finally, the BaseRepository which extends the JpaRepository from Spring.
Now we have our entities and repositories in place. But take a look at the packages, did you find anything unusual? Yes, the main Spring Boot class is in com.terawarehouse package but we have entities and repositories in com.broodcamp, by Spring standard it will only load the classes from the package and sub-packages where the main class is defined. Therefore, we need to tell Spring to scan the com.broodcamp package as well. That can be done by annotating the main class with @ComponentScan, @EntityScan and @EnableJpaRepositories. The first two are non-trivial, so we will just check why we need to specify a repositoryBaseClass and repositoryFactoryBeanClass parameter in EnableJpaRepositories annotation.
First, let’s take a look at why we need to define a custom BaseRepositoryImpl class.
It extends Spring’s SimpleJpaRepository and implements our BaseRepository interface which overrides the save method.
Why? This is where one of our abstract classes fits in. Whenever we save an entity that extends an auditableEntity, we may want to save the timeStamp as well as the currently logged user. So we have this instanceof check and then get the name of the user from the injected CurrentUser class. However, it’s not that simple, it’s unfortunate but @Autowired doesn’t work in this place. And that is why we need to define a custom repositoryFactoryBean class.
There are methods of interest here, the getRepositoryBaseClass which returns our custom BaseRepositoryImpl class and the getTargetRepository. Now, what is SpringContextUtil? It implements ApplicationContextAware interface which notifies the instance of this class via the setApplicationContext of the ApplicationContext it runs in. This is where CurrentUser injection in the base repository implementation class is enabled.
Specifically in this line:
And that is how we can get the currentUser.name property in this class.
You can override other methods as well and implement depending on your requirements.
In our next video, we will create tests for our repository classes. Again this is Edward and thanks for watching. I hope you learn something from this lecture. I’m constantly updating the git repository so you might want to check it out and play around.