Search code examples
javaspring-bootswaggerspring-webfluxspringdoc

Spring boot 3 open api - Field of array in response class is not rendering


Thank you for the help in advance. I am using Spring boot webflux 3 with Spring doc Open API 2.4

Here is my response entity records

public record UserResponse(
  Integer id,
  String name,
  ScoreResponse scoreSummary
){

}
public record ScoreResponse(
  Integer avgScore,
  List<Score> score
){

  public record Score(
    Integer scoreId,
    Integer score
  ){

  }
}

Here is the handler class

@Component
@RequiredArgsConstructor
public class UserHandler {

  private final UserService userService;
  private final UserMapper userMapper;
  private final ClientAuthorizer clientAuthorizer;

  @Bean
  @RouterOperations({
      @RouterOperation(
          path = "/user/{userId}",
          produces = {MediaType.APPLICATION_JSON_VALUE},
          method = RequestMethod.GET,
          beanClass = UserHandler.class,
          beanMethod = "getById",
          operation = @Operation(
              description = "GET user by id", operationId = "getById", tags = "users",
              responses = @ApiResponse(
                  responseCode = "200",
                  description = "Successful GET operation",
                  content = @Content(
                      schema =  @Schema(
                          implementation = UserResponse.class
                      )
                  )
              ),
              parameters = {
                  @Parameter(in = ParameterIn.PATH,name = "userId")
              }
          )
      )
  })
  public @NonNull RouterFunction<ServerResponse> userIdRoutes() {
    return RouterFunctions.nest(RequestPredicates.path("/user/{userId}"),
        RouterFunctions.route()
            .GET("", this::getById)
            .build());
  }

  @NonNull
  Mono<ServerResponse> getById(@NonNull ServerRequest request) {
    String userId = request.pathVariable("userId");
    return authorize(request.method(), request.requestPath())
        .then(userService.getUserWithScore(userId))
        .flatMap(result -> ServerResponse.ok().body(Mono.just(result), UserResponse.class))
        .doOnEach(serverResponseSignal -> LoggingHelper.addHttpStatusToContext(serverResponseSignal, HttpStatus.OK));
  }
  ....
}

The expected example in Swagger UI is

{
  "id": 1073741824,
  "name": "string",
  "scoreSummary": {
    "avgScore": 1073741824,
    "score": [
      
      {
        "scoreId": 1073741824,
        "score": 1073741824
      }
    ]
  }
}

But actual example is

{
  "id": 1073741824,
  "name": "string",
  "scoreSummary": {
    "avgScore": 1073741824,
    "score": [
      "string"
    ]
  }
}

Additionally I can see an error in the UI

Errors
Resolver error at responses.200.content.application/json.schema.$ref
Could not resolve reference: JSON Pointer evaluation failed while evaluating token "score" against an ObjectElement

Please help me to find what I am missing.

After days of research I found this and it worked and I got expected result. But I need ro understand is there any better approach or is this fine.

Added below bean definition in my handler class.

@Bean
public OpenApiCustomizer schemaCustomizer() {
    ResolvedSchema resolvedSchema = ModelConverters.getInstance()
        .resolveAsResolvedSchema(new AnnotatedType(Score.class));
    return openApi - > openApi
        .schema(resolvedSchema.schema.getName(), resolvedSchema.schema);
}

Solution

  • Finally I found the solution for this. Somehow the reference is getting broken. Thus spring is removing those definitions. By adding below property in application.yaml file resolved my issue.

    springdoc:
      remove-broken-reference-definitions: false