Deniss M. Deniss M. - 11 days ago 5
Java Question

Spring Data: multiple repository interfaces into a single 'repository' service class

I have quite some

JpaRepository
extended Repository interfaces due to the design of the database.

In order to construct a simple object i.e
Person
I have to make method calls to about 4 - 5 repositories just because the data is spread like that throughout the database. Something like this (pardon for pseudocode):

@Service
public class PersonConstructService {

public PersonConstructService(Repository repository,
RepositoryTwo repositoryTwo,
RepositoryThree repositoryThree) {

public Person constructPerson() {
person
.add(GetDataFromRepositoryOne())
.add(GetDataFromRepositoryTwo())
.add(GetDataFromRepositoryThree());

return person;
}

private SomeDataTypeReturnedOne GetDataFromRepositoryOne() {
repository.doSomething();
}

private SomeDataTypeReturnedTwo GetDataFromRepositoryTwo() {
repositoryTwo.doSomething();
}

private SomeDataTypeReturnedThree GetDataFromRepositoryThree() {
repositoryThree.doSomething();
}
}
}


PersonConstructService
class uses all these interfaces just to construct a simple
Person
object. I am calling these repositories from different methods inside the
PersonConstructService
class. I have thought about spreading this class into multiple classes, but I do not think this is correct.

Instead I would like to use a
repositoryService
which would include all the repositories listed necessary for creation of a
Person
object. Is that a good approach? Is it possible in Spring?

The reason I am asking is that sometimes the count of injected Services into a class is about 7-8. This is definitely not good.

GPI GPI
Answer

I do not think you can / shoudl create a meta-repository like abstraction. Repositories have a well defined meaning, conceptually, they are CRUD services (and a bit more sometimes :-)) for your Hibernate/JPA/Datastore entities. And I guess this is enough for them. Anything more is confusing.

Now what I would propose is a "smart" way of building your "Person" objects that is automa(g)tically aware of any new services that contribute to the meaning of the Person object.

The crux of it would be that :

  • you could have your Repositories implement a given Interface, say PersonDataProvider, which would have a method, say public PersonPart contributeDataToPersonBuidler(PersonBuilder).
  • You would make your @Service implement Spring's BeanFactoryPostProcessor interface, allowing you to inspect the container for all such PersonDataProvider instances, and inject them to your service.
  • Your @Service implementation would then be to ask all the PersonDataProviders in turn to ask them to contribute their data.

I could expand a bit, but this seems to me like the way to go.

One could argue that this is not clean (it makes your Repositories aware of "something" that happens at the service layer, and they should not have to), and one could work around that, but it's simpler to expose the gist of the solution that way.

Comments