I have folowing entety.
package com.example.model; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; import java.util.Date; import org.hibernate.annotations.OnDelete; import org.hibernate.annotations.OnDeleteAction; import org.springframework.data.annotation.CreatedDate; @Entity @Table(name = "documents") public class Documents { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private int id; @Column(name = "date_created", nullable = false, updatable = false) @CreatedDate private Date date_created; @Column(name = "name") private String name; @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "type_id", nullable = false) @OnDelete(action = OnDeleteAction.CASCADE) private Documenttypes typeid; @Column(name = "file") private String file; public int getId() { return id; } public void setId(int id) { this.id = id; } public Date getDate_created() { return date_created; } public void setDate_created(Date date_created) { this.date_created = date_created; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Documenttypes getTypeid() { return typeid; } public void setTypeid(Documenttypes typeid) { this.typeid = typeid; } public String getFile() { return file; } public void setFile(String file) { this.file = file; } }
One of the fields called file is to upload the document. And the controller function for this is as follows:
public ModelAndView add(@ModelAttribute("documentsForm") Documents documents,@RequestParam("file") MultipartFile file) { //upload if (file.isEmpty()) { return new ModelAndView("redirect:/document/list"); } try { byte[] bytes = file.getBytes(); Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename()); documents.setFile("test"); Files.write(path, bytes); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } //end documentsService.addDocument(documents); return new ModelAndView("redirect:/document/list"); }
But then I try to upload file and submit a form I am getting this exception Failed to convert property value of type ‘org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile’ to required type ‘java.lang.String’ for property ‘file’; nested exception is java.lang.IllegalStateException: Cannot convert value of type ‘org.springframewo
Full error is:
2021-10-15 12:44:35.029 WARN 13500 --- [nio-8888-exec-5] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors Field error in object 'documentsForm' on field 'file': rejected value [org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile@2c2feacc]; codes [typeMismatch.documentsForm.file,typeMismatch.file,typeMismatch.java.lang.String,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [documentsForm.file,file]; arguments []; default message [file]]; default message [Failed to convert property value of type 'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile' to required type 'java.lang.String' for property 'file'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile' to required type 'java.lang.String' for property 'file': no matching editors or conversion strategy found]]
Advertisement
Answer
@ModelAttribute
will enable data binding from the HTTP request to @ModelAttribute
instance.
It will try to bind the value from the query parameter , field name of the form data and others (see this) to the @ModelAttribute
instance ‘s field provided that their names are matched.
In your case , as your controller method has a query parameter called file , it will try to bind its value to the Documents
‘s file field. As the file query parameter is in MultipartFile
type but Documents
is in String
type , it requires conversion but there are no Converter
registered for doing it.
Not sure if you really want to bind the content of the MultipartFile
to the Documents
‘s file field. If not, you can simply rename either one such that they are not matched.
Otherwise, you can implement a Converter
to convert MultipartFile
to String
:
public class MulitpartConverter implements Converter<MultipartFile, String> { @Override public String convert(MultipartFile source) { try { return new String(source.getBytes(), StandardCharsets.UTF_8); } catch (IOException e) { throw new RuntimeException("Fail to convert multipart file to string", e); } } }
And register it :
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addFormatters(FormatterRegistry registry) { registry.addConverter(new MulitpartConverter()); } }