Fixed enum comparison in AbstractStatemachine#resetStateMachine
- Add a check for enum class as well so that restore doesn't pick a wrong instance. - Fixes #554
This commit is contained in:
committed by
Janne Valkealahti
parent
1a797532ca
commit
cb74a35bff
@@ -15,6 +15,15 @@
|
||||
*/
|
||||
package org.springframework.statemachine.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
@@ -60,15 +69,6 @@ import org.springframework.statemachine.trigger.Trigger;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
/**
|
||||
* Base implementation of a {@link StateMachine} loosely modelled from UML state
|
||||
* machine.
|
||||
@@ -655,7 +655,7 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
|
||||
for (State<S, E> ss : s.getStates()) {
|
||||
|
||||
boolean enumMatch = false;
|
||||
if (state instanceof Enum && ss.getId() instanceof Enum
|
||||
if (state instanceof Enum && ss.getId() instanceof Enum && state.getClass() == ss.getId().getClass()
|
||||
&& ((Enum) ss.getId()).ordinal() == ((Enum) state).ordinal()) {
|
||||
enumMatch = true;
|
||||
}
|
||||
@@ -717,9 +717,11 @@ public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSuppo
|
||||
S state2 = child.getState();
|
||||
boolean enumMatch2 = false;
|
||||
if (state2 instanceof Enum && ss.getId() instanceof Enum
|
||||
&& state.getClass() == ss.getId().getClass()
|
||||
&& ((Enum) ss.getId()).ordinal() == ((Enum) state2).ordinal()) {
|
||||
enumMatch2 = true;
|
||||
}
|
||||
|
||||
if (state2 != null && (ss.getIds().contains(state2) || enumMatch2) ) {
|
||||
currentState = s;
|
||||
lastState = currentState;
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.EnableStateMachine;
|
||||
import org.springframework.statemachine.config.EnableStateMachineFactory;
|
||||
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
|
||||
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
|
||||
import org.springframework.statemachine.config.StateMachineFactory;
|
||||
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
@@ -377,6 +378,54 @@ public class StateMachineResetTests extends AbstractStateMachineTests {
|
||||
assertThat(listener.count2, is(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResetFunkyEnumTypes1() throws Exception {
|
||||
context.register(Config6.class);
|
||||
context.refresh();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
StateMachine<MyState, MyEvent> machine = context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE,
|
||||
StateMachine.class);
|
||||
|
||||
DefaultStateMachineContext<MyState, MyEvent> stateMachineContext = new DefaultStateMachineContext<MyState, MyEvent>(
|
||||
SubState.SUB_NEXT, null, null, null);
|
||||
|
||||
machine.getStateMachineAccessor().doWithAllRegions(new StateMachineFunction<StateMachineAccess<MyState, MyEvent>>() {
|
||||
|
||||
@Override
|
||||
public void apply(StateMachineAccess<MyState, MyEvent> function) {
|
||||
function.resetStateMachine(stateMachineContext);
|
||||
}
|
||||
});
|
||||
|
||||
machine.start();
|
||||
assertThat(machine.getState().getIds(), containsInAnyOrder(SuperState.PARENT, SubState.SUB_NEXT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResetFunkyEnumTypes2() throws Exception {
|
||||
context.register(Config6.class);
|
||||
context.refresh();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
StateMachine<MyState, MyEvent> machine = context.getBean(StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE,
|
||||
StateMachine.class);
|
||||
|
||||
DefaultStateMachineContext<MyState, MyEvent> stateMachineContext = new DefaultStateMachineContext<MyState, MyEvent>(
|
||||
SuperState.INITIAL, null, null, null);
|
||||
|
||||
machine.getStateMachineAccessor().doWithAllRegions(new StateMachineFunction<StateMachineAccess<MyState, MyEvent>>() {
|
||||
|
||||
@Override
|
||||
public void apply(StateMachineAccess<MyState, MyEvent> function) {
|
||||
function.resetStateMachine(stateMachineContext);
|
||||
}
|
||||
});
|
||||
|
||||
machine.start();
|
||||
assertThat(machine.getState().getIds(), containsInAnyOrder(SuperState.INITIAL));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
static class Config1 extends EnumStateMachineConfigurerAdapter<States, Events> {
|
||||
@@ -756,4 +805,65 @@ public class StateMachineResetTests extends AbstractStateMachineTests {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@Configuration
|
||||
@EnableStateMachine
|
||||
static class Config6 extends StateMachineConfigurerAdapter<MyState, MyEvent> {
|
||||
|
||||
@Override
|
||||
public void configure(final StateMachineStateConfigurer<MyState, MyEvent> states) throws Exception {
|
||||
states
|
||||
.withStates()
|
||||
.end(SuperState.END)
|
||||
.state(SuperState.PARENT)
|
||||
.initial(SuperState.INITIAL)
|
||||
.and()
|
||||
.withStates()
|
||||
.parent(SuperState.PARENT)
|
||||
.initial(SubState.SUB_INITIAL)
|
||||
.state(SubState.SUB_NEXT)
|
||||
.end(SubState.SUB_END);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(final StateMachineTransitionConfigurer<MyState, MyEvent> transitions) throws Exception {
|
||||
transitions
|
||||
.withExternal()
|
||||
.source(SuperState.INITIAL)
|
||||
.target(SuperState.PARENT)
|
||||
.event(MyEvent.GO)
|
||||
.and()
|
||||
.withExternal()
|
||||
.source(SuperState.PARENT)
|
||||
.target(SuperState.END)
|
||||
.event(MyEvent.GO)
|
||||
.and()
|
||||
.withExternal()
|
||||
.source(SubState.SUB_INITIAL)
|
||||
.target(SubState.SUB_NEXT)
|
||||
.event(MyEvent.GO)
|
||||
.and()
|
||||
.withExternal()
|
||||
.source(SubState.SUB_NEXT)
|
||||
.target(SubState.SUB_END)
|
||||
.event(MyEvent.GO);
|
||||
}
|
||||
}
|
||||
|
||||
public enum SubState implements MyState {
|
||||
SUB_INITIAL,
|
||||
SUB_NEXT,
|
||||
SUB_END;
|
||||
}
|
||||
|
||||
public enum SuperState implements MyState {
|
||||
INITIAL,
|
||||
PARENT,
|
||||
END;
|
||||
}
|
||||
|
||||
public interface MyState {
|
||||
}
|
||||
|
||||
public enum MyEvent {
|
||||
GO;
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user