1

I've started using Thymeleaf recently, and generally been getting on pretty well. However I'm trying to use a multiple select to populate a list of Enums that are wrapped up in an immutable.

I refactored it and it works using a POJO:

public enum Place {

    FIRST("First"),
    SECOND("Second"),
    THIRD("Third"),
    FOURTH("Fourth"),
    FIFTH("Fifth");

    private final String formatted;

    Place(String s) {
        formatted = s;
    }
    
    public String getFormatted() {
        return formatted;
    }
}
public class Places {

    private List<Place> places;
    // get/set/constructors omitted 


}
    @GetMapping("/complex")
    public ModelAndView complex() {
        Places places =  new Places(Place.THIRD);
        ModelAndView model = new ModelAndView("complex");
        model.addObject("filter", places);
        return model;
    }

    @RequestMapping(value = "/complex",
            method = RequestMethod.POST)
    public ModelAndView multiPost(@ModelAttribute Places places, ModelAndView model) {
        model.addObject("filter", places);
        model.setViewName("complex");
        System.out.println("post " + places.getPlaces());
        return model;
    }
    <form id="main_form" class="mainform"
          method="post" th:action="@{/complex}"
          th:object="${filter}">
        <div class="col-md-3">
            <label id="include">Included</label>
            <select class="form-select" aria-label=".form-select-sm example" multiple="multiple"
                    th:field="*{{places}}">
                <option th:each="state : ${T(uk.co.enums.Place).values()}"
                        th:value="${state}"
                        th:text="${state.getFormatted()}">
                </option>
            </select>
        </div>
        <input type="submit" value="Create">
    </form>

However, I'd like to be able to use an object created through the immutables library to replace the Places class.

@Value.Immutable
public interface Places {

    List<Place> places();
}

However this produces:

Caused by: org.springframework.core.convert.ConversionFailedException: 
Failed to convert from type [java.lang.String] to type [com.google.common.collect.ImmutableList<uk.co.enums.Place>] for value 'FIRST'; 
nested exception is java.lang.IllegalArgumentException: 
Could not instantiate Collection type: com.google.common.collect.ImmutableList

I created the converters (StringToListPlaceConverter and StringArrToPlacesConverter) and added them to the formatter registry which works, but ends up being similar in length to having a POJO, but with extra classes dotted around. These also seemed to require explicit use of the ImmutableList, which feels wrong to me:

public class StringToListPlaceConverter implements Converter<String, ImmutableList<Place>> {

    @Override
    public ImmutableList<Place> convert(String from) {
        System.out.println("from = " + from);
        return ImmutableList.of(Place.valueOf(from));
    }

}

Am I missing something annotation-wise with the immutables? Or is this something that needs to stay as plain as possible while interfacing between the web and java-side?

trickster
  • 75
  • 1
  • 9
  • 1
    I wouldn't say that it *needs* to stay as plain as possible. I would say that calling JPA picky is an understatement, and you will gain very little, if any, benefit from using complex assortments of classes coupled together through annotations. I would recommend using plain simple POJO's and enums for the entire process. – davidalayachew May 25 '22 at 19:25
  • 1
    Yeah, that seems fair. I guess I'll try and decouple the POJO and business logic using immutables. It's a fun game... – trickster May 25 '22 at 20:28

0 Answers0