diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/builder/FlowBuilder.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/builder/FlowBuilder.java index 8a3a16ae3..d06c69c05 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/builder/FlowBuilder.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/builder/FlowBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ import org.springframework.batch.core.job.flow.Flow; import org.springframework.batch.core.job.flow.FlowExecutionStatus; import org.springframework.batch.core.job.flow.JobExecutionDecider; import org.springframework.batch.core.job.flow.State; +import org.springframework.batch.core.job.flow.support.DefaultStateTransitionComparator; import org.springframework.batch.core.job.flow.support.SimpleFlow; import org.springframework.batch.core.job.flow.support.StateTransition; import org.springframework.batch.core.job.flow.support.state.DecisionState; @@ -44,6 +45,7 @@ import org.springframework.core.task.TaskExecutor; * conditional transitions that depend on the exit status of the previous step. * * @author Dave Syer + * @author Michael Minella * * @since 2.2 * @@ -244,6 +246,7 @@ public class FlowBuilder { } addDanglingEndStates(); flow.setStateTransitions(transitions); + flow.setStateTransitionComparator(new DefaultStateTransitionComparator()); dirty = false; return flow; } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/job/builder/FlowBuilderTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/job/builder/FlowBuilderTests.java index 68b2eadbf..1fc4cd4fa 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/job/builder/FlowBuilderTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/job/builder/FlowBuilderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,11 @@ */ package org.springframework.batch.core.job.builder; +import java.util.Iterator; + import org.junit.Test; + +import org.springframework.batch.core.ExitStatus; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobInterruptedException; import org.springframework.batch.core.JobParameters; @@ -23,13 +27,17 @@ import org.springframework.batch.core.StepExecution; import org.springframework.batch.core.UnexpectedJobExecutionException; import org.springframework.batch.core.job.SimpleStepHandler; import org.springframework.batch.core.job.flow.Flow; +import org.springframework.batch.core.job.flow.FlowExecution; import org.springframework.batch.core.job.flow.JobFlowExecutor; import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean; import org.springframework.batch.core.step.StepSupport; +import static org.junit.Assert.assertEquals; + /** * @author Dave Syer + * @author Michael Minella * */ public class FlowBuilderTests { @@ -47,4 +55,43 @@ public class FlowBuilderTests { }).end().start(new JobFlowExecutor(jobRepository, new SimpleStepHandler(jobRepository), execution)); } + @Test + public void testTransitionOrdering() throws Exception { + FlowBuilder builder = new FlowBuilder<>("transitionsFlow"); + JobRepository jobRepository = new MapJobRepositoryFactoryBean().getObject(); + JobExecution execution = jobRepository.createJobExecution("foo", new JobParameters()); + + StepSupport stepA = new StepSupport("stepA") { + @Override + public void execute(StepExecution stepExecution) throws JobInterruptedException, + UnexpectedJobExecutionException { + stepExecution.setExitStatus(new ExitStatus("FAILED")); + } + }; + + StepSupport stepB = new StepSupport("stepB") { + @Override + public void execute(StepExecution stepExecution) throws JobInterruptedException, + UnexpectedJobExecutionException { + } + }; + + StepSupport stepC = new StepSupport("stepC") { + @Override + public void execute(StepExecution stepExecution) throws JobInterruptedException, + UnexpectedJobExecutionException { + } + }; + + FlowExecution flowExecution = builder.start(stepA) + .on("*").to(stepB) + .from(stepA).on("FAILED").to(stepC) + .end().start(new JobFlowExecutor(jobRepository, new SimpleStepHandler(jobRepository), execution)); + + Iterator stepExecutions = execution.getStepExecutions().iterator(); + StepExecution stepExecutionA = stepExecutions.next(); + assertEquals(stepExecutionA.getStepName(), "stepA"); + StepExecution stepExecutionC = stepExecutions.next(); + assertEquals(stepExecutionC.getStepName(), "stepC"); + } }