tomdavies
tomdavies

Reputation: 1976

Spring MVC forms - model with reference to object

I created a form, that has 2 fields (product name and price) and dropdown list of category objects (product's categories). I have no idea how to make this work, when I have got a of Category objects to be set in Product object.

Product:

public class Product {
    private String name;
    private Category category;
    private int price;

    public Product() {
    }

    public Product(String name, Category category, int price) {
        this.name = name;
        this.category = category;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Category getCategory() {
        return category;
    }

    public void setCategory(Category category) {
        this.category = category;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

}

Product controller:

    @ModelAttribute("categoryList")
    public List<Category> categoryList() {
          return categoryService.getCategories();
    }

    @RequestMapping("/products/add")
    public ModelAndView addProductForm() {
        ModelAndView mv = new ModelAndView("addProduct");

        mv.addObject("product", new Product());
        return mv;
    }
    @RequestMapping(value = "/products/add/process", method = RequestMethod.POST)
    public ModelAndView addProduct(@ModelAttribute("product") Product product) {
        ModelAndView mv = new ModelAndView("products");
        System.out.println("added " + product.getName() + " " + product.getPrice());
        return mv;
    }

The form:

<form class="form-horizontal" action="#"
        th:action="@{/products/add/process}" th:object="${product}"
        method="post">
        <fieldset>

            <!-- Form Name -->
            <legend>Add product</legend>

            <!-- Text input-->
            <div class="form-group">
                <label class="col-md-4 control-label" for="textinput">Product
                    name</label>
                <div class="col-md-4">
                    <input id="textinput" name="textinput" placeholder="Product name"
                        class="form-control input-md" required="" type="text"
                        th:field="*{name}"></input>
                </div>
            </div>

            <!-- Select Basic -->
            <div class="form-group">
                <label class="col-md-4 control-label" for="selectbasic">Category</label>
                <div class="col-md-4">
                    <select th:field="*{category}">
                        <option th:each="cat : ${categoryList}" th:value="${cat.getId()}"
                            th:text="${cat.getName()}"></option>
                    </select>
                </div>
            </div>

            <!-- Text input-->
            <div class="form-group">
                <label class="col-md-4 control-label" for="textinput">Price</label>
                <div class="col-md-4">
                    <input id="textinput" name="textinput" placeholder=""
                        class="form-control input-md" required="" type="text"
                        th:field="*{price}"></input>
                </div>
            </div>

            <!-- Button -->
            <div class="form-group">
                <label class="col-md-4 control-label" for="singlebutton"></label>
                <div class="col-md-4">
                    <button id="singlebutton" name="singlebutton"
                        class="btn btn-success">Add product</button>
                </div>
            </div>
        </fieldset>
    </form>

Additional Info from comments
When I submit it (see addProduct method - it's a form handler) I get: java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [com.example.shop.Category] for property 'category': no matching editors or conversion strategy found]. I simply can't convert String coming from dropdown to an object

Upvotes: 1

Views: 3071

Answers (1)

t0mppa
t0mppa

Reputation: 4078

Problem is that Spring doesn't have a built-in conversion ability from String to Category. It knows it needs a Category to use the setCategory(Category category) method of Product, but has no way of converting the String it gets from your posted drop down into one. Thus, you need to be a dear and help Spring some by telling it how to do the conversion and define a converter, see Spring docs for more info.

Easiest option is to use Converter SPI:

package com.example.shop.converter;

final class StringToCategoryConverter implements Converter<String, Category> {
  public Category convert(String source) {
    Category category;

    // Put your conversion logic here

    return category;
  }
}

In your case, I'd guess you'll want to use: CategoryService.getCategory(int id) or a similar method.

Then you need to configure Spring to actually use your converter, here's an XML example of how to do that:

<mvc:annotation-driven conversion-service="conversionService" />

<bean id="conversionService"
      class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <bean class="com.example.shop.converter.StringToCategoryConverter" />
        </list>
    </property>
</bean>

Upvotes: 2

Related Questions