Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 617
Deniss M. Avatar asked Nov 24 '16 07:11

Deniss M.


1 Answers

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 (see accepted answer at How to collect and inject all beans of a given type in Spring XML configuration)
  • 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.

EDIT : since this post was first written, I came aware that Spring can auto-detect and inject all beans of a certain type, without the need of PostProcessors. See the accepted answer here : Autowire reference beans into list by type

like image 72
GPI Avatar answered Oct 29 '22 14:10

GPI