2

I have integrated swagger in my spring boot project. All swagger endpoints are working fine but /product/swagger-ui.html is giving 400 error.

After some debugging I have found that there is conflict between two endpoints.

In my application.properties file, I am using server.contextPath=/product.

In my controller I have following mappings that I think have caused error.

ProductRestController.java

@RestController
public class ProductRestController {

    // some autowired services

    @GetMapping("/{id}")
    public ResponseEntity<ProductDTO> getProductById(
            @Min(value = 1, message = "id {javax.validation.constraints.Min.message}") @PathVariable Long id,
            @RequestAttribute Long tenantId) {
        return ResponseEntity.ok(productService.getProductById(id, tenantId));
    }

    @PutMapping("/{id}")
    public ResponseEntity<ProductDTO> updateProduct(
            @Min(value = 1, message = "id {javax.validation.constraints.Min.message}") @PathVariable Long id,
            @RequestBody HashMap<String, Object> requestBody, @RequestAttribute Long tenantId,
            @RequestAttribute Long userId) {

        ProductDTO productDTO;
        try {
            productDTO = objectMapper.convertValue(requestBody, ProductDTO.class);
        } catch (IllegalArgumentException e) {
            throw new HttpMessageNotReadableException(e.getMessage(), e);
        }

        Set<ConstraintViolation<ProductDTO>> errors = validator.validate(productDTO, ProductDTO.UpdateProduct.class);

        if (!errors.isEmpty()) {
            throw new ConstraintViolationException(errors);
        }

        return ResponseEntity.ok(productService.updateProduct(productDTO, requestBody, id, tenantId, userId));
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<?> deleteProduct(
            @Min(value = 1, message = "id {javax.validation.constraints.Min.message}") @PathVariable Long id,
            @RequestAttribute Long tenantId,
            @RequestParam(required = false, name = "delete_members") boolean deleteMembers) {
        productService.deleteProduct(id, tenantId, deleteMembers);
        return ResponseEntity.status(HttpStatus.NO_CONTENT).body(null);
    }

    //other mappings
}

I debugged and found that HandlerExecutionChain has forwarded this request to getProductById method and then it threw exception cannot cast from String to Long.

So I removed that mapping and again checked if it's working but this time I got HTTP 405 error. Again by debugging I found that stack trace is showing allowed methods are PUT & DELETE.

Then I removed both those mappings and checked, and it's working fine.

What I understood From this is somehow spring is picking /product/{id} mapping for /product/swagger-ui.html endpoint & then it throws error because of type mismatch.

Question is why is this happening and how to resolve this issue?

EDIT : Exception caught in DispatcherServlet.doDispatch method: org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Long'; nested exception is java.lang.NumberFormatException: For input string: "swagger-ui"

Exception caught in same method after removing GET mapping: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported

Harshit
  • 1,334
  • 1
  • 9
  • 23

3 Answers3

2

@GetMapping("/{id}") gives id value in String, and you are directly trying to map String to Long. Try to use: @PathVariable String id and then convert your String to Long as following:

Long longId = Long.parseLong(id);
Kaushal28
  • 5,377
  • 5
  • 41
  • 72
  • I have tried that but Spring still picks wrong handler, i.e. it picks /{id} handler and then gives error for `@Min` validation – Harshit Mar 07 '18 at 13:17
  • I have removed that validation too and now code within getProductById is executed and it throws error for parsing. – Harshit Mar 07 '18 at 13:18
  • but there are no ambiguous handlers, how it picks wrong handler? – Kaushal28 Mar 07 '18 at 13:20
  • that's what my question is. If I remove all those /{id} mappings then swagger endpoint works fine. – Harshit Mar 07 '18 at 13:23
  • I got similar kind of errors few days back and here what I look for : 1. Check if you have any GET end point without value = "\" 2. Comment all end points having Long in method argument and then try to run by only keeping one or two end points. As per error trace it seems error of parsing String to Long which is not correct. Give github URL to examine the code. – Hiren Sep 04 '19 at 17:56
0

You were right: by doing /{id} spring assumes that swagger-ui.html is an id. This is the url if your baseUrl=/ : http://localhost:8080/swagger-ui.html

0

Though its an old thread, providing my view just in case it helps someone.

The swagger URL is pointing to the ProductRestController, as it doesn't have any context-path of its own. So, to resolve it, try adding a context-path to the ProductRestController, something like @RequestMapping("v1").

Then your swagger URL of http://localhost:8080/swagger-ui.html should work, as it will not point to any controller.