Binding Select List Objects in Spring Webflow

50 Views Asked by At

I have a select list bound to Java POJOs on a thymeleaf form. I want to populate the model with the object selected from this list.

The form below works perfectly fine when using spring boot controllers and the species object is bound to the animal model. The problem arises when I use Spring Boot WebFlow. The object fails to bind.

<form id="registration-form" th:object="${animal}"
    th:action="${flowExecutionUrl}" method="post">
    <div class="row"><div class="col">
        <label for="species">Species</label> 
        <select  th:value="*{species}" id="species" name="species" class="form-control">
            <option selected disabled value="">-Choose-</option>
            <option th:each="species : ${speciess}" 
                th:value="${species.id}" 
                th:text="${species.description}">
            </option>
        </select>
    </div></div>
    <div class="form-group row"><div class="col-sm-10">
        <button type="submit" class="btn btn-primary" name="_eventId_next">Next
        &raquo;</button>

    </div></div>
</form>

My Flow mapping is as follows:

<on-start>
    <evaluate expression="animalServiceImpl.init()" result="flowScope.animal"/>
</on-start>

<view-state id="start" view="my/animal/new" model="flowScope.animal">
    <on-render>
        <evaluate expression="holdingServiceImpl.findAll()" result="requestScope.holdings"/>
        <evaluate expression="colorServiceImpl.findAll()" result="requestScope.colors"/>
        <evaluate expression="genderServiceImpl.findAll()" result="requestScope.genders"/>
        <evaluate expression="arrivalTypeServiceImpl.findAll()" result="requestScope.arrivalTypes"/>
        <evaluate expression="speciesServiceImpl.findAll()" result="requestScope.speciess"/>
        <evaluate expression="baitsTagsServiceImpl.findAll()" result="requestScope.baitsTags"/>
        <evaluate expression="customTagServiceImpl.findAll()" result="requestScope.customTags"/>
        <evaluate expression="breedServiceImpl.findAll()" result="requestScope.breeds"/>
    </on-render>
    <transition on="next" to="confirmation"/>
    <transition on="cancel" to="registrationCancelled" validate="false" bind="false" /> 
</view-state>

<view-state id="confirmation" view="my/animal/confirm" model="flowScope.animal">
    <transition on="back" to="start" />
    <transition on="submit" to="submitRegistration"/>
    <transition on="cancel" to="registrationCancelled" />
</view-state> 

I get the following error when submitting the form:

[TargetAccessError@ecf873b mapping = parameter:'species' -> species, code = 'typeMismatch', error = true, errorCause = org.springframework.binding.expression.ValueCoercionException: Value could not be converted to target class; is a suitable type converter registered?, originalValue = 'bd8e962f-b334-4599-af69-d10352399b50', mappedValue = [null]]

The id of the Species object is UUID.

Please assist on what I can do to resolve this problem.

I tried changing the select option th::value to "species" as below but that resulted in the error below:

            <option th:each="species : ${speciess}" 
                th:value="${species}" 
                th:text="${species.description}">
            </option>

, code = 'propertyNotFound', error = true, errorCause = org.springframework.binding.expression.PropertyNotFoundException: Property not found, originalValue = [null], mappedValue = [null]], [TargetAccessError@1745e0fe mapping = parameter:'species' -> species, code = 'typeMismatch', error = true, errorCause = org.springframework.binding.expression.ValueCoercionException: Value could not be converted to target class; is a suitable type converter registered?, originalValue = 'Species{id=bd8e962f-b334-4599-af69-d10352399b50, description='Sheep'}', mappedValue = [null]],

1

There are 1 best solutions below

0
Patrick Andrew Jansen On

I solved this problem by using the following code after going through the Spring WebFlow engine source code:

    @Bean(name="conversionService")
    GenericConversionService conversionService() {
        GenericConversionService generic=new GenericConversionService();
        generic.addConverter("StringToSpecies", new StringToSpeciesConverter());
        return generic;
    }
    @Bean
    FlowBuilderServices flowBuilderServices() {
        
        return getFlowBuilderServicesBuilder() //
                .setConversionService(this.conversionService())
                .setViewFactoryCreator(this.mvcViewFactoryCreator()) // Important!
                .setValidator(this.localValidatorFacotryBean).build();
    }

I hope this neatly solves the problem for others. Please note that the Converter you are implementing should be of type org.springframework.binding.convert.converters.Converter and be consistent with that.