Search code examples
javaspringspring-mvcthymeleaf

Thymeleaf+ spring: MethodArgumentTypeMismatchException


I'm creating a simple web application(clothes shop) and having a problem with passing objects from view to controller. This is a piece of html code that displays all the items of clothing on the screen in the form of cards. Each of them has a button, clicking on which should invoke POST request and put this item in user's cart.

<div class="container">
  <div class="row row-cols-1 row-cols-sm-2 row-cols-md-4">
    <form class="card rounded-0 mt-1 px-2" method="post" th:action="@{/main/add/{item}(item = ${item})}" 
          th:each="item:${products}">
      <img class="card-img-top" src="/img/duetddoskonaly.jpg" alt="Card image cap">
      <div class="card-body">
        <h4 class="card-title" th:text="${item.name}">Card title</h4>
        <p class="card-text" th:text="${item.description}">
          No Description
        </p>
        <button type="submit" class="btn btn-dark">Добавить</button>
      </div>
    </form>
  </div>
</div>

@PostMapping itself:

@PostMapping("/add/{item}")
public String addProductToCart(@PathVariable(name = "item") Product product,
                                   @ModelAttribute("cart") Cart cart,
                                   RedirectAttributes attributes) {
    cart.addProduct(product);
    log.info("Processing cart {}", cart);
    return "redirect:/";
}

However, once I click the button I get this output:

2023-03-05 21:21:26.148 WARN 584 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'com.ivand.shopfullstack.model.Product'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.lang.Long] for value 'Product(id=25, name=Sneaker1, description=An amazing sneakers, sex=male, price=null, oldPrice=null, discount=null, hotProduct=null, image=null, category=Category(id=19, type=SHOES, name=Sneakers))'; nested exception is java.lang.NumberFormatException: For input string: "Product(id=25,name=Sneaker1,description=Anamazingsneakers,sex=male,price=null,oldPrice=null,discount=null,hotProduct=null,image=null,category=Category(id=19,type=SHOES,name=Sneakers))"]

I understand that the problem lies in the inability to convert query string parameters to object(with type Product). Is there any way to pass the object not the string query from view to controller? Please correct my question if it is incorrect.


Solution

  • It is generally a bad idea trying to put your whole class contents as a path or query parameter. I would advice to just put the id of the product into the URL and then in the controller, or in the service, fetch the product using the id.

    Something like this:

    @PostMapping("/add/{item}")
    public String addProductToCart(@PathVariable(name = "item") Long productId,
                                       @ModelAttribute("cart") Cart cart,
                                       RedirectAttributes attributes) {
        Product product = productService.getProduct(productId);
        cart.addProduct(product);
        log.info("Processing cart {}", cart);
        return "redirect:/";
    }