Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to inject a dependency into a repository base class

The various @EnableXXXRepository annotations of Spring Data allow you to specify a custom base class for your repositories, which will be used as an implementation of methods in your repository.

If such a base class needs access to other beans in the ApplicationContext how does one get those injected? It doesn't work out of the box, because Spring Data instantiates those base classes itself, supporting only special store dependent constructor parameters.

Note: I created this answer in the chat to this now deleted question and thought it might be valuable for others, although the original question is gone.

like image 701
Jens Schauder Avatar asked Jul 27 '17 08:07

Jens Schauder


People also ask

How do you inject a dependency?

The injector class injects dependencies broadly in three ways: through a constructor, through a property, or through a method. Constructor Injection: In the constructor injection, the injector supplies the service (dependency) through the client class constructor.

What is repository injection?

Corticotropin repository injection comes as a long acting gel to inject under the skin or into a muscle. When corticotropin repository injection is used to treat infantile spasms, it is usually injected into a muscle twice a day for two weeks and then injected on a gradually decreasing schedule for another two weeks.

What is difference between dependency injection and repository pattern?

They really aren't comparable a repository is something you can inject via dependency injection. The aim of DI is to make your application loosely coupled. Rather than specify a concrete implementation you can specify an interface that defines a contract that an implementation must fulfil.


1 Answers

In the @Enable...Repository annotation specify a repositoryBaseClass and repositoryFactoryBeanClass. Like this:

@EnableMongoRepositories(
    repositoryBaseClass = MyBaseClass.class,
    repositoryFactoryBeanClass = MyRepositoryFactoryBean.class)

In that RepositoryFactoryBean class, you can use normal dependency injection, because it is a Spring Bean, so, for example, you can get an instance of SomeBean injected via the constructor, as shown below:

public class MyRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends MongoRepositoryFactoryBean<T,S,ID>{

    private final SomeBean bean;

    public MyRepositoryFactoryBean(Class repositoryInterface, SomeBean bean) {
        super(repositoryInterface);
        this.bean = bean;
    }

}

Your RepositoryFactoryBean now create an instance of a custom RepositoryFactory by overwriting 'getFactoryInstance'.

@Override
protected RepositoryFactorySupport getFactoryInstance(MongoOperations operations) {
    return new MyMongoRepositoryFactory(operations, bean);
}

While doing so, it can pass on the bean to be injected. bean in the example above.

And this factory finally instantiates your repository base class. Probably the best way to do it is to delegate everything to the existing factory class and just add injecting of the dependency to the mix:

public class MyMongoRepositoryFactory extends MongoRepositoryFactory {

    private final SomeBean bean;

    MyMongoRepositoryFactory(MongoOperations mongoOperations, SomeBean bean) {
        super(mongoOperations);
        this.bean = bean;
    }

    @Override
    protected Object getTargetRepository(RepositoryInformation information) {
        Object targetRepository = super.getTargetRepository(information);
        if (targetRepository instanceof MyBaseClass) {
            ((MyBaseClass) targetRepository).setSomeBean(bean);
        }
        return targetRepository;
    }
}

There is a complete working example on Github.

like image 94
Jens Schauder Avatar answered Sep 18 '22 12:09

Jens Schauder