diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapExecutionContextDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapExecutionContextDao.java index 9261f8890..c6862023a 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapExecutionContextDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapExecutionContextDao.java @@ -2,6 +2,7 @@ package org.springframework.batch.core.repository.dao; import java.util.Map; +import org.apache.commons.lang.SerializationUtils; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.StepExecution; import org.springframework.batch.item.ExecutionContext; @@ -17,22 +18,26 @@ public class MapExecutionContextDao implements ExecutionContextDao { contextsByJobExecutionId.clear(); contextsByStepExecutionId.clear(); } + + private static ExecutionContext copy(ExecutionContext original) { + return (ExecutionContext) SerializationUtils.deserialize(SerializationUtils.serialize(original)); + } public ExecutionContext getExecutionContext(StepExecution stepExecution) { - return contextsByStepExecutionId.get(stepExecution.getId()); + return copy(contextsByStepExecutionId.get(stepExecution.getId())); } public void persistExecutionContext(StepExecution stepExecution) { - contextsByStepExecutionId.put(stepExecution.getId(), stepExecution.getExecutionContext()); + contextsByStepExecutionId.put(stepExecution.getId(), copy(stepExecution.getExecutionContext())); } public ExecutionContext getExecutionContext(JobExecution jobExecution) { - return contextsByJobExecutionId.get(jobExecution.getId()); + return copy(contextsByJobExecutionId.get(jobExecution.getId())); } public void persistExecutionContext(JobExecution jobExecution) { - contextsByJobExecutionId.put(jobExecution.getId(), jobExecution.getExecutionContext()); + contextsByJobExecutionId.put(jobExecution.getId(), copy(jobExecution.getExecutionContext())); } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapStepExecutionDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapStepExecutionDao.java index 8fba0163b..b9873985b 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapStepExecutionDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapStepExecutionDao.java @@ -21,6 +21,7 @@ import java.util.Comparator; import java.util.List; import java.util.Map; +import org.apache.commons.lang.SerializationUtils; import org.springframework.batch.core.Entity; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.StepExecution; @@ -40,6 +41,10 @@ public class MapStepExecutionDao implements StepExecutionDao { public static void clear() { executionsByJobExecutionId.clear(); } + + private static StepExecution copy(StepExecution original){ + return (StepExecution) SerializationUtils.deserialize(SerializationUtils.serialize(original)); + } public void saveStepExecution(StepExecution stepExecution) { Assert.isTrue(stepExecution.getId() == null); @@ -53,7 +58,7 @@ public class MapStepExecutionDao implements StepExecutionDao { } stepExecution.setId(new Long(currentId++)); stepExecution.incrementVersion(); - executions.put(stepExecution.getStepName(), stepExecution); + executions.put(stepExecution.getStepName(), copy(stepExecution)); } public void updateStepExecution(StepExecution stepExecution) { @@ -72,7 +77,7 @@ public class MapStepExecutionDao implements StepExecutionDao { } stepExecution.incrementVersion(); - executions.put(stepExecution.getStepName(), stepExecution); + executions.put(stepExecution.getStepName(), copy(stepExecution)); } } @@ -82,7 +87,7 @@ public class MapStepExecutionDao implements StepExecutionDao { return null; } - return (StepExecution) executions.get(stepName); + return copy(executions.get(stepName)); } public List getStepExecutions(JobExecution jobExecution) { @@ -94,6 +99,11 @@ public class MapStepExecutionDao implements StepExecutionDao { return Long.signum(o2.getId() - o1.getId()); } }); - return result; + + List copy = new ArrayList(result.size()); + for(StepExecution exec : result) { + copy.add(copy(exec)); + } + return copy; } } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java index f662329ac..dc284c278 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java @@ -483,6 +483,8 @@ public class SimpleJobTests extends TestCase { } stepExecution.setExitStatus(ExitStatus.FINISHED); stepExecution.setStatus(BatchStatus.COMPLETED); + jobRepository.update(stepExecution); + jobRepository.updateExecutionContext(stepExecution); } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/MapJobExecutionDaoTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/MapJobExecutionDaoTests.java index 6015ed0ee..a1dba96b0 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/MapJobExecutionDaoTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/MapJobExecutionDaoTests.java @@ -35,6 +35,10 @@ public class MapJobExecutionDaoTests extends AbstractJobExecutionDaoTests { JobExecution retrieved = tested.getJobExecution(jobExecution.getId()); assertNull(retrieved.getStartTime()); + tested.updateJobExecution(jobExecution); + jobExecution.setEndTime(new Date()); + assertNull(retrieved.getEndTime()); + } } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/MapStepExecutionDaoTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/MapStepExecutionDaoTests.java index ca688f14e..1eaafc483 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/MapStepExecutionDaoTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/MapStepExecutionDaoTests.java @@ -1,7 +1,14 @@ package org.springframework.batch.core.repository.dao; +import static org.junit.Assert.*; + +import java.util.Date; + +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.StepExecution; import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.core.repository.support.SimpleJobRepository; +import org.junit.Test; import org.junit.runner.RunWith; import org.junit.internal.runners.JUnit4ClassRunner; @@ -19,5 +26,29 @@ public class MapStepExecutionDaoTests extends AbstractStepExecutionDaoTests { return new SimpleJobRepository(new MapJobInstanceDao(), new MapJobExecutionDao(), new MapStepExecutionDao(), new MapExecutionContextDao()); } + + /** + * Modifications to saved entity do not affect the persisted object. + */ + @Test + public void testPersistentCopy() { + StepExecutionDao tested = new MapStepExecutionDao(); + JobExecution jobExecution = new JobExecution((long) 77); + StepExecution stepExecution = new StepExecution("stepName", jobExecution); + + assertNull(stepExecution.getEndTime()); + tested.saveStepExecution(stepExecution); + stepExecution.setEndTime(new Date()); + + StepExecution retrieved = tested.getStepExecution(jobExecution, "stepName"); + assertNull(retrieved.getEndTime()); + + stepExecution.setEndTime(null); + tested.updateStepExecution(stepExecution); + stepExecution.setEndTime(new Date()); + + StepExecution stored = tested.getStepExecution(jobExecution, "stepName"); + assertNull(stored.getEndTime()); + } }