MJBZA
MJBZA

Reputation: 5018

Make `Autowired` inside the run method

I have a small spinet of Java code:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import me.cimply.ask.odata.repository.*;

@Component
public class Runner implements CommandLineRunner {

    private static final Logger log = LoggerFactory.getLogger(Runner.class);

    @Autowired
    private IconRepository iconRepository;

    @Autowired
    private UserRepository userRepository;

    @Override
    public void run(String... args) throws Exception {
        this.fillRepository(iconRepository);
        this.fillRepository(userRepository);
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private void fillRepository(BaseRepository repository) {
       // Code
    }
}

I want to make this code as generic as possible.

I would like to extract the names of all the interfaces inside the me.cimply.ask.odata.repository package and generate the instances of them in a loop in the run method or in the constructor of the class and invoke the fillRepository method for them.

In the other word, I would like to only add new interfaces inside the me.cimply.ask.odata.repository package and the above code is run for them too, without adding any new line of code each time here. Something like this pseudocode:

import me.cimply.ask.odata.repository.*;

@Component
public class Runner implements CommandLineRunner {

    private static final Logger log = LoggerFactory.getLogger(Runner.class);

    private BaseRepository repositories[];

    public Runner(){
       for(InterfaceX in me.cimply.ask.odata.repository.*){
          repositories.push(new Autowired instance of InterfaceX);
       }
    }

    @Override
    public void run(String... args) throws Exception {
        for(repo in repositories)
           this.fillRepository(repo);
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private void fillRepository(BaseRepository repository) {
       // Code
    }
}

Please note BaseRepository is an interface in the me.cimply.ask.odata.repository package that all other interfaces implement that!

I searched a lot, and it seems the Autowired must be defined as a class property, anyway maybe someone know a technique to implement this idea!

Upvotes: 0

Views: 127

Answers (2)

dominikbrandon
dominikbrandon

Reputation: 428

If every of your repositories implement BaseRepository, then you can do that:

import me.cimply.ask.odata.repository.*;

@Component
public class Runner implements CommandLineRunner {

    private List<BaseRepository> repositories;

    @Autowired
    public Runner(List<BaseRepository> repositories){
       this.repositories = repositories;
    }

    @Override
    public void run(String... args) throws Exception {
        for(BaseRepository repo : repositories)
           this.fillRepository(repo);
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private void fillRepository(BaseRepository repository) {
       // Code
    }
}

Upvotes: 1

knittl
knittl

Reputation: 265928

If you have several beans implementing a common interface, define a dependency on the list of interfaces and Spring will give you all the available implementations:

@Component
public class Runner {
    private final List<Interface> beans;

    @Autowired
    public Runner(final List<Interface> beans) {
        this.beans = beans;
        // beans will contain Bean1, Bean2, Bean3
    }
}

public interface Interface {}

@Component
public class Bean1 implements Interface {}

@Component
public class Bean2 implements Interface {}

@Component
public class Bean3 implements Interface {}

Upvotes: 1

Related Questions