org.springframework.dao.DuplicateKeyException: A different object with the same identifier value was already associated with the session

My objective is to download Issue data of Apache projects using the Jira REST api and store the fetched objects using Spring with JPA (Hibernate).

The Issue entity can be linked with Developer entities using several relations such as Creator, Reporter, Assignee etc. This means that when receiving the JSON from the REST remote endpoint, the parsing will produce different objects of type Developer that can relate to the same Developer entity (i.e. if the Developer is both the assignee and the reporter). Besides, several issues can refer to same developer (i.e. a Developer is assigned to work to multiple issues).

Given a list of Issue keys, what I would like to achieve is, for each issue:

  1. Download corresponding JSON from Jira REST remote endpoint;
  2. Parse JSON into a Issue entity (along with referred child objects such as Developers)
  3. Store entities in DB

I don’t care for overwriting pre-existent entities (i.e. Developers already mentioned in previous issues) since I’m assuming that data in remote Jira DB is consistent.

When trying to save in db this issue alone, I’m getting the exception mentioned in the title (full stacktrace below).

From the stacktrace it seems that the problem is caused by the Developer entity referring to user vkorehov, which is both Creator and Reportes for this issue. So the problem seems to be that the parser (GSON) creates two different entities with same primary key that cannot both be stored in DB since they would break the unique constraint.

Can I tell Spring to merge all Developer object with same Id into the same entity? Isn’t it be the default behaviour of Spring? Should I resolve by myself all duplicates of Developer objects before storing the Issue entity in DB??? 🙁

Full stacktrace:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>org.springframework.dao.DuplicateKeyException: A different object with the same identifier value was already associated with the session : [it.torkin.dataminer.entities.jira.Developer#vkorehov]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:304)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:550)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:335)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:160)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:165)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:223)
at jdk.proxy2/jdk.proxy2.$Proxy132.save(Unknown Source)
at it.torkin.dataminer.control.dataset.ApachejitController.loadIssues(ApachejitController.java:78)
at it.torkin.dataminer.control.dataset.ApachejitController.loadDataset(ApachejitController.java:178)
at it.torkin.dataminer.DatasetControllerTest.testLoadDataset(DatasetControllerTest.java:31)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:76)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:93)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:530)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:758)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:453)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:211)
Caused by: org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [it.torkin.dataminer.entities.jira.Developer#vkorehov]
at org.hibernate.event.internal.AbstractSaveEventListener.entityKey(AbstractSaveEventListener.java:237)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:219)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:137)
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:175)
at org.hibernate.event.internal.DefaultPersistEventListener.persist(DefaultPersistEventListener.java:93)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:77)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:138)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:799)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:747)
at org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:290)
at org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:280)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:517)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:439)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:224)
at org.hibernate.engine.internal.Cascade.cascadeComponent(Cascade.java:410)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:245)
at org.hibernate.engine.internal.Cascade.cascadeComponent(Cascade.java:410)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:245)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:157)
at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:487)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:303)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:224)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:137)
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:175)
at org.hibernate.event.internal.DefaultPersistEventListener.persist(DefaultPersistEventListener.java:93)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:77)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:54)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:757)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:741)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:319)
at jdk.proxy2/jdk.proxy2.$Proxy126.persist(Unknown Source)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:629)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:354)
at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:277)
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:170)
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:158)
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:516)
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:285)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:628)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:168)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:143)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:70)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:379)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:138)
... 42 more
</code>
<code>org.springframework.dao.DuplicateKeyException: A different object with the same identifier value was already associated with the session : [it.torkin.dataminer.entities.jira.Developer#vkorehov] at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:304) at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244) at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:550) at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:335) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:160) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:165) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:223) at jdk.proxy2/jdk.proxy2.$Proxy132.save(Unknown Source) at it.torkin.dataminer.control.dataset.ApachejitController.loadIssues(ApachejitController.java:78) at it.torkin.dataminer.control.dataset.ApachejitController.loadDataset(ApachejitController.java:178) at it.torkin.dataminer.DatasetControllerTest.testLoadDataset(DatasetControllerTest.java:31) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:569) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:76) at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97) at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329) at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) at org.junit.runners.ParentRunner.run(ParentRunner.java:413) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:93) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:530) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:758) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:453) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:211) Caused by: org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [it.torkin.dataminer.entities.jira.Developer#vkorehov] at org.hibernate.event.internal.AbstractSaveEventListener.entityKey(AbstractSaveEventListener.java:237) at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:219) at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:137) at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:175) at org.hibernate.event.internal.DefaultPersistEventListener.persist(DefaultPersistEventListener.java:93) at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:77) at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:138) at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:799) at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:747) at org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:290) at org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:280) at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:517) at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:439) at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:224) at org.hibernate.engine.internal.Cascade.cascadeComponent(Cascade.java:410) at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:245) at org.hibernate.engine.internal.Cascade.cascadeComponent(Cascade.java:410) at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:245) at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:157) at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:487) at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:303) at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:224) at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:137) at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:175) at org.hibernate.event.internal.DefaultPersistEventListener.persist(DefaultPersistEventListener.java:93) at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:77) at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:54) at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127) at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:757) at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:741) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:569) at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:319) at jdk.proxy2/jdk.proxy2.$Proxy126.persist(Unknown Source) at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:629) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:569) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:354) at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:277) at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:170) at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:158) at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:516) at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:285) at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:628) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:168) at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:143) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:70) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:379) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:138) ... 42 more </code>
org.springframework.dao.DuplicateKeyException: A different object with the same identifier value was already associated with the session : [it.torkin.dataminer.entities.jira.Developer#vkorehov]
        at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:304)
        at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244)
        at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:550)
        at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
        at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:335)
        at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:160)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
        at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:165)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
        at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:223)
        at jdk.proxy2/jdk.proxy2.$Proxy132.save(Unknown Source)
        at it.torkin.dataminer.control.dataset.ApachejitController.loadIssues(ApachejitController.java:78)
        at it.torkin.dataminer.control.dataset.ApachejitController.loadDataset(ApachejitController.java:178)
        at it.torkin.dataminer.DatasetControllerTest.testLoadDataset(DatasetControllerTest.java:31)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:569)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:76)
        at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
        at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
        at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
        at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
        at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
        at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
        at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
        at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
        at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
        at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:93)
        at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:530)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:758)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:453)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:211)
Caused by: org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [it.torkin.dataminer.entities.jira.Developer#vkorehov]
        at org.hibernate.event.internal.AbstractSaveEventListener.entityKey(AbstractSaveEventListener.java:237)
        at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:219)
        at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:137)
        at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:175)
        at org.hibernate.event.internal.DefaultPersistEventListener.persist(DefaultPersistEventListener.java:93)
        at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:77)
        at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:138)
        at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:799)
        at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:747)
        at org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:290)
        at org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:280)
        at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:517)
        at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:439)
        at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:224)
        at org.hibernate.engine.internal.Cascade.cascadeComponent(Cascade.java:410)
        at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:245)
        at org.hibernate.engine.internal.Cascade.cascadeComponent(Cascade.java:410)
        at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:245)
        at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:157)
        at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:487)
        at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:303)
        at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:224)
        at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:137)
        at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:175)
        at org.hibernate.event.internal.DefaultPersistEventListener.persist(DefaultPersistEventListener.java:93)
        at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:77)
        at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:54)
        at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127)
        at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:757)
        at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:741)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:569)
        at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:319)
        at jdk.proxy2/jdk.proxy2.$Proxy126.persist(Unknown Source)
        at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:629)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:569)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:354)
        at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:277)
        at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:170)
        at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:158)
        at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:516)
        at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:285)
        at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:628)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
        at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:168)
        at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:143)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
        at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:70)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:379)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
        at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:138)
        ... 42 more

My model looks like this (only relevant parts listed):

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>@Entity
public class Issue {
@Id
@GeneratedValue
private long id;
private String key; // "PROJ-123"
/**
* Issue details mapped to the attributes obtainable from the
* Jira REST API.
*/
@Embedded
private IssueDetails details;
}
@Embeddable
@Data
public class IssueDetails {
@SerializedName("id")
@Column(unique = true) private String jiraId;
@SerializedName("key")
private String self; // link to issue in Jira
@Embedded private IssueFields fields;
}
@Embeddable
@Data
public class IssueFields{
@Column(columnDefinition = "text")
private String description;
private int upTimestampd;
private String summary; // issue title
private Timestamp resolutionTimestamp;
private Developer assignee;
@ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
private Developer creator;
@ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
private Developer reporter;
@ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
private List<Component> components;
}
@Data
@Entity
public class Developer{
private String accountType;
private boolean active;
@Embedded
private AvatarUrls avatarUrls;
private String displayName;
@Id
private String key;
private String name;
private String self;
private String timeZone;
}
</code>
<code>@Entity public class Issue { @Id @GeneratedValue private long id; private String key; // "PROJ-123" /** * Issue details mapped to the attributes obtainable from the * Jira REST API. */ @Embedded private IssueDetails details; } @Embeddable @Data public class IssueDetails { @SerializedName("id") @Column(unique = true) private String jiraId; @SerializedName("key") private String self; // link to issue in Jira @Embedded private IssueFields fields; } @Embeddable @Data public class IssueFields{ @Column(columnDefinition = "text") private String description; private int upTimestampd; private String summary; // issue title private Timestamp resolutionTimestamp; private Developer assignee; @ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY) private Developer creator; @ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY) private Developer reporter; @ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY) private List<Component> components; } @Data @Entity public class Developer{ private String accountType; private boolean active; @Embedded private AvatarUrls avatarUrls; private String displayName; @Id private String key; private String name; private String self; private String timeZone; } </code>
@Entity
public class Issue {
    
    @Id
    @GeneratedValue
    private long id;

    private String key; // "PROJ-123"
    

    /**
     * Issue details mapped to the attributes obtainable from the
     * Jira REST API.
     */
    @Embedded
    private IssueDetails details;
}

@Embeddable
@Data
public class IssueDetails {

    @SerializedName("id")
    @Column(unique = true) private String jiraId;
    
    @SerializedName("key")
    private String self; // link to issue in Jira

    @Embedded private IssueFields fields;

    
}

@Embeddable
@Data
public class IssueFields{
    
    @Column(columnDefinition = "text")
    private String description;
    private int upTimestampd;
    private String summary; // issue title
    private Timestamp resolutionTimestamp;

    
    private Developer assignee;
    @ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
    private Developer creator;
    @ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
    private Developer reporter;
    
    @ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
    private List<Component> components;
}

@Data
@Entity
public class Developer{
    private String accountType;
    private boolean active;
    @Embedded
    private AvatarUrls avatarUrls;
    private String displayName;
    @Id
    private String key;
    private String name;
    private String self;
    private String timeZone;
}

database properties:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>spring.datasource.driverClassName=org.postgresql.Driver
spring.jpa.properties.hibernate.event.merge.entity_copy_observer=allow
spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
</code>
<code>spring.datasource.driverClassName=org.postgresql.Driver spring.jpa.properties.hibernate.event.merge.entity_copy_observer=allow spring.jpa.hibernate.ddl-auto=create spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect </code>
spring.datasource.driverClassName=org.postgresql.Driver
spring.jpa.properties.hibernate.event.merge.entity_copy_observer=allow
spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect

Any help would be greatly appreciated, thank you all.

Exception triggers when launching the following test:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>public class DatasetControllerTest {
@Autowired private IDatasetController datasetController;
@Test
public void testLoadDataset() throws UnableToLoadDatasetException{
datasetController.loadDataset();
log.info(datasetController.getDataset().toString());
}
}
@Service
@Slf4j
public class ApachejitController implements IDatasetController{
@Autowired private ApachejitConfig apachejitConfig;
@Autowired private JiraConfig jiraConfig;
@Autowired private CommitDao commitDao;
@Autowired private IssueDao issueDao;
@Autowired private DatasetDao datasetDao;
private Dataset dataset;
private void loadIssues(ApachejitDao apachejitDao, JiraDao jiraDao) throws UnableToLoadIssuesException {
/**
* - get the path of the issues folder from the configuration
* - list all csvs in the folder
* - for each csv
* - load each issue record from csv
* - for each record
* - transform record into an Issue object
* - fetch issue details from Jira API
* - store IssueDetails reference in Issue
* - load Commit matching the hash commit in Issue
* - store Commit reference in Issue
* - save Issue in the database
*/
List<Resultset<IssueRecord>> issues;
Issue issue;
IssueRecord record;
int skipped;
try {
issues = apachejitDao.getAllIssues(apachejitConfig.getIssuesPath());
for (int i = 0; i < issues.size(); i++) {
try (Resultset<IssueRecord> projectIssues = issues.get(i)) {
while (projectIssues.hasNext()) {
record = projectIssues.next();
// skip commit if it is already in db, but only if
// we do not have to refresh the db
if (!issueDao.existsByKey(record.getIssue_key())
|| apachejitConfig.isRefresh()) {
try {
issue = new Issue();
issue.setKey(record.getIssue_key());
linkIssueDetails(issue, jiraDao);
linkCommit(issue, record.getCommit_id());
issueDao.save(issue); // <-- THROWS EXCEPTION!!
dataset.setNrIssues(dataset.getNrIssues() + 1);
} catch (UnableToLinkIssueDetailsException | CommitNotFoundException e) {
log.warn(String.format("Skipping issue %s: %s", record.getIssue_key(), e.getMessage()));
dataset.getSkippedIssuesKeys().add(record.getIssue_key());
}
}
}
}
}
skipped = dataset.getSkippedIssuesKeys().size();
if (skipped > 0) {
log.warn(String.format("Skipped %d issues", skipped));
}
} catch (UnableToGetIssuesException | IOException e) {
throw new UnableToLoadIssuesException(e);
}
}
private void linkIssueDetails(Issue issue, JiraDao jiraDao) throws UnableToLinkIssueDetailsException {
try {
IssueDetails details = jiraDao.queryIssueDetails(issue.getKey());
issue.setDetails(details);
} catch (UnableToGetIssueException e) {
throw new UnableToLinkIssueDetailsException(e);
}
}
private void linkCommit(Issue issue, String commitHash) throws CommitNotFoundException {
Commit commit = commitDao.findByHash(commitHash);
if (commit == null){
throw new CommitNotFoundException(issue, commitHash);
}
issue.setCommit(commit);
}
/*
* Loads apachejit dataset from the filesystem into the local db,
* fetching issue details from Jira API
*
* @return a @Code Dataset entity with some stats about the dataset
*/
@Override
public void loadDataset() throws UnableToLoadDatasetException {
ApachejitDao apachejitDao;
JiraDao jiraDao;
if(apachejitConfig.isSkipLoad()) return;
try {
if(dataset == null){
dataset = new Dataset();
dataset.setName("apachejit");
}
apachejitDao = new ApachejitDao();
jiraDao = new JiraDao(
jiraConfig.getHostname(),
jiraConfig.getApiVersion());
loadCommits(apachejitDao);
loadIssues(apachejitDao, jiraDao);
datasetDao.save(dataset);
} catch (UnableToLoadCommitsException | UnableToLoadIssuesException e) {
dataset = null;
throw new UnableToLoadDatasetException(e);
}
}
}
</code>
<code>public class DatasetControllerTest { @Autowired private IDatasetController datasetController; @Test public void testLoadDataset() throws UnableToLoadDatasetException{ datasetController.loadDataset(); log.info(datasetController.getDataset().toString()); } } @Service @Slf4j public class ApachejitController implements IDatasetController{ @Autowired private ApachejitConfig apachejitConfig; @Autowired private JiraConfig jiraConfig; @Autowired private CommitDao commitDao; @Autowired private IssueDao issueDao; @Autowired private DatasetDao datasetDao; private Dataset dataset; private void loadIssues(ApachejitDao apachejitDao, JiraDao jiraDao) throws UnableToLoadIssuesException { /** * - get the path of the issues folder from the configuration * - list all csvs in the folder * - for each csv * - load each issue record from csv * - for each record * - transform record into an Issue object * - fetch issue details from Jira API * - store IssueDetails reference in Issue * - load Commit matching the hash commit in Issue * - store Commit reference in Issue * - save Issue in the database */ List<Resultset<IssueRecord>> issues; Issue issue; IssueRecord record; int skipped; try { issues = apachejitDao.getAllIssues(apachejitConfig.getIssuesPath()); for (int i = 0; i < issues.size(); i++) { try (Resultset<IssueRecord> projectIssues = issues.get(i)) { while (projectIssues.hasNext()) { record = projectIssues.next(); // skip commit if it is already in db, but only if // we do not have to refresh the db if (!issueDao.existsByKey(record.getIssue_key()) || apachejitConfig.isRefresh()) { try { issue = new Issue(); issue.setKey(record.getIssue_key()); linkIssueDetails(issue, jiraDao); linkCommit(issue, record.getCommit_id()); issueDao.save(issue); // <-- THROWS EXCEPTION!! dataset.setNrIssues(dataset.getNrIssues() + 1); } catch (UnableToLinkIssueDetailsException | CommitNotFoundException e) { log.warn(String.format("Skipping issue %s: %s", record.getIssue_key(), e.getMessage())); dataset.getSkippedIssuesKeys().add(record.getIssue_key()); } } } } } skipped = dataset.getSkippedIssuesKeys().size(); if (skipped > 0) { log.warn(String.format("Skipped %d issues", skipped)); } } catch (UnableToGetIssuesException | IOException e) { throw new UnableToLoadIssuesException(e); } } private void linkIssueDetails(Issue issue, JiraDao jiraDao) throws UnableToLinkIssueDetailsException { try { IssueDetails details = jiraDao.queryIssueDetails(issue.getKey()); issue.setDetails(details); } catch (UnableToGetIssueException e) { throw new UnableToLinkIssueDetailsException(e); } } private void linkCommit(Issue issue, String commitHash) throws CommitNotFoundException { Commit commit = commitDao.findByHash(commitHash); if (commit == null){ throw new CommitNotFoundException(issue, commitHash); } issue.setCommit(commit); } /* * Loads apachejit dataset from the filesystem into the local db, * fetching issue details from Jira API * * @return a @Code Dataset entity with some stats about the dataset */ @Override public void loadDataset() throws UnableToLoadDatasetException { ApachejitDao apachejitDao; JiraDao jiraDao; if(apachejitConfig.isSkipLoad()) return; try { if(dataset == null){ dataset = new Dataset(); dataset.setName("apachejit"); } apachejitDao = new ApachejitDao(); jiraDao = new JiraDao( jiraConfig.getHostname(), jiraConfig.getApiVersion()); loadCommits(apachejitDao); loadIssues(apachejitDao, jiraDao); datasetDao.save(dataset); } catch (UnableToLoadCommitsException | UnableToLoadIssuesException e) { dataset = null; throw new UnableToLoadDatasetException(e); } } } </code>
public class DatasetControllerTest {

    @Autowired private IDatasetController datasetController;

    @Test
    public void testLoadDataset() throws UnableToLoadDatasetException{
      
        datasetController.loadDataset();
        log.info(datasetController.getDataset().toString());

    }
}

@Service
@Slf4j
public class ApachejitController implements IDatasetController{

    @Autowired private ApachejitConfig apachejitConfig;
    @Autowired private JiraConfig jiraConfig;
    @Autowired private CommitDao commitDao;
    @Autowired private IssueDao issueDao;
    @Autowired private DatasetDao datasetDao;

    private Dataset dataset;
    
    private void loadIssues(ApachejitDao apachejitDao, JiraDao jiraDao) throws UnableToLoadIssuesException {
        /**
         * - get the path of the issues folder from the configuration
         * - list all csvs in the folder
         * - for each csv
         *  - load each issue record from csv
         *  - for each record
         *   - transform record into an Issue object
         *   - fetch issue details from Jira API
         *   - store IssueDetails reference in Issue
         *   - load Commit matching the hash commit in Issue
         *   - store Commit reference in Issue
         *   - save Issue in the database
        */
        
        List<Resultset<IssueRecord>> issues;        
        Issue issue;
        IssueRecord record;
        int skipped;

        try {
            issues = apachejitDao.getAllIssues(apachejitConfig.getIssuesPath());

            for (int i = 0; i < issues.size(); i++) {
                try (Resultset<IssueRecord> projectIssues = issues.get(i)) {
                    while (projectIssues.hasNext()) {
                        
                        record = projectIssues.next();
                        // skip commit if it is already in db, but only if
                         // we do not have to refresh the db
                        if (!issueDao.existsByKey(record.getIssue_key())
                            || apachejitConfig.isRefresh()) {
                            try {
                                issue = new Issue();
                                issue.setKey(record.getIssue_key());
                                linkIssueDetails(issue, jiraDao);
                                linkCommit(issue, record.getCommit_id());                        
                                issueDao.save(issue);    // <-- THROWS EXCEPTION!!
                                dataset.setNrIssues(dataset.getNrIssues() + 1);
                            } catch (UnableToLinkIssueDetailsException | CommitNotFoundException e) {
                                log.warn(String.format("Skipping issue %s: %s", record.getIssue_key(), e.getMessage()));
                                dataset.getSkippedIssuesKeys().add(record.getIssue_key());
                            }
                        } 
                    }    
                    
                } 
            }
            skipped = dataset.getSkippedIssuesKeys().size();
            if (skipped > 0) {
                log.warn(String.format("Skipped %d issues", skipped));
            }
        } catch (UnableToGetIssuesException | IOException e) {
        
            throw new UnableToLoadIssuesException(e);
        }
    }

    private void linkIssueDetails(Issue issue, JiraDao jiraDao) throws UnableToLinkIssueDetailsException {
        try {
            IssueDetails details = jiraDao.queryIssueDetails(issue.getKey());
            issue.setDetails(details);
            
        } catch (UnableToGetIssueException e) {
            throw new UnableToLinkIssueDetailsException(e);
        }
    }

    private void linkCommit(Issue issue, String commitHash) throws CommitNotFoundException {

        Commit commit = commitDao.findByHash(commitHash);
        if (commit == null){
            throw new CommitNotFoundException(issue, commitHash);
        }
        issue.setCommit(commit);
    }

    /*
     * Loads apachejit dataset from the filesystem into the local db,
     * fetching issue details from Jira API
     * 
     * @return a @Code Dataset entity with some stats about the dataset 
     */
    @Override
    public void loadDataset() throws UnableToLoadDatasetException {
                
        ApachejitDao apachejitDao;
        JiraDao jiraDao;

        if(apachejitConfig.isSkipLoad()) return;

        try {
                
            if(dataset == null){
                dataset = new Dataset();
                dataset.setName("apachejit");
            }

            apachejitDao = new ApachejitDao();
            jiraDao = new JiraDao(
                jiraConfig.getHostname(),
                jiraConfig.getApiVersion());
            
            loadCommits(apachejitDao);
            loadIssues(apachejitDao, jiraDao);
            datasetDao.save(dataset);

        } catch (UnableToLoadCommitsException | UnableToLoadIssuesException e) {
            dataset = null;
            throw new UnableToLoadDatasetException(e);
        }
    }
    
}


Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật