In Spring MVC, it is currently possible to map a many-to-one relationship property using the autoGrowNestedPaths feature. However, there is no built-in support for mapping "-to-many" relationship properties when the request parameter names do not match the target property names.

For example, if a Movie entity has a "-to-many" relationship with Actor entities, and the form contains a multi-select dropdown with the name "actors" that allows the user to select multiple actors for the movie, the submitted request parameter values will be in the form of actors=[id1, id2, id3]. In order to map these values to the Movie entity's actors property, a custom Converter must be defined.

It would be helpful if Spring MVC could provide built-in support for mapping "-to-many" relationship properties with property paths in a similar way to how autoGrowNestedPaths works for many-to-one relationships. For example, it would be great if the following syntax could be used in the form field names to indicate that the values should be mapped to a nested property with the given path:

<select name="actors.id" multiple>
    <option value="1">Actor 1</option>
    <option value="2">Actor 2</option>
    <option value="3">Actor 3</option>
</select>
````
This would allow Spring to automatically map the submitted values to the Movie entity's actors property without the need for a custom Converter.

If this enhancement is accepted, I would be happy to help.

Thank you for considering this enhancement request!


**Comment From: sultan**

Here is the Generic Converter i am using to avoid making one per table.

```java
// Copyright (c) 2023 the original author or authors.

package fr.eni.movielibrary.converter;

import java.lang.reflect.*;
import java.util.*;
import java.util.regex.*;
import java.util.stream.*;

import org.springframework.beans.*;
import org.springframework.core.convert.*;
import org.springframework.core.convert.converter.*;
import org.springframework.stereotype.*;

/** @author Souheil SULTAN */
@Component
public class GenericCollectionConverter2 implements ConditionalGenericConverter {

    public final static String DEFAULT_ID_NAME = "id";
    public final static Pattern ID_ANNOTATION_PATTERN = Pattern.compile( "^(?:javax|jakarta).persistence.Id$" );

    @Override
    public Set<ConvertiblePair> getConvertibleTypes() {
        return null;
    }

    @Override
    public boolean matches( TypeDescriptor idType, TypeDescriptor beanType ) {
        final var idClass = idType.isArray() ? idType.getElementTypeDescriptor().getType() : idType.getType();
        return idClass.equals(String.class) && beanType.isCollection();
    }

    @Override
    public Object convert( Object idValues, TypeDescriptor idType, TypeDescriptor beanType ) {
        final var beanClass = beanType.getElementTypeDescriptor().getType();
        final var idField = Arrays.stream(beanClass.getDeclaredFields())
            .filter( f -> f.getName().equals(DEFAULT_ID_NAME) || Arrays.stream(f.getAnnotations())
                .map( a -> a.annotationType().getName() ).anyMatch( ID_ANNOTATION_PATTERN.asMatchPredicate() ))
            .findFirst().orElseThrow( () -> new UnknownFormatConversionException("No id field found for: "+beanClass) );
        final var idName = idField.getName();
        final var values = idType.isArray() ? Arrays.stream((Object[])idValues) : Stream.of(idValues);
        return values.map( id -> {
            final var bean = new BeanWrapperImpl(beanClass);
            bean.setPropertyValue( idName, id );
            return bean.getWrappedInstance();
        }).collect(Collectors.toList());
    }

}

Comment From: sultan

looks implemented now. should we close ?

works with attributes bindings.

    <tr>
        <th scope="row"><label th:for="name">Nom</label></th>
        <td><input th:field="*{name}" class="form-control" /></td>
        <td><span th:errorclass="text-danger" th:errors="*{name}"></span></td>
    </tr>

    <tr>
        <th scope="row"><label th:for="crust">Pâte</label></th>
        <td>
            <select th:field="*{crust}" class="form-control">
                <option value=""></option>
                <option th:each="crust:${crusts}" th:value="${crust.id}" th:text="${crust.name}"></option>
            </select>
        </td>
        <td><span th:errorclass="text-danger" th:errors="*{crust}"></span></td>
    </tr>

    <tr>
        <th scope="row"><label th:for="toppings">Ingrédients</label></th>
        <td>
            <select multiple th:field="*{toppings}" class="form-control">
                <option th:each="topping:${toppings}" th:value="${topping.id}" th:text="${topping.name}"></option>
            </select>
        </td>
        <td><span th:errorclass="text-danger" th:errors="*{toppings}"></span></td>
    </tr>

Comment From: snicoll

Thanks for following-up and sorry we didn't get to it sooner.