Невозможно внедрить @Repository в @Service

Я столкнулся со странной проблемой, когда не могу автоматически подключить @Repository к @Service... Вот код:

@SpringBootApplication
@EntityScan("com.example.api")
@EnableJpaRepositories("com.example.api")
public class ApiApplication {

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

}

Это базовый контроллер

package com.example.api.user.controller;
...
@RestController
public class UserController {

    @PostMapping(
        value = "/signup",
        consumes = MediaType.APPLICATION_JSON_VALUE,
        produces = MediaType.APPLICATION_JSON_VALUE
    )
    public ResponseEntity<Object> userSignUp(
        @RequestBody SignUpRequest request,
        SignUpHandler handler
        ) {
        return new ResponseEntity<>(handler.handle(request), HttpStatus.OK);
    }

И сам сервис:

package com.example.api.user.handler;
...
@Service
public class SignUpHandler {
    private final UserCrudRepository repository;

    @Autowired
    public SignUpHandler(UserCrudRepository repository) {
        this.repository = repository;
    }

    public SignUpResponse handle(SignUpRequest request) {
        User user = new User(...);
        this.repository.save(user);
        // then it does something and returns data,
        // not important for the question
    }
}

И репозиторий:

package com.example.api.user.repository;
...
@Repository
public interface UserCrudRepository extends CrudRepository<User, Long> {
    Optional<User> findByEmail(String email);
}

И хотя все соответствует документам и другим ответам на SO, я все еще не могу вызвать this.repository.save(user):

java.lang.NullPointerException: Cannot invoke \"com.example.api.user.repository.UserCrudRepository.save(Object)\" because \"this.repository\" is null
  1. Я попробовал указать @EnableJpaRepositories("com.example.api.user.repository"), не помогло. Однако я считаю, что Spring должен справиться с этим сам.
  2. Сервис SignUpHandler не создается вручную, он внедряется в метод, так что все должно быть в порядке, верно?
  3. У объекта User есть аннотация @Entity.
  4. Вообще-то у меня закончились идеи.

Есть ли у SignUpHandler еще один конструктор? Spring ModelAttributeMethodProcessor не смог бы создать экземпляр (модели) типа SignUpHandler с помощью этого конструктора.

Sotirios Delimanolis 24.08.2024 17:54
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
1
69
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я думаю, вам следует объявить SignUpHandler в классе UserController вместо того, чтобы получать его из параметров метода.

@Autowired
private SignUpHandler signUpHandler;

затем

return new ResponseEntity<>(signUpHandler.handle(request), HttpStatus.OK);

Хм, это работает. Но почему это работает, а внедрение метода — нет? Actuator фактически показывает экземпляр UserCrudRepository, если он введен через метод.

Kevin Kopf 24.08.2024 02:12

Параметры метода контроллера берутся из параметров http-запроса, а не из контекста Spring.

jinzuchi 24.08.2024 02:50
Ответ принят как подходящий

К сожалению, другие ответившие не удосужились объяснить, почему это не работает, поэтому мне пришлось углубиться в документацию. В любом случае, именно такого ответа следует ожидать от сообщества SO:

Spring явно определяет разрешенные аргументы метода контроллера в своей документации. В конце таблицы написано:

Любой другой аргумент. Если аргумент метода не соответствует ни одному из предыдущих значений в этой таблице и является простым типом (как определено BeanUtils#isSimpleProperty), он разрешается как @RequestParam. В противном случае это разрешается как @ModelAttribute.

Следовательно, когда я пытаюсь ввести SignUpHandler, он разрешается как @ModelAttribute, и Spring пытается привязать к нему параметры запроса, как если бы это был объект модели. Поэтому @Repository не вводится.

Чтобы это работало, SignUpHandler следует ввести через конструктор контроллера.

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

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