Создать собственный репозиторий для Spring Data JPA

Я пытаюсь создать custom repository, следуя этому руководству: https://www.baeldung.com/spring-data-jpa-method-in-all-repositories

Моя сборка приложения завершилась ошибкой:

NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.dao.ExtendedStudentRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

Мой полный исходный код: https://github.com/sesong11/springjpa-custom-repo

Подобных вопросов много, но ни один из них не решен для меня. Возможно, это проблема Spring в текущей версии 2.1.1, или я пропустил некоторую настройку.

Не могли бы вы убедиться, что у вас установлен java11 и ваша среда использует его для запуска кода?

Dmytro Chasovskyi 25.12.2018 11:10

Да. Моя другая программа также использует ту же настройку среды

Se Song 25.12.2018 11:13

Я использую OpenJDK 11

Se Song 25.12.2018 11:13

Вкалываю репо на тестирование github.com/sesong11/springjpa-custom-repo/blob/master/src/te‌ st /…

Se Song 26.12.2018 03:03
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
4
5 812
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Вам нужна аннотация в вашем реализованном классе. Вы должны добавить аннотацию @Component или @Service, чтобы Spring мог подобрать инъекцию.

@Component
public class ExtendedRepositoryImpl<T, ID extends Serializable>
extends SimpleJpaRepository<T, ID> implements ExtendedRepository<T, ID> {

Обычно такая ошибка связана с ответом, который я вам дал, и иногда я его получаю. Пожалуйста, посмотрите официальную документацию или другие рабочие примеры в github. Страница, на которую вы ссылаетесь, не всегда дает вам полный исходный код, а дает частичные или небольшие фрагменты реализации.

ibercode 25.12.2018 11:38

Для решения этой проблемы вам необходимо внести следующие изменения. Кроме того, я выполнил это с помощью JDK 8, поскольку у меня нет JDK 11 в моем локальном хранилище. Кроме того, я выполнил ExtendedStudentRepositoryIntegrationTest.java с целью воспроизведения проблемы.

  1. В StudentJPAH2Config.java необходимо добавить сканирование компонентов.
@Configuration
@ComponentScan("com.example.demo")
@EnableJpaRepositories(basePackages = "com.example.demo.dao", 
  repositoryBaseClass = ExtendedRepositoryImpl.class)
public class StudentJPAH2Config {
  1. В DemoApplication необходимо исправить имя базового пакета.
@SpringBootApplication
@ComponentScan("com.example.demo.dao")
@EntityScan("com.example.demo.entity")
@EnableTransactionManagement
public class DemoApplication {

Причина изменения №1 - отсутствие сканирования компонентов в тестовой конфигурации, Spring не смог найти зависимости в нужных пакетах. # 2 необходим, так как ваш Student.java находится внутри пакета com.example.demo.entity напрямую, а не в каком-либо его подпакете. Вы также можете указать @EntityScan в тестовом конфигурационном файле StudentJPAH2Config, но это не обязательно.

Теперь это решает сиюминутную проблему, с которой вы столкнулись, но, тем не менее, вас будут приветствовать некоторые другие проблемы, которые довольно просты, и вы сможете решить их отсюда.

Вы должны поместить аннотацию @Primary в класс ExtendedRepositoryImpl. Он должен работать.

Spring в принципе не может квалифицировать зависимость. @Primary гарантирует, что куда бы вы ни вводили зависимость для интерфейса ExtendedRepository, первым квалифицирующим bean-компонентом (классом) будет ExtendedRepositoryImpl.

Были внесены следующие изменения:

@SpringBootApplication
@ComponentScan("com.example.demo.dao")
@EntityScan("com.example.demo.entity")
@EnableJpaRepositories(basePackages = "com.example.demo.dao",
        repositoryBaseClass = ExtendedRepositoryImpl.class)
@EnableTransactionManagement
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }


}

и для класса StudentJPAH2Config

@Configuration
@ComponentScan("com.example.demo")
@EnableJpaRepositories(basePackages = "com.example.demo.dao",
        repositoryBaseClass = ExtendedRepositoryImpl.class)
public class StudentJPAH2Config {
    // additional JPA Configuration
}

Студенческий класс, в котором отсутствовал пустой конструктор:

@Entity
public class Student {

    public Student() {
    }

    public Student(long id, String name) {
        this.id = id;
        this.name = name;
    }

    @Id
    private long id;
    private String name;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

И результат

и состояние работы приложения

@DarrenForsythe Вы прочитали вопрос ?? вот вы хвастаетесь лучшими наработками ??? а вы решили проблему ??? просто внимательно прочитайте вопрос, прежде чем голосовать против.

Moshiour 29.12.2018 08:32

Да, я тоже смотрел исходный код. Возможно, прочтите документацию по Spring Boot. Это не приложение Spring Framework, требующее такого уровня конфигурации, просто потому, что оно работает, еще не значит, что это правильно.

Darren Forsythe 29.12.2018 13:12

@DarrenForsythe этих конфигураций можно было бы немного избежать. Но его цель не была целью этого вопроса. Вы говорите это просто для аргументации. Придерживайтесь сути дела, чтобы помочь людям, а не просто интересно здесь и там.

Moshiour 29.12.2018 13:16

Я сказал это, чтобы остановить распространение плохих конфигураций пружинных ботинок. Вы сами сказали, что их можно избежать. Так почему бы не следовать лучшим практикам? Это приложение для весенней загрузки, а не весенний фреймворк.

Darren Forsythe 04.01.2019 02:13

Вы должны удалить @ContextConfiguration(classes = { StudentJPAH2Config.class }) и добавить аннотации @SpringBootTest в свой тестовый класс ExtendedStudentRepositoryIntegrationTest, это устранит текущую ошибку NoSuchBeanDefinitionException.

Но снова у меня такая ошибка, как:

Caused by: java.lang.IllegalArgumentException: Not a managed type: class com.example.demo.entity.Student

это потому, что Spring не может сканировать Entity Student.

Для этого вам нужно сменить @EntityScan("com.example.demo.entity.*") на @EntityScan("com.example.demo.entity") в классе DemoApplication.

Опять я получил ошибку:

Caused by: org.springframework.data.mapping.PropertyReferenceException: No property attributeContainsText found for type Student!

Причина в том, что метод findByAttributeContainsText() не является допустимым.

Прежде чем запускать тест, давайте убедимся, что основное приложение запущено. Собственно, тут есть некоторые проблемы.

1. IllegalArgumentException: Неуправляемый тип: класс com.example.demo.entity.Student.

Проблема в @EntityScan("com.example.demo.entity.*"). Имя пакета неверно, поэтому класс Student не сканируется.

Решение - @EntityScan("com.example.demo.entity").

2. PropertyReferenceException: свойство attributeContainsText для типа Student не найдено!

Проблема в том, что базовый класс репозитория не установлен и JpaQueryLookupStrategy думают, что должны создать RepositoryQuery из имени метода findByAttributeContainsText. Он распознает шаблон findBy{EntityPropertyName} и не может найти поле attributeContainsText в Student.

Базовый класс репозитория не установлен, потому что конфигурация StudentJPAH2Config не применяется. Конфигурация не применяется, если ее невозможно сканировать. @ComponentScan("com.example.demo.dao") не сканирует пакет, в котором находится StudentJPAH2Config.

Решение - @ComponentScan("com.example.demo"), который будет сканировать как "com.example.demo", так и "com.example.demo.dao" пакеты 1.

Теперь, когда с приложением все в порядке, вернемся к тесту.

3. NoSuchBeanDefinitionException: Нет подходящего компонента типа com.example.demo.dao.ExtendedStudentRepository.

Проблема в том, что отсутствуют StudentJPAH2Config не составляет всей конфигурации и некоторые beans.

Решение состоит в том, чтобы перечислить все классы конфигурации.

@ContextConfiguration(classes = { StudentJPAH2Config.class, DemoApplication.class })

или

@ContextConfiguration(classes = DemoApplication.class)

или

@SpringBootTest

4. JpaSystemException: нет конструктора по умолчанию для объекта com.example.demo.entity.Student.

Проблема в том, что Hibernate2 требует конструктора по умолчанию для Student:

@Entity
public class Student {

    @Id
    private long id;
    private String name;

    public Student() {}

    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }

    // getters & setters

}

1@ComponentScan("com.example.demo.dao") is redundant since this package will be scanned because of @SpringBootApplication located in there.
2 Hibernate is the default JPA provider in Spring applications.

Лучший ответ, который я когда-либо видел. Спасибо!

Anton Kot 05.12.2019 16:33
Ответ принят как подходящий

Чтобы ваш тест заработал, вам необходимо сделать следующее:

1) Замените неправильное определение basePackages в StudentJPAH2Config на com.example.demo.dao, или лучше удалите его как избыточное:

@Configuration
@EnableJpaRepositories(repositoryBaseClass = ExtendedRepositoryImpl.class)
public class StudentJPAH2Config {
}

2) Также замените basePackages в @ComponentScan и @EntityScan в классе DemoApplication на com.example.demo.dao и com.example.demo.entity. Или лучше вообще удалить их и аннотации @EnableTransactionManagement:

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

3) Добавьте конструктор без аргументов к объекту Student.

4) Исправьте свой тестовый класс - используйте @DataJpaTest для тестирования уровня DAO и импортируйте свою конфигурацию StudentJPAH2Config:

@RunWith(SpringRunner.class)
@DataJpaTest
@Import(StudentJPAH2Config.class)
public class ExtendedStudentRepositoryIntegrationTest {
   //...
}

С этими исправлениями я успешно выполнил ваш тест.

Я не могу удалить @ComponentScan и @EntityScan, это ошибка Field * in * required a bean of type * that could not be found, когда я импортирую свой пример проекта в проект с несколькими модулями. Другие проблемы с моим другим модулем должны реализовывать конфигурацию с аннотацией @EnableJpaRepositories(repositoryBaseClass = SimpleJpaRepository.class) или @EnableJpaRepositories(repositoryBaseClass = ExtendedRepositoryImpl.class), иначе это ошибка required a bean of type * that could not be found

Se Song 31.12.2018 09:08

Другие вопросы по теме