I think in terms of REST, the ID should be placed into the URL, something like:

<https://example.com/module/[ID]>

and then I call GET, PUT, DELETE on that URL. That's kind of clear I think. In Spring MVC controllers, I'd get the ID with @PathVariable. Works.

Now, my practical problem with Spring MVC is, that if I do this, I have to NOT include the ID as part of the form (as well), Spring emits warnings of type 

```
Skipping URI variable 'id' since the request contains a bind value with the same name.

```

otherwise. And it also makes kind of sense to only send it once, right? What would you do if they don't match?? 

That would be fine, but I do have a custom validator for my form backing bean, that needs to know the ID! (It needs to check if a certain unique name is already being used for a different entity instance, but cannot without knowing the ID of the submitted form).

I haven't found a good way to tell the validator that ID from @PathVariable, since the validation happens even before code in my controller method is executed.

How would you solve this dilemma?

This is my Controller (modified):

```
@Controller
@RequestMapping("/channels")
@RoleRestricted(resource = RoleResource.CHANNEL_ADMIN)
public class ChannelAdminController
{
    protected ChannelService channelService;
    protected ChannelEditFormValidator formValidator;

    @Autowired
    public ChannelAdminController(ChannelService channelService, ChannelEditFormValidator formValidator)
    {
        this.channelService = channelService;
        this.formValidator = formValidator;
    }

    @RequestMapping(value = "/{channelId}/admin", method = RequestMethod.GET)
    public String editChannel(@PathVariable Long channelId, @ModelAttribute("channelForm") ChannelEditForm channelEditForm, Model model)
    {
        if (channelId > 0)
        {
            // Populate from persistent entity
        }
        else
        {
            // Prepare form with default values
        }
        return "channel/admin/channel-edit";
    }

    @RequestMapping(value = "/{channelId}/admin", method = RequestMethod.PUT)
    public String saveChannel(@PathVariable Long channelId, @ModelAttribute("channelForm") @Valid ChannelEditForm channelEditForm, BindingResult result, Model model, RedirectAttributes redirectAttributes)
    {
        try
        {
            // Has to validate in controller if the name is already used by another channel, since in the validator, we don't know the channelId
            Long nameChannelId = channelService.getChannelIdByName(channelEditForm.getName());
            if (nameChannelId != null && !nameChannelId.equals(channelId))
                result.rejectValue("name", "channel:admin.f1.error.name");
        }
        catch (EmptyResultDataAccessException e)
        {
            // That's fine, new valid unique name (not so fine using an exception for this, but you know...)
        }

        if (result.hasErrors())
        {
            return "channel/admin/channel-edit";
        }

        // Copy properties from form to ChannelEditRequest DTO
        // ...

        // Save
        // ...

        redirectAttributes.addFlashAttribute("successMessage", new SuccessMessage.Builder("channel:admin.f1.success", "Success!").build());
        // POST-REDIRECT-GET
        return "redirect:/channels/" + channelId + "/admin";
    }

    @InitBinder("channelForm")
    protected void initBinder(WebDataBinder binder)
    {
        binder.setValidator(formValidator);
    }
}

```