Question

I've seen a few related questions on this topic but none that seem to exactly match what I'm after.

I have a form where I'd like the user to be able to select a number of items from a checkbox list (backed by an enum), and to receive that as a Set. I have the following (using days as an example)

My enum:

public enum Day {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
}

Sending the enum values to the page in the controller to be displayed as the options:

model.addAttribute("allDays", Day.values());

Writing the options as checkboxes and mapping to correct form field:

<form:form method="get" modelAttribute="filterForm" commandName="filterForm">
    <c:forEach items="${allDays}" var="item">
        <form:checkbox path="days" value="${item.name()}" label="${item.name()}"/>
    </c:forEach>
</form:form>

The form object backing the form:

public class FilterForm {

    private EnumSet<Day> days;

    public EnumSet<Day> getDays() {
        return days;
    }

    public void setDays(EnumSet<Day> days) {
        this.days = days;
    }
}

This works as far as showing the options correctly, but when I try to submit, I get an error:

org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors Field error in object 'filterForm' on field 'days': rejected value [0,1]; codes [typeMismatch.filterForm.days,typeMismatch.days,typeMismatch.java.util.EnumSet,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [filterForm.days,days]; arguments []; default message [days]]; default message [Failed to convert property value of type 'java.lang.String[]' to required type 'java.util.EnumSet' for property 'days'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type java.lang.String[] to type java.util.EnumSet for value '{0, 1}'; nested exception is java.lang.IllegalArgumentException: Could not instantiate Collection type: java.util.EnumSet] org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:111) org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:75) org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:156) org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:117) org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96) org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617) org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578) org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80) org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923) org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852) org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882) org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778) javax.servlet.http.HttpServlet.service(HttpServlet.java:621) javax.servlet.http.HttpServlet.service(HttpServlet.java:728)

Any idea what the problem is or if there is a better way to achieve this? Thanks

Was it helpful?

Solution

I managed to resolve this by changing my form to use Set instead of EnumSet, and I also modified the tag so that the submitted values would remain selected:

<form:form method="get" modelAttribute="filterForm" commandName="filterForm">
    <form:checkboxes items="${allDays}" path="days" />
</form:form>

And the Form:

public class FilterForm {

    private Set<Day> days;

    public Set<Day> getDays() {
        return days;
    }

    public void setDays(Set<Day> days) {
        this.days = days;
    }
}

OTHER TIPS

You just need to work with interfaces instead of implementations.

You can still use an EnumSet, but the declaration needs to use interfaces (it's a good practice anyway).

In other words, use the code provided by Abby's answer. Then, you can do stuff like:

filterForm.setDays(EnumSet.allOf(Day.class));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top