2

I am modifying the spring petclinic application to import a document from the user's computer into MySQL. I am using the jpa architecture from the petclinic application, which employs an EntityManager object in repository files. I understand I need to use the following syntax to expose a session object from the EntityManager and then create a blob to insert into the database:

Session session = em.unwrap(Session.class);//em is an EntityManager
Blob blob = (blob)Hibernate.getLobCreator(session).createBlob(document.getFile().getInputStream(), document.getFile().getSize());

In accordance with the petclinic jpa architecture, I am using five java files:

View/JSP: CreateOrUpdateDocument.jsp
Model: Document.java
Controller: DocumentController.java
Repository: JpaDocumentRepository.java
Service: ClinicServiceImpl.java  

My question is where to put it and how to set it up. Now, my code is throwing the following exception, which I think is related to the fact that the file property of Document.java is not given any annotation:

org.hibernate.MappingException: Could not determine type for:  
org.springframework.web.multipart.MultipartFile, at table:  
documents, for columns: [org.hibernate.mapping.Column(file)

I will include relevant portions of each file, the stack trace, and the sql definition of the documents table, below. What changes do I need to make in order for the document to successfully make it from the user's computer into the documents table of the MySQL database on the server?

CreateOrUpdateDocument.jsp:

<html lang="en">
<jsp:include page="../fragments/headTag.jsp"/>
<body>
<script>
    $(function () {$("#created").datepicker({ dateFormat: 'yy/mm/dd'});});
</script>
<div class="container">
    <jsp:include page="../fragments/bodyHeader.jsp"/>
    <c:choose>
        <c:when test="${document['new']}">
            <c:set var="method" value="post"/>
        </c:when>
        <c:otherwise>
            <c:set var="method" value="put"/>
        </c:otherwise>
    </c:choose>
    <h2>
        <c:if test="${document['new']}">New </c:if>
        Document
    </h2>
    <form:form modelAttribute="document" method="${method}" enctype="multipart/form-data"
               class="form-horizontal">
        <div class="control-group" id="patient">
            <label class="control-label">Patient </label>
            <c:out value="${document.patient.firstName} ${document.patient.lastName}"/>
        </div>
        <petclinic:inputField label="Name" name="name"/>
        <petclinic:inputField label="Description" name="description"/>
        <div class="control-group">
            <petclinic:selectField name="type" label="Type " names="${types}" size="5"/>
        </div>
        <td><input type="file" name="file" id="file"></input></td>
        <div class="form-actions">
            <c:choose>
                <c:when test="${document['new']}">
                    <button type="submit">Add Document</button>
                </c:when>
                <c:otherwise>
                    <button type="submit">Update Document</button>
                </c:otherwise>
            </c:choose>
        </div>
    </form:form>
    <c:if test="${!document['new']}">
    </c:if>
    <jsp:include page="../fragments/footer.jsp"/>
</div>
</body>
</html>

Document.java:

@Entity
@Table(name = "documents")
public class Document {
    @Id
    @GeneratedValue
    @Column(name="id")
    private Integer id;

    @ManyToOne
    @JoinColumn(name = "client_id")
    private Patient patient;

    @ManyToOne
    @JoinColumn(name = "type_id")
    private DocumentType type;

    @Column(name="name")
    private String name;

    @Column(name="description")
    private String description;

    @Column(name="filename")
    private String filename;

    @Column(name="content")
    @Lob
    private Blob content;

    @Column(name="content_type")
    private String contentType;

    @Column(name = "created")
    private Date created;

    private MultipartFile file;

    public Integer getId(){return id;}
    public void setId(Integer i){id=i;}

    protected void setPatient(Patient patient) {this.patient = patient;}
    public Patient getPatient(){return this.patient;}

    public void setType(DocumentType type) {this.type = type;}
    public DocumentType getType() {return this.type;}

    public String getName(){return name;}
    public void setName(String nm){name=nm;}

    public String getDescription(){return description;}
    public void setDescription(String desc){description=desc;}

    public String getFileName(){return filename;}
    public void setFileName(String fn){filename=fn;}

    public Blob getContent(){return content;}
    public void setContent(Blob ct){content=ct;}

    public String getContentType(){return contentType;}
    public void setContentType(String ctype){contentType=ctype;}

    public void setCreated(){created=new java.sql.Date(System.currentTimeMillis());}
    public Date getCreated() {return this.created;}

    public MultipartFile getFile(){return file;}
    public void setFile(MultipartFile f){file=f;}

    @Override
    public String toString() {return this.getName();}
    public boolean isNew() {return (this.id == null);}
}

Here is DocumentController.java. Note processCreationForm() method handles the form from jsp:

@Controller
@SessionAttributes("document")
public class DocumentController {
    private final ClinicService clinicService;

    @Autowired
    public DocumentController(ClinicService clinicService) {this.clinicService = clinicService;}

    @ModelAttribute("types")
    public Collection<DocumentType> populateDocumentTypes() {return this.clinicService.findDocumentTypes();}

    @InitBinder
    public void setAllowedFields(WebDataBinder dataBinder) {dataBinder.setDisallowedFields("id");}

    @RequestMapping(value = "/patients/{patientId}/documents/new", method = RequestMethod.GET)
    public String initCreationForm(@PathVariable("patientId") int patientId, Map<String, Object> model) {
        Patient patient = this.clinicService.findPatientById(patientId);
        Document document = new Document();
        patient.addDocument(document);
        model.put("document", document);
        return "documents/createOrUpdateDocumentForm";
    }

    //THIS IS THE METHOD THAT HANDLES THE FORM
    @RequestMapping(value = "/patients/{patientId}/documents/new", headers = "content-type=multipart/*", method = RequestMethod.POST)
    public String processCreationForm(@ModelAttribute("document") Document document, BindingResult result, SessionStatus status, @RequestParam("file") final MultipartFile file) {
        document.setCreated();
        document.setFile(file);
        new DocumentValidator().validate(document, result);
        if (result.hasErrors()) {return "documents/createOrUpdateDocumentForm";}
        else {
            this.clinicService.saveDocument(document);
            status.setComplete();
            return "redirect:/patients?patientID={patientId}";
        }
    }

    @RequestMapping(value = "/patients/*/documents/{documentId}/edit", method = RequestMethod.GET)
    public String initUpdateForm(@PathVariable("documentId") int documentId, Map<String, Object> model) {
        Document document = this.clinicService.findDocumentById(documentId);
        model.put("document", document);
        return "documents/createOrUpdateDocumentForm";
    }

    @RequestMapping(value = "/patients/{patientId}/documents/{documentId}/edit", method = {RequestMethod.PUT, RequestMethod.POST})
    public String processUpdateForm(@ModelAttribute("document") Document document, BindingResult result, SessionStatus status) {
        new DocumentValidator().validate(document, result);
        if (result.hasErrors()) {return "documents/createOrUpdateDocumentForm";}
        else {
            this.clinicService.saveDocument(document);
            status.setComplete();
            return "redirect:/patients/{patientId}";
        }
    }
}

JpaDocumentRepository.java. Note the save() method should handle the blob document:

@Repository
public class JpaDocumentRepositoryImpl implements DocumentRepository {
    @PersistenceContext
    private EntityManager em;

    @Override
    @SuppressWarnings("unchecked")
    public List<DocumentType> findDocumentTypes() {
        return this.em.createQuery("SELECT dtype FROM DocumentType dtype ORDER BY dtype.name").getResultList();
    }

    @Override
    public Document findById(int id) {return this.em.find(Document.class, id);}

    @Override
    public void save(Document document) {
        try {
            Session session = em.unwrap(Session.class);
            Blob blob = (Blob) Hibernate.getLobCreator(session).createBlob(document.getFile().getInputStream(), document.getFile().getSize());
            document.setFileName(document.getFile().getOriginalFilename());
            document.setContent(blob);
            document.setContentType(document.getFile().getContentType());
        } catch (IOException e) {e.printStackTrace();}      
        if (document.getId() == null) {this.em.persist(document);}
        else {this.em.merge(document);}
    }

    @Override
    public List<Document> list() throws DataAccessException {
       return this.em.createQuery("SELECT doc FROM Document doc ORDER BY doc.name").getResultList();
    }

    @Override
    public void remove(Integer id) throws DataAccessException {
        Document thisdoc = em.find(Document.class, id);
        em.remove(thisdoc);
    }

}

ClinicServiceImpl.java:

@Service
public class ClinicServiceImpl implements ClinicService {
    private DocumentRepository documentRepository;
    private PatientRepository patientRepository;

    @Autowired
    public ClinicServiceImpl(DocumentRepository documentRepository, PatientRepository patientRepository) {
        this.documentRepository = documentRepository;
        this.patientRepository = patientRepository;
    }

    //Other methods

    @Override
    @Transactional
    public void saveDocument(Document doc) throws DataAccessException {documentRepository.save(doc);}
}

Here is the stack trace:

ERROR ContextLoader - Context initialization failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0' defined in class path resource [spring/business-config.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [spring/business-config.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: petclinic] Unable to build EntityManagerFactory  

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:529) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:296) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:293) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:741) ~[spring-context-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464) ~[spring-context-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389) ~[spring-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294) ~[spring-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112) [spring-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4939) [catalina.jar:7.0.42]
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434) [catalina.jar:7.0.42]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) [catalina.jar:7.0.42]
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) [catalina.jar:7.0.42]
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) [catalina.jar:7.0.42]
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) [na:1.6.0_29]
    at java.util.concurrent.FutureTask.run(FutureTask.java:138) [na:1.6.0_29]
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) [na:1.6.0_29]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) [na:1.6.0_29]
    at java.lang.Thread.run(Thread.java:662) [na:1.6.0_29]  

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [spring/business-config.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: petclinic] Unable to build EntityManagerFactory  

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1512) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:296) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:293) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:438) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:277) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.detectPersistenceExceptionTranslators(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.<init>(PersistenceExceptionTranslationInterceptor.java:79) ~[spring-tx-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.dao.annotation.PersistenceExceptionTranslationAdvisor.<init>(PersistenceExceptionTranslationAdvisor.java:71) ~[spring-tx-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor.setBeanFactory(PersistenceExceptionTranslationPostProcessor.java:85) ~[spring-tx-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1532) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1500) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    ... 20 common frames omitted  

Caused by: javax.persistence.PersistenceException: [PersistenceUnit: petclinic] Unable to build EntityManagerFactory
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:923) ~[hibernate-entitymanager-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:898) ~[hibernate-entitymanager-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:76) ~[hibernate-entitymanager-4.2.1.Final.jar:4.2.1.Final]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:288) ~[spring-orm-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:310) ~[spring-orm-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1571) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1509) ~[spring-beans-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    ... 35 common frames omitted  
Caused by: org.hibernate.MappingException: Could not determine type for: org.springframework.web.multipart.MultipartFile, at table: documents, for columns: [org.hibernate.mapping.Column(file)]
    at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:314) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:292) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.mapping.Property.isValid(Property.java:239) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:469) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.mapping.RootClass.validate(RootClass.java:270) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.cfg.Configuration.validate(Configuration.java:1296) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1752) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.ejb.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:96) ~[hibernate-entitymanager-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:913) ~[hibernate-entitymanager-4.2.1.Final.jar:4.2.1.Final]
    ... 41 common frames omitted  
Dec 13, 2013 8:38:54 PM org.apache.catalina.core.StandardContext listenerStart
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0' defined in class path resource [spring/business-config.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [spring/business-config.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: petclinic] Unable to build EntityManagerFactory  

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:529)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:296)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:293)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
    at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:741)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4939)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [spring/business-config.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: petclinic] Unable to build EntityManagerFactory
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1512)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:296)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:293)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:438)
    at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:277)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.detectPersistenceExceptionTranslators(PersistenceExceptionTranslationInterceptor.java:139)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.<init>(PersistenceExceptionTranslationInterceptor.java:79)
    at org.springframework.dao.annotation.PersistenceExceptionTranslationAdvisor.<init>(PersistenceExceptionTranslationAdvisor.java:71)
    at org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor.setBeanFactory(PersistenceExceptionTranslationPostProcessor.java:85)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1532)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1500)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521)
    ... 20 more
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: petclinic] Unable to build EntityManagerFactory
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:923)
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:898)
    at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:76)
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:288)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:310)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1571)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1509)
    ... 35 more
Caused by: org.hibernate.MappingException: Could not determine type for: org.springframework.web.multipart.MultipartFile, at table: documents, for columns: [org.hibernate.mapping.Column(file)]
    at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:314)
    at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:292)
    at org.hibernate.mapping.Property.isValid(Property.java:239)
    at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:469)
    at org.hibernate.mapping.RootClass.validate(RootClass.java:270)
    at org.hibernate.cfg.Configuration.validate(Configuration.java:1296)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1752)
    at org.hibernate.ejb.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:96)
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:913)
    ... more  

SQL that creates documents table in database. Compare with annotation in Document.java:

CREATE TABLE IF NOT EXISTS documents (
  id int(11) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  client_id int(4) UNSIGNED NOT NULL,
  type_id INT(4) UNSIGNED, 
  name varchar(200) NOT NULL,
  description text NOT NULL,
  filename varchar(200) NOT NULL,
  content mediumblob NOT NULL, 
  content_type varchar(255) NOT NULL,
  created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (client_id) REFERENCES patients(id),
  FOREIGN KEY (type_id) REFERENCES documenttypes(id)
);

EDIT:

When I put @Transient in front of the MultipartFile file property declaration, I get the stack trace that you can download at this file sharing link.

The business-config.xml referred to in the stack trace can be read at this file sharing site.

CodeMed
  • 9,527
  • 70
  • 212
  • 364
  • Are you currently getting a an error when the JpaDocumentRepositoryImpl.save() method is called? If so, can you include the stack trace. – drembert Dec 13 '13 at 23:59
  • @drembert It will not compile yet because the `file` instance in `JpaDocumentRepositoryImpl.save()` is not populated. See note in code. `file` is from `DocumentController.java`, and one problem is I don't know how to get it into `JpaDocumentRepositoryImpl.save()` . Are there specific suggestions you can make? I am online now and can try things and report back. – CodeMed Dec 14 '13 at 03:32
  • @drembert I got rid of the eclipse errors by adding a property of type MultipartFile called file to the Document.java class, and then setting it in DocumentController.java and retrieving it in JpaDocumentRespositoryImpl.java. But it is giving me an error related to PersistenceExceptionTranslationPostProcessor when I try to launch the application. I will add code in an edit now. Does this cause you any new ideas? – CodeMed Dec 14 '13 at 04:20
  • I am not exactly sure what error that particular exception is referring to offhand. I can take a look at some point tonight or tomorrow morning and let you know if I can figure it out – drembert Dec 14 '13 at 04:31
  • @drembert Thank you. I just posted a lot more code and the stack trace to help you figure it out. I think the problem is the lack of annotation for the MultipartFile file property I added to Document.java. But I imagine there are other problems too and I would appreciate you help. – CodeMed Dec 14 '13 at 05:07

2 Answers2

2

annotate

@Transient
private MultipartFile file;

update

from your stacktrace:

 Caused by: org.hibernate.MappingException: Could not determine type for: org.springframework.web.multipart.MultipartFile, at table: documents, for columns: [org.hibernate.mapping.Column(file)]

error is explicit, JPA does not know how to map MultipartFile as a Column.

using @Transient we are saying not to map at all.

so drop your database and re-create it, clean and re-compile your code, because this errors shows that your code has not been compiled with @Transient.

and be sure @Transient is @javax.persistence.Transient

Michele Mariotti
  • 7,372
  • 5
  • 41
  • 73
1

When you annotate a class with @Entity the default is for all fields within that class to be inserted into the database when you persist the entity.

Unless you provide annotations on each field, your persistence provider will take it's "default" approach to making the fields persistent (what the defaults exactly are may be guided by the JPA spec, I'm not sure). For fields where the type is a primitive or other easily mappable field types such as Strings and enums, this isn't a problem.

Where the type of the field is a object or not easily mappable, you will run into problems. Essentially your persistence provider doesn't know how you want to store the field into the database and can't take a sensible default action. The best thing for it to do is to throw an Exception telling you exactly that and make you be more specific about how you want to store data in the database.

This is what is happening with your MultipartFile field. Hibernate doesn't know how you want to persist it in the database.

To solve the problem, you have a few options:

1: You can explicitly tell your persistence provider to ignore certain fields using the @Transient annotation. In your case you would add this to the file field within your Document entity. Be clear though that when you load a Document entity from the database, the file field will always be null. You will need to ensure that your business logic is OK with this.

2: Use the @Lob annotation on the file field. This will rely on Java's in-built Serialization to store the MulitpartFile in your database

3: Provide a Hibernate User Type that essentially instructs Hibernate how it should attempt to persist any field of type MultipartFile

Which one is right for you depends completely upon the requirements of your application.

Rob Lockwood-Blake
  • 4,688
  • 24
  • 22
  • +1 Thank you. When I add at_Transient in front of the MultipartFile file declaration in Document.java, I get a stack trace which refers to business-config.xml. I have included both the stack trace and business-config.xml in links to a file sharing site in an edit at the end of my original posting above. Can you please look at them and tell me how to resolve the error so that the application compiles? – CodeMed Dec 14 '13 at 22:14