The following example works with Spring Framework 6.0, but not with 6.1:

class MyForm {
    private String name;
    private MultipartFile file;

    MyForm(String name, @Nullable MultipartFile file) {
        this.name = name;
        this.file = file;
    }

    // ...
}

@Controller
public class FileUploadController {
    @PostMapping("/form")
    public String handleFormUpload(MyForm form, BindingResult errors) {
        if (!form.getFile().isEmpty()) {
            byte[] bytes = form.getFile().getBytes();
            // store the bytes somewhere
            return "redirect:uploadSuccess";
        }
        return "redirect:uploadFailure";
    }
}

The above code throws the exception java.lang.IllegalStateException: No primary or single unique constructor found for interface org.springframework.web.multipart.MultipartFile if the file is not specified in the request.

The method DataBinder#shouldCreateObject(MethodParameter) was introduced with #31488. I think this method should also check whether the parameter is optional or not by calling MethodParameter#isOptional().

Comment From: snicoll

I think this method should also check whether the parameter is optional or not by calling MethodParameter#isOptional().

I am not sure about that. Can you check that you compile your code with -parameters, see the second paragraph of this section of the upgrade notes. And you should have seen a warning in the logs stating as much with 6.0.x. If that doesn't help, please move that code in text into a sample we can actually run. You can attach a zip to this issue or push the code to a separate GitHub repository.

Comment From: jhoeller

@rstoyanchev is the new check in DataBinder possibly mis-handling MultipartFile as a plain nested bind object there?

Comment From: mschneid

@snicoll But Spring Boot sets -parameters automatically:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <parameters>true</parameters>
  </configuration>
</plugin>

However, I have created a minimal, fully verifiable example here.

Comment From: snicoll

@mschneid apologizes, we've got many report around this and I thought it could have been one more occurrence.

Comment From: rstoyanchev

@mschneid, thanks for the sample. DataBinder is detecting correctly that the parameter is optional. The issue is related to a new feature in 6.1 where we nest recursively to apply constructor binding initialization to the arguments of a constructor. Part and MultipartFile arguments, however, should only be looked up.