Jens Schauder
Jens Schauder

Reputation: 81998

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.

Upvotes: 6

Views: 1790

Answers (1)

Jens Schauder
Jens Schauder

Reputation: 81998

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.

Upvotes: 9

Related Questions