Add checks for missing transitions
- Now checking if some transitions are missing and throwing a proper exception instead of NPE. - Fixes #775
This commit is contained in:
@@ -46,6 +46,7 @@ import org.springframework.statemachine.config.model.EntryData;
|
||||
import org.springframework.statemachine.config.model.ExitData;
|
||||
import org.springframework.statemachine.config.model.HistoryData;
|
||||
import org.springframework.statemachine.config.model.JunctionData;
|
||||
import org.springframework.statemachine.config.model.MalformedConfigurationException;
|
||||
import org.springframework.statemachine.config.model.StateData;
|
||||
import org.springframework.statemachine.config.model.StateMachineModel;
|
||||
import org.springframework.statemachine.config.model.StateMachineModelFactory;
|
||||
@@ -665,6 +666,9 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
State<S, E> defaultState = null;
|
||||
S s = stateData.getState();
|
||||
Collection<HistoryData<S,E>> historys = stateMachineTransitions.getHistorys();
|
||||
if (historys == null) {
|
||||
throw new MalformedConfigurationException("No transitions for state " + s);
|
||||
}
|
||||
for (HistoryData<S,E> history : historys) {
|
||||
if (history.getSource().equals(s)) {
|
||||
defaultState = stateMap.get(history.getTarget());
|
||||
@@ -685,6 +689,9 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
State<S, E> defaultState = null;
|
||||
S s = stateData.getState();
|
||||
Collection<HistoryData<S,E>> historys = stateMachineTransitions.getHistorys();
|
||||
if (historys == null) {
|
||||
throw new MalformedConfigurationException("No transitions for state " + s);
|
||||
}
|
||||
for (HistoryData<S,E> history : historys) {
|
||||
if (history.getSource().equals(s)) {
|
||||
defaultState = stateMap.get(history.getTarget());
|
||||
@@ -706,6 +713,9 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
if (stateData.getPseudoStateKind() == PseudoStateKind.CHOICE) {
|
||||
S s = stateData.getState();
|
||||
List<ChoiceData<S, E>> list = stateMachineTransitions.getChoices().get(s);
|
||||
if (list == null) {
|
||||
throw new MalformedConfigurationException("No transitions for state " + s);
|
||||
}
|
||||
List<ChoiceStateData<S, E>> choices = new ArrayList<ChoiceStateData<S, E>>();
|
||||
for (ChoiceData<S, E> c : list) {
|
||||
StateHolder<S, E> holder = new StateHolder<S, E>(stateMap.get(c.getTarget()));
|
||||
@@ -723,6 +733,9 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
S s = stateData.getState();
|
||||
List<JunctionData<S, E>> list = stateMachineTransitions.getJunctions().get(s);
|
||||
List<JunctionStateData<S, E>> junctions = new ArrayList<JunctionStateData<S, E>>();
|
||||
if (list == null) {
|
||||
throw new MalformedConfigurationException("No transitions for state " + s);
|
||||
}
|
||||
for (JunctionData<S, E> c : list) {
|
||||
StateHolder<S, E> holder = new StateHolder<S, E>(stateMap.get(c.getTarget()));
|
||||
if (holder.getState() == null) {
|
||||
@@ -738,6 +751,9 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
} else if (stateData.getPseudoStateKind() == PseudoStateKind.ENTRY) {
|
||||
S s = stateData.getState();
|
||||
Collection<EntryData<S, E>> entrys = stateMachineTransitions.getEntrys();
|
||||
if (entrys == null) {
|
||||
throw new MalformedConfigurationException("No transitions for state " + s);
|
||||
}
|
||||
for (EntryData<S, E> entry : entrys) {
|
||||
if (s.equals(entry.getSource())) {
|
||||
PseudoState<S, E> pseudoState = new EntryPseudoState<S, E>(stateMap.get(entry.getTarget()));
|
||||
@@ -751,6 +767,9 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
} else if (stateData.getPseudoStateKind() == PseudoStateKind.EXIT) {
|
||||
S s = stateData.getState();
|
||||
Collection<ExitData<S, E>> exits = stateMachineTransitions.getExits();
|
||||
if (exits == null) {
|
||||
throw new MalformedConfigurationException("No transitions for state " + s);
|
||||
}
|
||||
for (ExitData<S, E> entry : exits) {
|
||||
if (s.equals(entry.getSource())) {
|
||||
StateHolder<S, E> holder = new StateHolder<S, E>(stateMap.get(entry.getTarget()));
|
||||
@@ -769,6 +788,9 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
S s = stateData.getState();
|
||||
List<S> list = stateMachineTransitions.getForks().get(s);
|
||||
List<State<S, E>> forks = new ArrayList<State<S,E>>();
|
||||
if (list == null) {
|
||||
throw new MalformedConfigurationException("No transitions for state " + s);
|
||||
}
|
||||
for (S fs : list) {
|
||||
forks.add(stateMap.get(fs));
|
||||
}
|
||||
@@ -780,6 +802,9 @@ public abstract class AbstractStateMachineFactory<S, E> extends LifecycleObjectS
|
||||
} else if (stateData.getPseudoStateKind() == PseudoStateKind.JOIN) {
|
||||
S s = stateData.getState();
|
||||
List<S> list = stateMachineTransitions.getJoins().get(s);
|
||||
if (list == null) {
|
||||
throw new MalformedConfigurationException("No transitions for state " + s);
|
||||
}
|
||||
List<List<State<S, E>>> joins = new ArrayList<List<State<S, E>>>();
|
||||
|
||||
// if join source is an orthogonal state, assume we're joining by region end states
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.statemachine.config;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
@@ -121,6 +122,26 @@ public class ConfigurationErrorTests extends AbstractStateMachineTests {
|
||||
assertThat(verifier.latch.await(2, TimeUnit.SECONDS), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPseudostateNoTransition() throws Exception {
|
||||
Exception exception = assertThrows(Exception.class, ()-> {
|
||||
Builder<String, String> builder = StateMachineBuilder.builder();
|
||||
builder.configureStates()
|
||||
.withStates()
|
||||
.initial("S1")
|
||||
.state("S1")
|
||||
.choice("S2")
|
||||
.state("S3");
|
||||
builder.configureTransitions()
|
||||
.withExternal()
|
||||
.source("S1")
|
||||
.target("S2");
|
||||
builder.build();
|
||||
});
|
||||
assertTrue(exception.getCause() instanceof MalformedConfigurationException);
|
||||
assertThat(exception.getLocalizedMessage(), containsString("No transitions for state S2"));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
public static class Config1 extends StateMachineConfigurerAdapter<String, String> {
|
||||
|
||||
Reference in New Issue
Block a user