Вопрос:

Бин типа 'java.util.Function', который не может быть найден

java spring spring-boot dependency-injection spring-bean

115 просмотра

1 ответ

6442 Репутация автора

Основываясь на этом ответе, я пытаюсь настроить бин области запроса, используя java.util.Functionинтерфейс.

Моя конфигурация выглядит так:

@Configuration
public class RequestConfig {

    @Bean
    public Function<? extends BaseRequest, RequestWrapper<? extends BaseRequest, ? extends BaseResponse>> requestWrapperFactory() {
        return request -> requestWrapper(request);
    }

    @Bean
    @RequestScope
    public RequestWrapper<? extends BaseRequest, ? extends BaseResponse> requestWrapper(
            BaseRequest request) {
        RequestWrapper<?, ?> requestWrapper = new RequestWrapper<BaseRequest, BaseResponse>(request);
        return requestWrapper;
    }
}

И я пытаюсь использовать бин так:

@RestController
public class CheckRequestController {

    private final RequestService<CheckRequest, CheckResponse> checkRequestServiceImpl;

    @Autowired
    private Function<CheckRequest, RequestWrapper<CheckRequest, CheckResponse>> requestWrapperFactory;

    public CheckRequestController(
            RequestService<CheckRequest, CheckResponse> checkRequestServiceImpl) {
        super();
        this.checkRequestServiceImpl = checkRequestServiceImpl;
    }

    @PostMapping(value = "/check", consumes = { MediaType.TEXT_XML_VALUE,
            MediaType.MULTIPART_FORM_DATA_VALUE }, produces = MediaType.TEXT_XML_VALUE)
    public ResponseEntity<CheckResponse> checkRequest(
            @RequestBody(required = true) CheckRequest checkRequest) {

        RequestWrapper<CheckRequest, CheckResponse> requestWrapper = requestWrapperFactory
                .apply(checkRequest);
        checkRequestServiceImpl.getResponse(requestWrapper);

        return new ResponseEntity<CheckResponse>(requestWrapper.getResponse(),
                HttpStatus.OK);
    }
}

И здесь:

@RestController
public class CancelRequestController {

private final RequestService<CancelRequest, CancelResponse> cancelRequestServiceImpl;

@Autowired
private Function<CancelRequest, RequestWrapper<CancelRequest, CancelResponse>> requestWrapperFactory;

public CancelRequestController(
        RequestService<CancelRequest, CancelResponse> cancelRequestServiceImpl) {
    super();
    this.cancelRequestServiceImpl = cancelRequestServiceImpl;
}

@PostMapping(value = "/cancel", consumes = { MediaType.TEXT_XML_VALUE,
        MediaType.MULTIPART_FORM_DATA_VALUE }, produces = MediaType.TEXT_XML_VALUE)
public ResponseEntity<CancelResponse> CancelRequest(
        @RequestBody(required = true) CancelRequest cancelRequest) {
    RequestWrapper<CancelRequest, CancelResponse> requestWrapper = requestWrapperFactory
            .apply(cancelRequest);
    cancelRequestServiceImpl.getResponse(requestWrapper);
    return new ResponseEntity<CancelResponse>(requestWrapper.getResponse(),
            HttpStatus.OK);
}
}

Но я получаю исключение, что не определен боб типа Function.

  Field requestWrapperFactory in CheckRequestController required a bean of type 'java.util.Function' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'java.util.Function' in your configuration.

Есть ли проблема с использованием универсальных типов? Что я не прав?

Автор: Patrick Источник Размещён: 01.08.2019 02:20

Ответы (1)


3 плюса

77427 Репутация автора

Решение

Ответ, на который вы ссылаетесь, имеет различие: он использует один и тот же тип обобщенного типа в объявленном и введенном компонентах:

@Bean
public Function<String, Thing> thingFactory() {
    return name -> thing(name); // or this::thing
} 

а также :

@Autowired
private Function<String, Thing> thingFactory;

Есть ли проблема с использованием универсальных типов? Что я не прав?

Да. Вы хотите внедрить компонент с этой подписью:

Function<CheckRequest, RequestWrapper<CheckRequest, CheckResponse>> requestWrapperFactory;

Но вы объявили бин с этой подписью:

Function<? extends BaseRequest, RequestWrapper<? extends BaseRequest, ? extends BaseResponse>>

Вот :

@Bean
public Function<? extends BaseRequest, RequestWrapper<? extends BaseRequest, ? extends BaseResponse>> requestWrapperFactory() {
    return request -> requestWrapper(request);
}

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

Так что просто объявите одинаковые типы в обе стороны.

так что это означает, что нет способа сконфигурировать bean-компонент с использованием обобщений? потому что я хотел использовать создание бина также для CancelRequest (обновленный ответ). Поэтому я должен создать Бин для всех типов BaseRequest.

@RequestScopeТеоретически для bean-компонентов не должно возникать проблем с использованием обобщенных элементов, поскольку bean-компонент создается при каждом запросе и не используется повторно, но я думаю, что универсальные функции для @Beanэтого не имеют значения, поэтому рассмотрим общий случай (singleton scope), где идеальное соответствие необходимо, чтобы избежать проблем с безопасностью типов и согласованностью. Это может вас заинтересовать .


После вашего редактирования:

Я обновил первую часть, чтобы соответствовать вашим изменениям.

Теперь ваше требование объявляет функцию, которая возвращает клиенту прототип bean-компонента с универсальным типом, указанным клиентом.
Это возможно Но чтобы сделать его аккуратным, вы не должны использовать два bean-компонента: один для фабрики (singleton) и другой для создания RequestWrapperобъекта (прототипа).
Поскольку фабричный компонент не позволяет клиентам указывать общий тип, вам придется выполнять нежелательные uncast.
Вам также следует заменить @RequestScopeна, @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)потому что bean-объекты в области запроса не позволяют быть настолько настраиваемыми, как bean-компоненты singleton и прототипы в классе конфигурации.
Например, использование параметров или подстановочных знаков не работает хорошо.

Таким образом, идея заключается в объявлении bean-компонента-прототипа, который возвращается универсальным типом, зависит от параметра и цели.
О RequestConfig, лучше бы сейчас называться так RequestFactoryкак это его роль.

@Configuration
public class RequestFactory {

    @Bean
    @RequestScope
    public <T extends BaseRequest, U extends BaseResponse> RequestWrapper<T, U> requestWrapper(
            T request) {
        RequestWrapper<T, U> requestWrapper = new RequestWrapper<>(request);
        return requestWrapper;
    }

}

В контроллере введите конфигурационный компонент:

private RequestFactory requestFactory; // Change

public CheckRequestController(
        RequestService<CheckRequest, CheckResponse> checkRequestServiceImpl,
        RequestConfig requestConfig) {
    this.checkRequestServiceImpl = checkRequestServiceImpl;
    this.requestFactory = requestFactory; // Change
}

И теперь вы можете вводить прототип bean с желаемым, RequestWrapperкогда вам нужно:

@PostMapping(value = "/cancel", consumes = { MediaType.TEXT_XML_VALUE,
        MediaType.MULTIPART_FORM_DATA_VALUE }, produces = MediaType.TEXT_XML_VALUE)
public ResponseEntity<CancelResponse> CancelRequest(
        @RequestBody(required = true) CancelRequest cancelRequest) {
    RequestWrapper<CheckRequest, CheckResponse> requestWrapper = 
               requestFactory.requestWrapper(cancelRequest);
     //...
    return new ResponseEntity<CancelResponse>(requestWrapper.getResponse(),
            HttpStatus.OK);
}

Проверено, что сейчас, это выглядит работать.

Автор: davidxxx Размещён: 01.08.2019 02:30
Вопросы из категории :
32x32