java - Spring Repository Rest Resource - issue not saving sub objects -
i have been trying restful interface going spring boot have hit problem.
when post'ing following json org.hibernate.transientobjectexception exception (please see below) indicates sub-object not being saved.
on hand tracing appears json correctly rendered domain objects when save() method (simplejparepository) called doesn't attempt recurse down through sub-objects. intentional? if so, correct approach configuring @repositoryrestresource such save sub-objects?
i have minimal spring.boot application happily provide if diagnosis.
i have been looking around working example has sub-object (relation) haven't found 1 yet. spring.io example great getting me going have become bit stuck expanding on it.
code snippets follow below:
json being posted: { "name" : "test sample group", "description" : null, "projectcode" : null, "creator" : "user001", "createddate" : 1395130128971, "lastmodifieddate" : 1395130128971, "samples" : [ { "userpreferredid" : "s00012223434", "wtsiuid" : "99997853483845", "synonyms" : [ "abc12345", "humgen-0011232233", "1200088132734888234" ] }, { "userpreferredid" : "s000634734588", "wtsiuid" : "34583934085358", "synonyms" : [ "4875345993599934", "humgen-004537682", "abc674534" ] } ] }
which posted using following command:
curl -i -x post -h "content-type:application/json" --data @postdata.txt http://localhost:8080/samplegroup/
the exception thrown follows:
org.hibernate.transientobjectexception: object references unsaved transient instance - save transient instance before flushing: uk.ac.sanger.mig.samplegroup.domain.sample at** org.hibernate.engine.internal.foreignkeys.getentityidentifierifnotunsaved(foreignkeys.java:294) @ org.hibernate.type.entitytype.getidentifier(entitytype.java:510) @ org.hibernate.type.manytoonetype.nullsafeset(manytoonetype.java:165) @ org.hibernate.persister.collection.abstractcollectionpersister.writeelement(abstractcollectionpersister.java:899) @ org.hibernate.persister.collection.abstractcollectionpersister.recreate(abstractcollectionpersister.java:1308) @ org.hibernate.persister.collection.onetomanypersister.recreate(onetomanypersister.java:184) @ org.hibernate.action.internal.collectionrecreateaction.execute(collectionrecreateaction.java:67) @ org.hibernate.engine.spi.actionqueue.executeactions(actionqueue.java:453) @ org.hibernate.engine.spi.actionqueue.executeactions(actionqueue.java:345) @ org.hibernate.event.internal.abstractflushingeventlistener.performexecutions(abstractflushingeventlistener.java:350) @ org.hibernate.event.internal.defaultflusheventlistener.onflush(defaultflusheventlistener.java:56) @ org.hibernate.internal.sessionimpl.flush(sessionimpl.java:1218) @ org.hibernate.internal.sessionimpl.managedflush(sessionimpl.java:421) @ org.hibernate.engine.transaction.internal.jdbc.jdbctransaction.beforetransactioncommit(jdbctransaction.java:101) @ org.hibernate.engine.transaction.spi.abstracttransactionimpl.commit(abstracttransactionimpl.java:177) @ org.hibernate.jpa.internal.transactionimpl.commit(transactionimpl.java:77) @ org.springframework.orm.jpa.jpatransactionmanager.docommit(jpatransactionmanager.java:515) @ org.springframework.transaction.support.abstractplatformtransactionmanager.processcommit(abstractplatformtransactionmanager.java:757) @ org.springframework.transaction.support.abstractplatformtransactionmanager.commit(abstractplatformtransactionmanager.java:726) @ org.springframework.transaction.interceptor.transactionaspectsupport.committransactionafterreturning(transactionaspectsupport.java:478) @ org.springframework.transaction.interceptor.transactionaspectsupport.invokewithintransaction(transactionaspectsupport.java:272) @ org.springframework.transaction.interceptor.transactioninterceptor.invoke(transactioninterceptor.java:95) @ org.springframework.aop.framework.reflectivemethodinvocation.proceed(reflectivemethodinvocation.java:179) @ org.springframework.dao.support.persistenceexceptiontranslationinterceptor.invoke(persistenceexceptiontranslationinterceptor.java:136) @ org.springframework.aop.framework.reflectivemethodinvocation.proceed(reflectivemethodinvocation.java:179) @ org.springframework.data.jpa.repository.support.lockmoderepositorypostprocessor$lockmodepopulatingmethodintercceptor.invoke(lockmoderepositorypostprocessor.java:92) @ org.springframework.aop.framework.reflectivemethodinvocation.proceed(reflectivemethodinvocation.java:179) @ org.springframework.aop.interceptor.exposeinvocationinterceptor.invoke(exposeinvocationinterceptor.java:92) @ org.springframework.aop.framework.reflectivemethodinvocation.proceed(reflectivemethodinvocation.java:179) @ org.springframework.aop.framework.jdkdynamicaopproxy.invoke(jdkdynamicaopproxy.java:207) @ com.sun.proxy.$proxy67.save(unknown source) @ org.springframework.data.rest.core.invoke.crudrepositoryinvoker.invokesave(crudrepositoryinvoker.java:106) @ org.springframework.data.rest.webmvc.repositoryentitycontroller.createandreturn(repositoryentitycontroller.java:339) @ org.springframework.data.rest.webmvc.repositoryentitycontroller.postentity(repositoryentitycontroller.java:177) @ sun.reflect.nativemethodaccessorimpl.invoke0(native method) @ sun.reflect.nativemethodaccessorimpl.invoke(nativemethodaccessorimpl.java:57) @ sun.reflect.delegatingmethodaccessorimpl.invoke(delegatingmethodaccessorimpl.java:43) @ java.lang.reflect.method.invoke(method.java:606) @ org.springframework.web.method.support.invocablehandlermethod.invoke(invocablehandlermethod.java:215) @ org.springframework.web.method.support.invocablehandlermethod.invokeforrequest(invocablehandlermethod.java:132) @ org.springframework.web.servlet.mvc.method.annotation.servletinvocablehandlermethod.invokeandhandle(servletinvocablehandlermethod.java:104) @ org.springframework.web.servlet.mvc.method.annotation.requestmappinghandleradapter.invokehandlemethod(requestmappinghandleradapter.java:749) @ org.springframework.web.servlet.mvc.method.annotation.requestmappinghandleradapter.handleinternal(requestmappinghandleradapter.java:690) @ org.springframework.web.servlet.mvc.method.abstracthandlermethodadapter.handle(abstracthandlermethodadapter.java:83) @ org.springframework.web.servlet.dispatcherservlet.dodispatch(dispatcherservlet.java:945) @ org.springframework.web.servlet.dispatcherservlet.doservice(dispatcherservlet.java:876) @ org.springframework.web.servlet.frameworkservlet.processrequest(frameworkservlet.java:961) @ org.springframework.web.servlet.frameworkservlet.dopost(frameworkservlet.java:863) @ javax.servlet.http.httpservlet.service(httpservlet.java:646) @ org.springframework.web.servlet.frameworkservlet.service(frameworkservlet.java:837) @ javax.servlet.http.httpservlet.service(httpservlet.java:727) @ org.apache.catalina.core.applicationfilterchain.internaldofilter(applicationfilterchain.java:303) @ org.apache.catalina.core.applicationfilterchain.dofilter(applicationfilterchain.java:208) @ org.springframework.web.filter.hiddenhttpmethodfilter.dofilterinternal(hiddenhttpmethodfilter.java:77) @ org.springframework.web.filter.onceperrequestfilter.dofilter(onceperrequestfilter.java:108) @ org.apache.catalina.core.applicationfilterchain.internaldofilter(applicationfilterchain.java:241) @ org.apache.catalina.core.applicationfilterchain.dofilter(applicationfilterchain.java:208) @ org.apache.catalina.core.standardwrappervalve.invoke(standardwrappervalve.java:220) @ org.apache.catalina.core.standardcontextvalve.invoke(standardcontextvalve.java:122) @ org.apache.catalina.authenticator.authenticatorbase.invoke(authenticatorbase.java:501) @ org.apache.catalina.valves.remoteipvalve.invoke(remoteipvalve.java:683) @ org.apache.catalina.core.standardhostvalve.invoke(standardhostvalve.java:170) @ org.apache.catalina.valves.errorreportvalve.invoke(errorreportvalve.java:98) @ org.apache.catalina.core.standardenginevalve.invoke(standardenginevalve.java:116) @ org.apache.catalina.connector.coyoteadapter.service(coyoteadapter.java:408) @ org.apache.coyote.http11.abstracthttp11processor.process(abstracthttp11processor.java:1040) @ org.apache.coyote.abstractprotocol$abstractconnectionhandler.process(abstractprotocol.java:607) @ org.apache.tomcat.util.net.nioendpoint$socketprocessor.dorun(nioendpoint.java:1721) @ org.apache.tomcat.util.net.nioendpoint$socketprocessor.run(nioendpoint.java:1679) @ java.util.concurrent.threadpoolexecutor.runworker(threadpoolexecutor.java:1145) @ java.util.concurrent.threadpoolexecutor$worker.run(threadpoolexecutor.java:615) @ java.lang.thread.run(thread.java:744)
the restful repository definition follows:
package uk.ac.sanger.mig.samplegroup.repository; import java.util.list; import org.springframework.data.repository.pagingandsortingrepository; import org.springframework.data.repository.query.param; import org.springframework.data.rest.core.annotation.repositoryrestresource; import uk.ac.sanger.mig.samplegroup.domain.samplegroup; @repositoryrestresource(collectionresourcerel = "samplegroup", path = "samplegroup") public interface samplegrouprepository extends pagingandsortingrepository<samplegroup, long> { list<samplegroup> findbyname(@param("name") string name); list<samplegroup> findbycreator(@param("name") string name); }
entity definitions follows:
package uk.ac.sanger.mig.samplegroup.domain; import java.util.date; import java.util.set; import javax.persistence.column; import javax.persistence.entity; import javax.persistence.generatedvalue; import javax.persistence.generationtype; import javax.persistence.id; import javax.persistence.joincolumn; import javax.persistence.onetomany; import javax.persistence.sequencegenerator; @entity public class samplegroup { // database primary key use only. @id @generatedvalue(strategy=generationtype.sequence, generator="sample_group_seq") @sequencegenerator( name="sample_group_seq", sequencename="sample_group_seq", allocationsize=1 ) private long id; @column(unique=true, nullable=false) private string name; private string description; private string projectcode; private string creator; private date createddate; private date lastmodifieddate; @onetomany @joincolumn(name="sample_fk") private set<sample> samples; public samplegroup() {} public string getname() { return name; } public void setname(string name) { this.name = name; } public string getcreator() { return creator; } public void setcreator(string creator) { this.creator = creator; } public date getcreateddate() { return createddate; } public void setcreateddate(date createddate) { this.createddate = createddate; } public date getlastmodifieddate() { return lastmodifieddate; } public void setlastmodifieddate(date lastmodifieddate) { this.lastmodifieddate = lastmodifieddate; } public set<sample> getsamples() { return samples; } public void setsamples(set<sample> samples) { this.samples = samples; } public string getdescription() { return description; } public void setdescription(string description) { this.description = description; } public string getprojectcode() { return projectcode; } public void setprojectcode(string projectcode) { this.projectcode = projectcode; } @override public string tostring() { return "samplegroup [id=" + id + ", name=" + name + ", description=" + description + ", projectcode=" + projectcode + ", creator=" + creator + ", createddate=" + createddate + ", lastmodifieddate=" + lastmodifieddate + ", samples=" + samples + "]"; } @override public int hashcode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashcode()); result = prime * result + ((projectcode == null) ? 0 : projectcode.hashcode()); return result; } @override public boolean equals(object obj) { if (this == obj) return true; if (obj == null) return false; if (getclass() != obj.getclass()) return false; samplegroup other = (samplegroup) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (projectcode == null) { if (other.projectcode != null) return false; } else if (!projectcode.equals(other.projectcode)) return false; return true; } } package uk.ac.sanger.mig.samplegroup.domain; import java.util.set; import javax.persistence.column; import javax.persistence.elementcollection; import javax.persistence.entity; import javax.persistence.generatedvalue; import javax.persistence.generationtype; import javax.persistence.id; import javax.persistence.sequencegenerator; @entity public class sample { // database primary key use only. @id @generatedvalue(strategy=generationtype.sequence, generator="sample_seq") @sequencegenerator( name="sample_seq", sequencename="sample_seq", allocationsize=1 ) private long id; private string userpreferredid; // buisiness user prefers call sample. @column(unique=true, nullable=false) private string wtsiuid; // must unique within wtsi (primary key) @elementcollection private set<string> synonyms; public sample() {} public string getuserpreferredid() { return userpreferredid; } public void setuserpreferredid(string userpreferredid) { this.userpreferredid = userpreferredid; } public string getwtsiuid() { return wtsiuid; } public void setwtsiuid(string wtsiuid) { this.wtsiuid = wtsiuid; } public set<string> getsynonyms() { return synonyms; } public void setsynonyms(set<string> synonyms) { this.synonyms = synonyms; } @override public string tostring() { return "sample [id=" + id + ", userpreferredid=" + userpreferredid + ", wtsiuid=" + wtsiuid + ", synonyms=" + synonyms + "]"; } @override public int hashcode() { final int prime = 31; int result = 1; result = prime * result + ((wtsiuid == null) ? 0 : wtsiuid.hashcode()); return result; } @override public boolean equals(object obj) { if (this == obj) return true; if (obj == null) return false; if (getclass() != obj.getclass()) return false; sample other = (sample) obj; if (wtsiuid == null) { if (other.wtsiuid != null) return false; } else if (!wtsiuid.equals(other.wtsiuid)) return false; return true; } }
the issue when saving samplegroup, samples inside set not managed hibernate. 1 solution make following change:
@onetomany(cascade={cascadetype.persist, cascadetype.merge}) @joincolumn(name="sample_fk") private set<sample> samples;
Comments
Post a Comment