0
votes

I have a Java EE application using JPA (EclipseLink) and Spring framework.

Everything worked fine in my persistence classes until I added Spring transaction management. I have following entities (corresponding to the database tables) :

  • Project

    @Entity
    @Table(name="projet")
    public class Projet implements Serializable {
     private static final long serialVersionUID = 1L;
    
     @Id
     @GeneratedValue(strategy=GenerationType.IDENTITY)
     @Column(name="id_projet", unique=true, nullable=false)
     private Integer idProjet;
    
     @Column(name="nom_projet")
     private String nomProjet;
    
     /** The projet util droits. */
     @OneToMany(mappedBy="projet", cascade={CascadeType.ALL})
     private Set<ProjetUtilDroit> projetUtilDroits;
    
         public Projet() {
         }
    
        ...
    }
    
  • User

    @Entity
    @Table(name="utilisateur")
    public class Utilisateur implements Serializable {
    
         /** The Constant serialVersionUID. */
    private static final long serialVersionUID = 1L;
    
     /** The id utilisateur. */
     @Id
     @GeneratedValue(strategy=GenerationType.IDENTITY)
     @Column(name="id_utilisateur", unique=true, nullable=false)
     private Integer idUtilisateur;
    
      /** The nom utilisateur. */
     @Column(name="nom_utilisateur", nullable=false, length=50)
     private String nomUtilisateur;
    
     //bi-directional many-to-one association to ProjetUtilDroit
     /** The projet util droits. */
     @OneToMany(mappedBy="utilisateur", cascade={CascadeType.REMOVE})
     private Set<ProjetUtilDroit> projetUtilDroits;
    
          ...
      }
    
  • Right

    @Entity
    @Table(name="droit")
    public class Droit implements Serializable {
    
      /** The Constant serialVersionUID. */
     private static final long serialVersionUID = 1L;
    
     /** The id droit. */
     @Id
     @GeneratedValue(strategy=GenerationType.IDENTITY)
     @Column(name="id_droit", unique=true, nullable=false)
     private Integer idDroit;
    
     /** The type droit. */
     @Column(name="type_droit", nullable=false, length=10)
     private String typeDroit;
    
         /**
          * Instantiates a new droit.
          */
         public Droit() {
         }
        ...
    }
    
  • And an association which links a user to a project with a specific right (ProjectUserRight)

    @Entity
    @Table(name="projet_util_droit")
    public class ProjetUtilDroit implements Serializable {
    
     /** The Constant serialVersionUID. */
     private static final long serialVersionUID = 1L;
    
     /** The id. */
     @EmbeddedId
     private ProjetUtilDroitPK id;
    
     //bi-directional many-to-one association to Droit
         /** The droit. */
     @ManyToOne(cascade={CascadeType.MERGE, CascadeType.REFRESH})
     @JoinColumn(name="id_droit")
     private Droit droit;
    
     //bi-directional many-to-one association to Projet
     /** The projet. */
     @MapsId("idProjet")
         @ManyToOne(cascade={CascadeType.MERGE, CascadeType.REFRESH})
         @JoinColumn(name="id_projet")
     private Projet projet;
    
     //bi-directional many-to-one association to Utilisateur
         /** The utilisateur. */
     @MapsId("idUtilisateur")
         @ManyToOne(cascade={CascadeType.MERGE, CascadeType.REFRESH})
     @JoinColumn(name="id_utilisateur")
     private Utilisateur utilisateur;
    
        ...
        }
    
  • The embedded id for the association:

    @Embeddable
    public class ProjetUtilDroitPK implements Serializable {
    
     //default serial version id, required for serializable classes.
     /** The Constant serialVersionUID. */
     private static final long serialVersionUID = 1L;
    
      /** The id projet. */
      @Column(name="id_projet", unique=true, nullable=false)
      private Integer idProjet;
    
      /** The id utilisateur. */
      @Column(name="id_utilisateur", unique=true, nullable=false)
      private Integer idUtilisateur;
    
       ...
    }
    

My method creating the project with its right:

   public Projet createProject(String name, int idRight, int idUser) {
    Projet project = new Projet();
    project.setNomProjet(name);
    ProjetUtilDroit pud = new ProjetUtilDroit();
    Droit d = rightDao.findById(idRight);
    pud.setDroit(d);
    pud.setProjet(project);
    Utilisateur user = userDao.findById(idUser);
    pud.setUtilisateur(user);
    if(user.getProjetUtilDroits() == null)
        user.setProjetUtilDroits(new HashSet<ProjetUtilDroit>());
    user.getProjetUtilDroits().add(pud);
    Set<ProjetUtilDroit> pudSet = new HashSet<ProjetUtilDroit>();
    pudSet.add(pud);
    project.setProjetUtilDroits(pudSet);
    project = projectDao.create(project);
    return project;
}

It worked like a charm (persist the project and the associated user rights) until I add the annotation @Transactionnal above the "createProject" method...

Now I get this error: Avertissement: StandardWrapperValve[dispatcher]: PWC1406: Servlet.service() for servlet dispatcher threw exception java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: *****Project right**** User name: userName Right: read. at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.discoverUnregisteredNewObjects(RepeatableWriteUnitOfWork.java:304) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.calculateChanges(UnitOfWorkImpl.java:702) at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.writeChanges(RepeatableWriteUnitOfWork.java:433) at org.eclipse.persistence.internal.jpa.EntityManagerImpl.flush(EntityManagerImpl.java:780) at org.eclipse.persistence.internal.jpa.EJBQueryImpl.performPreQueryFlush(EJBQueryImpl.java:1298) at org.eclipse.persistence.internal.jpa.EJBQueryImpl.executeReadQuery(EJBQueryImpl.java:434) at org.eclipse.persistence.internal.jpa.EJBQueryImpl.getResultList(EJBQueryImpl.java:742) at com.dao.BasicDAO.findAll(BasicDAO.java:92) at com.dao.BasicDAO.create(BasicDAO.java:103) at com.services.ProjectService.createProject(ProjectService.java:48) at com.services.ProjectService$$FastClassByCGLIB$$67c85b9f.invoke() at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191) at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:689) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622) at com.services.ProjectService$$EnhancerByCGLIB$$398fa756.createProject() at com.servlet.Test.handleCreateProject(Test.java:31) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:213) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778) at javax.servlet.http.HttpServlet.service(HttpServlet.java:668) at javax.servlet.http.HttpServlet.service(HttpServlet.java:770) at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1542) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161) at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231) at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317) at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195) at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:849) at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:746) at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1045) at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:228) at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90) at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79) at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54) at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59) at com.sun.grizzly.ContextTask.run(ContextTask.java:71) at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532) at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513) at java.lang.Thread.run(Thread.java:722)

The only solution I imagine is to create the project within one transaction and save its rights separately within another transaction. Is that the only solution or does anybody have another suggestion?

1

1 Answers

0
votes

Which object was not persisted? Include the full exception.

You need to either mark the relationship to the object as cascade persist, or call persist on the object before persisting the project.