Автопроводка CrudRepository на основе параметра типа - PullRequest
0 голосов
/ 19 сентября 2018

Я хотел бы автоматически связать CrudRespository<Type,Key> в абстрактном родительском классе, а затем использовать его с дочерними классами.Ошибка говорит мне:

java.lang.IllegalStateException: Failed to load ApplicationContext
[...]
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'accountExtractor': Unsatisfied dependency expressed through field 'repository'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.data.repository.CrudRepository<com.finnwa.adwords.adconnect.Account, java.lang.Long>' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

Абстрактный родительский элемент, определяющий зависимость.

@Component
public abstract class Extractor<T,KEY> {

    @Autowired
    protected CrudRepository<T,KEY> repository;
   // some business logic
}

Дочерний класс, предоставляющий параметры.

@Component
class AccountExtractor extends Extractor<Account, Long>{
    // some config
}

Другие классы, которые могут иметь отношение:

public interface AccountRepository extends CrudRepository<Account, Long>{}

@SpringBootApplication
@EnableJpaRepositories(basePackages = "package.my")
public class Application {
    public static void main(String[] args) {
         SpringApplication.run(Application.class);
    }
}

Из других вопросов я узнал, что зависимость в родительском классе может быть не частной.Поэтому я сделал это защищенным.Что-нибудь, что я пропускаю?

РЕДАКТИРОВАТЬ: Таким образом, Пол Янссенс и М. Дейнум опубликовали несколько хороших обходных путей.Но почему это не работает?Что здесь не так?

Ответы [ 3 ]

0 голосов
/ 19 сентября 2018

Для начала я предлагаю не использовать инжекцию поля, а использовать конструктор.Я бы также предложил использовать определенный тип, так как в случае дженериков изменение заключается в том, что информация о типе удаляется.

Я бы, вероятно, сделал что-то вроде

public abstract class Extractor<T,KEY> {

  private final CrudRepository<T,KEY> repository;

  protected Extractor(CrudRepository<T, KEY> repository) {
    this.repository=repository;
  }
}

Затем в вашем конкретном классе используйте AccountRepository и передайте его суперклассу.

@Component
class AccountExtractor extends Extractor<Account, Long>{

  AccountExtractor(AccountRepository repository) {
    super(repository);
  }
}

Таким образом, в вашем суперклассе и методах вы все еще можете использовать базовый тип CrudRepository.Дополнительным преимуществом является также то, что теперь вы можете довольно легко написать модульный тест для AcountExtractor и просто смоделировать AccountRepository без необходимости загружать приложение Spring Boot.(Я знаю, что вы могли бы использовать @DataJpaTest, но простой макет быстрее).

0 голосов
/ 19 сентября 2018

просто используйте абстрактный метод и выполните подключение в подклассе

public abstract CrudRepository<T,KEY> getRepository();

...

FooRepository implements CrudRepository<Foo,Integer>

...

@Autowired
protected FooRepository repository;

@Override
public CrudRepository<Foo,Integer> getRepository() {
    return repository;
}
0 голосов
/ 19 сентября 2018

Я бы сказал, что AccountRepository не хватает "волшебной аннотации":

@Repository // This tells Spring Data to actually create a "standard" repository instance for us
public interface AccountRepository extends CrudRepository<Account, Long>{}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...