title: Entities not persisting. Are RepositoryItemWriter & SimpleJpaWriter thread-safe?
body: <p>I have encountered an odd issue with a RepositoryItemWriter, where it does not appear to be persisting entities correctly through my configured Spring Data JPA repository to the data source.</p>
  
  <p>Step configuration</p>
  
  <pre><code>@Bean
  public Step orderStep(StepBuilderFactory stepBuilderFactory, ItemReader&lt;OrderEncounter&gt; orderEncounterReader, ItemWriter&lt;List&lt;Order&gt;&gt; orderWriter,
                        ItemProcessor&lt;OrderEncounter, List&lt;Order&gt;&gt; orderProcessor, TaskExecutor taskExecutor) {
      return stepBuilderFactory.get("orderStep")
              .&lt;OrderEncounter, List&lt;Order&gt;&gt; chunk(10)
              .reader(orderEncounterReader)
              .processor(orderProcessor)
              .writer(orderWriter)
              .taskExecutor(taskExecutor)
              .build();
  }
  </code></pre>
  
  <p>Task Executor Bean (configured for 1 thread for testing purposes)</p>
  
  <pre><code>@Bean
  public TaskExecutor taskExecutor() {
      ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
      taskExecutor.setCorePoolSize(1);
      taskExecutor.setMaxPoolSize(1);
      taskExecutor.afterPropertiesSet();
      return taskExecutor;
  }
  </code></pre>
  
  <p>OrderRepository</p>
  
  <pre><code>@Repository
  public interface OrderRepository extends PagingAndSortingRepository&lt;Order, Long&gt; {
  
  }
  </code></pre>
  
  <p>orderWriter bean</p>
  
  <pre><code>@Bean
  public ItemWriter&lt;List&lt;Order&gt;&gt; orderWriter(OrderRepository orderRepository) {
      RepositoryListItemWriter&lt;List&lt;Order&gt;&gt; writer = new RepositoryListItemWriter&lt;&gt;();
      writer.setRepository(orderRepository);
      writer.setMethodName("save");
  
      try {
          writer.afterPropertiesSet();
      } catch (Exception e) {
          e.printStackTrace();
      }
  
      return writer;
  }
  </code></pre>
  
  <p>RepositoryListItemWriter (modified RepositoryItemWriter to support multiple items that are returned from a stored procedure result set)</p>
  
  <pre><code>public class RepositoryListItemWriter&lt;T&gt; implements ItemWriter&lt;T&gt;, InitializingBean {
      protected static final Log logger = LogFactory.getLog(RepositoryListItemWriter.class);
      private CrudRepository&lt;?, ?&gt; repository;
      private String methodName;
  
      public RepositoryListItemWriter() {
      }
  
      public void setMethodName(String methodName) {
          this.methodName = methodName;
      }
  
      public void setRepository(CrudRepository&lt;?, ?&gt; repository) {
          this.repository = repository;
      }
  
      public void write(List&lt;? extends T&gt; items) throws Exception {
          if(!CollectionUtils.isEmpty(items)) {
              this.doWrite(items);
          }
  
      }
  
      protected void doWrite(List&lt;? extends T&gt; items) throws Exception {
          if(logger.isDebugEnabled()) {
              logger.debug("Writing to the repository with " + items.size() + " items.");
          }
  
          MethodInvoker invoker = this.createMethodInvoker(this.repository, this.methodName);
          Iterator i$ = items.iterator();
  
          while(i$.hasNext()) {
              Object object = i$.next();
              invoker.setArguments(new Object[]{object});
              this.doInvoke(invoker);
          }
  
      }
  
      public void afterPropertiesSet() throws Exception {
          Assert.state(this.repository != null, "A CrudRepository implementation is required");
      }
  
      private Object doInvoke(MethodInvoker invoker) throws Exception {
          try {
              invoker.prepare();
          } catch (ClassNotFoundException var3) {
              throw new DynamicMethodInvocationException(var3);
          } catch (NoSuchMethodException var4) {
              throw new DynamicMethodInvocationException(var4);
          }
  
          try {
              return invoker.invoke();
          } catch (InvocationTargetException var5) {
              if(var5.getCause() instanceof Exception) {
                  throw (Exception)var5.getCause();
              } else {
                  throw new InvocationTargetThrowableWrapper(var5.getCause());
              }
          } catch (IllegalAccessException var6) {
              throw new DynamicMethodInvocationException(var6);
          }
      }
  
      private MethodInvoker createMethodInvoker(Object targetObject, String targetMethod) {
          MethodInvoker invoker = new MethodInvoker();
          invoker.setTargetObject(targetObject);
          invoker.setTargetMethod(targetMethod);
          return invoker;
      }
  }
  </code></pre>
  
  <p>When orderStep is configured without a taskExecutor, then entities persist fine through the RepositoryItemWriter to the database; however, when it is configured with even a single-threaded taskExecutor, nothing is persisted to the database throughout the entire job execution - including after completion.</p>
  
  <p>I've performed a considerable amount of research and RepositoryItemWriter appears to be thread-safe -- along with PagingAndSortingRepository &amp; SimpleJpaWriter. Any suggestions?</p>
  
  <p>Trace-level log output</p>
  
  <p>No TaskExecutor in job:</p>
  
  <pre><code>2015-11-23 20:51:07.589 TRACE 31126 --- [nio-8080-exec-1] o.s.beans.CachedIntrospectionResults     : Found bean property 'verified
  ChangedByUsername' of type [java.lang.String]2015-11-23 20:51:07.589 TRACE 31126 --- [nio-8080-exec-1] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springfr
  amework.orm.jpa.EntityManagerHolder@56ca0bbc] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@5ffffca4] bound to thread [http-nio-8080-exec-1]2015-11-23 20:51:07.590 TRACE 31126 --- [nio-8080-exec-1] o.h.e.i.AbstractSaveEventListener        : Transient instance of: com.ii
  massociates.distiller.domain.Order2015-11-23 20:51:07.590 TRACE 31126 --- [nio-8080-exec-1] o.h.e.i.DefaultPersistEventListener      : Saving transient instance
  2015-11-23 20:51:07.590 TRACE 31126 --- [nio-8080-exec-1] o.h.e.i.AbstractSaveEventListener        : Saving [com.iimassociates.distiller.domain.Order#&lt;null&gt;]
  2015-11-23 20:51:07.591 TRACE 31126 --- [nio-8080-exec-1] org.hibernate.engine.spi.ActionQueue     : Adding an EntityIdentityInsertAction for [com.iimassociates.distiller.domain.Order] object
  2015-11-23 20:51:07.591 TRACE 31126 --- [nio-8080-exec-1] org.hibernate.engine.spi.ActionQueue     : Executing inserts before finding non-nullable transient entities for early insert: [EntityIdentityInsertAction[com.iimassociates.distiller.domain.Order#&lt;null&gt;]
  ]
  2015-11-23 20:51:07.591 TRACE 31126 --- [nio-8080-exec-1] org.hibernate.engine.spi.ActionQueue     : Adding insert with no non-nullable, transient entities: [EntityIdentityInsertAction[com.iimassociates.distiller.domain.Order#&lt;null&gt;]]
  2015-11-23 20:51:07.591 TRACE 31126 --- [nio-8080-exec-1] org.hibernate.engine.spi.ActionQueue     : Executing insertions before resolved early-insert
  2015-11-23 20:51:07.591 DEBUG 31126 --- [nio-8080-exec-1] org.hibernate.engine.spi.ActionQueue     : Executing identity-insert immediately
  2015-11-23 20:51:07.591 TRACE 31126 --- [nio-8080-exec-1] o.h.p.entity.AbstractEntityPersister     : Inserting entity: com.iimassociates.distiller.domain.Order (native id)
  2015-11-23 20:51:07.592 DEBUG 31126 --- [nio-8080-exec-1] org.hibernate.SQL                        : insert into orders (blah blah SQL)
  </code></pre>
  
  <p>TaskExecutor in job</p>
  
  <pre><code>2015-11-23 21:02:34.628 TRACE 31257 --- [ taskExecutor-1] o.s.beans.CachedIntrospectionResults     : Found bean property 'verifiedChangedByUsername' of type [java.lang.String]
  2015-11-23 21:02:34.628 TRACE 31257 --- [ taskExecutor-1] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@2b151d8a] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@2706e09c] bound to thread [taskExecutor-1]
  2015-11-23 21:02:34.629 TRACE 31257 --- [ taskExecutor-1] o.h.e.i.AbstractSaveEventListener        : Transient instance of: com.iimassociates.distiller.domain.Order
  2015-11-23 21:02:34.629 TRACE 31257 --- [ taskExecutor-1] o.h.e.i.DefaultPersistEventListener      : Saving transient instance
  2015-11-23 21:02:34.629 TRACE 31257 --- [ taskExecutor-1] o.h.e.i.AbstractSaveEventListener        : Saving [com.iimassociates.distiller.domain.Order#&lt;null&gt;]
  2015-11-23 21:02:34.630 TRACE 31257 --- [ taskExecutor-1] org.hibernate.engine.spi.ActionQueue     : Adding an EntityIdentityInsertAction for [com.iimassociates.distiller.domain.Order] object
  2015-11-23 21:02:34.630 TRACE 31257 --- [ taskExecutor-1] org.hibernate.engine.spi.ActionQueue     : Adding insert with no non-nullable, transient entities: [EntityIdentityInsertAction[com.iimassociates.distiller.domain.Order#&lt;delayed:1&gt;]]
  2015-11-23 21:02:34.630 TRACE 31257 --- [ taskExecutor-1] org.hibernate.engine.spi.ActionQueue     : Adding resolved non-early insert action.
  2015-11-23 21:02:34.630 TRACE 31257 --- [ taskExecutor-1] o.h.a.i.UnresolvedEntityInsertActions    : No unresolved entity inserts that depended on [[com.iimassociates.distiller.domain.Order#&lt;delayed:1&gt;]]
  2015-11-23 21:02:34.630 TRACE 31257 --- [ taskExecutor-1] o.h.a.i.UnresolvedEntityInsertActions    : No entity insert actions have non-nullable, transient entity dependencies.
  2015-11-23 21:02:34.630 TRACE 31257 --- [ taskExecutor-1] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.jpa.EntityManagerHolder@2b151d8a] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@2706e09c] bound to thread [taskExecutor-1]
  2015-11-23 21:02:34.630 TRACE 31257 --- [ taskExecutor-1] o.h.e.i.AbstractSaveEventListener        : Transient instance of: com.iimassociates.distiller.domain.Order
  2015-11-23 21:02:34.630 TRACE 31257 --- [ taskExecutor-1] o.h.e.i.DefaultPersistEventListener      : Saving transient instance
  2015-11-23 21:02:34.630 TRACE 31257 --- [ taskExecutor-1] o.h.e.i.AbstractSaveEventListener        : Saving [com.iimassociates.distiller.domain.Order#&lt;null&gt;]
  2015-11-23 21:02:34.631 TRACE 31257 --- [ taskExecutor-1] org.hibernate.engine.spi.ActionQueue     : Adding an EntityIdentityInsertAction for [com.iimassociates.distiller.domain.Order] object
  2015-11-23 21:02:34.631 TRACE 31257 --- [ taskExecutor-1] org.hibernate.engine.spi.ActionQueue     : Adding insert with no non-nullable, transient entities: [EntityIdentityInsertAction[com.iimassociates.distiller.domain.Order#&lt;delayed:2&gt;]]
  2015-11-23 21:02:34.631 TRACE 31257 --- [ taskExecutor-1] org.hibernate.engine.spi.ActionQueue     : Adding resolved non-early insert action.
  </code></pre>