使用 OpenAPI 生成的接口时不会注入服务

Services don't get injected when using OpenAPI generated interface

提问人:Syrious 提问时间:11/16/2023 最后编辑:Syrious 更新时间:11/16/2023 访问量:31

问:

使用 openApi 生成的接口时,服务不会注入到 MockMvc 测试中。让我告诉你。

控制器

@RestController
@Slf4j
@RequiredArgsConstructor
public class MyController implements MyApi {
    private final CodeService codeService;

    @Override
    @PutMapping("/path")
    public ResponseEntity<Void> putStuff(@RequestBody @Valid final Stuff stuff) {
        // do stuff
        return ResponseEntity.ok().build();
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    private ResponseEntity<ResponseWithError> handleException(final MethodArgumentNotValidException e, HttpServletRequest request) {
        log.error(e.getMessage());

        final ResponseWithError body = new ResponseWithError();
        body.setTimestamp(TimeUtil.getCurrentTimestampString());
        body.setId(UUID.randomUUID().toString());
        body.setMessage(e.getMessage());
        body.setPath(request.getRequestURI());
        body.code(codeService.getErrors(e.getAllErrors()));

        return ResponseEntity.badRequest().body(body);
    }
}

我的 Api

@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", date = "2023-11-15T16:01:27.640187200+01:00[Europe/Berlin]")
@Validated
@Tag(name = "stuff", description = "handles stuff")
public interface MyApi {

    default Optional<NativeWebRequest> getRequest() {
        return Optional.empty();
    }


    /**
     * PUT /stuff : creates stuff
     * creates stuff
     *
     * @param stuff (required)
     * @return OK (status code 200)
     * or CREATED (status code 201)
     * or UNAUTHORIZED (status code 401)
     * or BAD REQUEST (status code 400)
     * or INTERNAL SERVER ERROR (status code 500)
     */
    @Operation(
            operationId = "putStuff",
            summary = "creates stuff",
            description = "creates stuff",
            tags = {"stuff"},
            responses = {
                    @ApiResponse(responseCode = "200", description = "OK"),
                    @ApiResponse(responseCode = "201", description = "CREATED"),
                    @ApiResponse(responseCode = "401", description = "UNAUTHORIZED", content = {
                            @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseWithError.class))
                    }),
                    @ApiResponse(responseCode = "400", description = "BAD REQUEST", content = {
                            @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseWithError.class))
                    }),
                    @ApiResponse(responseCode = "500", description = "INTERNAL SERVER ERROR", content = {
                            @Content(mediaType = "application/json", schema = @Schema(implementation = ResponseWithError.class))
                    })
            },
            security = {
                    @SecurityRequirement(name = "bearerAuth")
            }
    )
    @RequestMapping(
            method = RequestMethod.PUT,
            value = "/path",
            produces = {"application/json"},
            consumes = {"application/json"}
    )
    default ResponseEntity<Void> putStuff(
            @Parameter(name = "stuff", description = "", required = true) @Valid @RequestBody Stuff stuff
    ) {
        return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
    }
}

测试

@WebMvcTest(controllers = {MyController.class}, excludeAutoConfiguration = {SecurityAutoConfiguration.class})
class MyControllerTest {
    @Autowired
    private MockMvc mvc;

    @MockBean
    private CodeService codeService;

    @Test
    void invalidRequest() throws Exception {
        // @GIVEN
        final Stuff stuff = new Stuff();
        stuff.setThings("");

        final String body = new ObjectMapper().writeValueAsString(stuff);

        given(codeService.getErrors(anyList())).willReturn(MY_VALIDATION_ERROR);

        // @WHEN
        mvc.perform(MockMvcRequestBuilders.put("/path")
                                          .contentType("application/json")
                                          .content(body));

        // @THEN
        // Assertions
    }
}
  • 我正在使用Spring-Boot 2.7.12
  • CodeService 带有 @Component 注释
  • MyApi 是 OpenAPI 生成的接口

执行测试时,它会触发异常并运行到处理程序中。一切都很好,直到它撞到线.不知何故没有被注入,但是 - 这是我不担心的事情 - 当我不使用生成的接口 MyApi 时,codeService 被注入并且测试按应有的方式运行。body.code(codeService.getErrors(e.getAllErrors()));codeService

有人可以解释一下,为什么当我使用 MyApi 接口时服务没有被注入?有没有办法让测试使用生成的 api?

编辑

  • 似乎是注解导致了这种行为。无论是直接注释控制器还是使用生成的接口。有人可以解释为什么吗?@Validated
弹簧 spring-boot spring-mvc openapi openapi-generator

评论

1赞 M. Deinum 11/16/2023
使控制器方法代替 .您也不需要接口上的,因此请将其删除。这导致创建代理,方法无法代理,因此在没有依赖项的代理上执行,而不是传递给实际包装的对象。publicprivate@Validated@Validatedprivate

答:

0赞 Syrious 11/16/2023 #1

正如 M. Deinum 所评论的那样,我将访问器更改为 public。不,它有效!