I am currently developing a microservice using spring-boot.I currently have an issue when using spring-state machine and spring-cloud-sleuth artifacts together.
@Validated
@RestController
@SuppressWarnings({"squid:S00112"})
@RequestMapping()
public class StatusController {
@Autowired
private QuoteService quoteService;
@Autowired
private StateMachine<StateMachineDefinition.States, StateMachineDefinition.Events> stateMachine;
@Autowired
private QuoteStateHandler quoteStateHandler;
@Value("${StateMachine.InvalidField.message}")
private String statusInvalidField;
@Value("${StateMachine.QuoteCannotBeNull.message}")
private String quoteStatusNull;
private static final String STATUS = "STATUS";
@InitBinder
public void initBinder(WebDataBinder binder, WebRequest request) {
binder.setAllowedFields("status");
}
/*
Possible state transitions for the specific quote.
*/
@RequestMapping(method = RequestMethod.GET, value = {"/quotes/{quoteId}/transitions", "/{internalClient:(?:ui|s2s)}/{version:^[v]+[0-9]+$}/quotes/{quoteId}/transitions"})
public List<Status> getPossibleTransitions(@PathVariable("quoteId") String id) {
String persistedStatus = quoteService.findOne(id).getStatus();
if (persistedStatus == null) {
persistedStatus = StateMachineDefinition.States.IN_PROCESS.name();
}
Collection<Transition<StateMachineDefinition.States, StateMachineDefinition.Events>> transitions = stateMachine.getTransitions();
String currentState = persistedStatus;
ArrayList<Status> possibleTransistions = new ArrayList<>();
Iterator<Transition<StateMachineDefinition.States, StateMachineDefinition.Events>> iterator = transitions.iterator();
String state;
while (iterator.hasNext()) {
Transition<StateMachineDefinition.States, StateMachineDefinition.Events> transition = iterator.next();
state = transition.getSource().getId().name();
if (state.compareTo(currentState) == 0) {
possibleTransistions.add(new Status(transition.getTrigger().getEvent().toString()));
}
}
return possibleTransistions;
}
@RequestMapping(method = RequestMethod.GET, value = {"/{internalClient:(?:ui)}/{version:^[v]+[0-9]+$}/states"})
public List<String> getStates() {
Collection<State<StateMachineDefinition.States, StateMachineDefinition.Events>> states = stateMachine.getStates();
Iterator<State<StateMachineDefinition.States, StateMachineDefinition.Events>> iterator = states.iterator();
List<String> stateList = new ArrayList<>();
while (iterator.hasNext()) {
State<StateMachineDefinition.States, StateMachineDefinition.Events> state = iterator.next();
stateList.add(state.getId().toString());
}
return stateList;
}
/*
Status is not a state but a transition or event.
*/
@RequestMapping(method = RequestMethod.POST, value = {"{quoteId}/transitions", "/{internalClient:(?:ui|s2s)}/{version:^[v]+[0-9]+$}/quotes/{quoteId}/transitions"})
@ResponseStatus(HttpStatus.NO_CONTENT)
public void postStatus(@RequestBody @Validated(Groups.Api.class) Status status, @PathVariable("quoteId") @Pattern(regexp = Patterns.UUID) String id, BindingResult bindingResult) throws Exception {
if (bindingResult.hasErrors()) {
throw new BadRequestValidationException(STATUS, statusInvalidField);
}
//get quoteid current status
Quote currentQuote = quoteService.findOne(id);
if (currentQuote.getStatus() != null) {
StateMachineDefinition.States currentQuoteState = StateMachineDefinition.States.valueOf(currentQuote.getStatus());
//need to send the event and let the state listener evaluate.
if (status.getStatus() != null) {
quoteStateHandler.handleEvent(
MessageBuilder
.withPayload(StateMachineDefinition.Events.valueOf(status.getStatus()))
.setHeader("quote-id", id)
.build(), currentQuoteState);
}
if (stateMachine.getExtendedState().getVariables().containsKey("ERROR")) {
Exception exception = (Exception) stateMachine.getExtendedState().getVariables().get("ERROR");
stateMachine.getExtendedState().getVariables().clear();
throw exception;
}
if (stateMachine.getState().getId() != currentQuoteState) {
quoteService.updateStatus(id, stateMachine.getState().getId());
}
} else {
//If a quote has null status then it wasnt created properly.
throw new BadRequestValidationException(STATUS, quoteStatusNull);
}
}
}
i didn't had any issues until I added the dependency of spring-cloud sleuth and the error popped up when I started doing the "mvn clean install".
Error stack trace:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'stateMachine': Invocation of init method failed; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'stateMachineTaskExecutor' is expected to be of type [org.springframework.core.task.TaskExecutor] but was actually of type [org.springframework.cloud.sleuth.instrument.async.LazyTraceExecutor]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1583)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:207)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1128)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1056)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:566)
... 44 common frames omitted
The error message org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'stateMachine': Invocation of init method failed; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'stateMachineTaskExecutor' is expected to be of type [org.springframework.core.task.TaskExecutor] but was actually of type [org.springframework.cloud.sleuth.instrument.async.LazyTraceExecutor]
Here is the pom.xml file with the two dependencies
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Camden.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth</artifactId>
<version>1.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-core</artifactId>
<version>LATEST</version>
<dependency>
How should I let the spring application context know which type specifically it has to load?Since both the classes are using the same executor from java util package.
java.util.concurrent.Executor
As presented in the comments it got fixed in the 1.0.12 and 1.1.1 and 1.2.0