Fix NPE with missing configurer

- Throw BeanDefinitionStoreException in favor of NPE if
  @EnableStateMachine or @EnableStateMachineFactory is used
  without a configurer meaning user is missing proper config
  adapter like EnumStateMachineConfigurerAdapter.
- Polish StateMachineConfiguration and StateMachineFactoryConfiguration
  by removing wrong typed refs to Enum.
- Fixes #119
This commit is contained in:
Janne Valkealahti
2015-11-14 14:10:39 +00:00
parent 5b715d0492
commit 19af615698
3 changed files with 65 additions and 6 deletions

View File

@@ -19,6 +19,7 @@ import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
@@ -30,6 +31,7 @@ import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.ObjectStateMachineFactory;
import org.springframework.statemachine.config.StateMachineConfig;
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineConfigBuilder;
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfig;
import org.springframework.statemachine.config.builders.StateMachineStates;
@@ -38,8 +40,18 @@ import org.springframework.statemachine.config.common.annotation.AbstractImporti
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurer;
import org.springframework.util.ClassUtils;
/**
* {@link Configuration} which gets imported from {@link EnableStateMachine} and registers
* a {@link StateMachine} build from a {@link StateMachineConfigurerAdapter} via
* a {@link BeanDefinition}.
*
* @author Janne Valkealahti
*
* @param <S> the type of state
* @param <E> the type of event
*/
@Configuration
public class StateMachineConfiguration<S extends Enum<S>, E extends Enum<E>> extends
public class StateMachineConfiguration<S, E> extends
AbstractImportingAnnotationConfiguration<StateMachineConfigBuilder<S, E>, StateMachineConfig<S, E>> {
private final StateMachineConfigBuilder<S, E> builder = new StateMachineConfigBuilder<S, E>();
@@ -67,7 +79,7 @@ public class StateMachineConfiguration<S extends Enum<S>, E extends Enum<E>> ext
return types;
}
private static class StateMachineDelegatingFactoryBean<S extends Enum<S>, E extends Enum<E>>
private static class StateMachineDelegatingFactoryBean<S, E>
extends BeanDelegatingFactoryBean<StateMachine<S, E>,StateMachineConfigBuilder<S, E>,StateMachineConfig<S, E>>
implements SmartLifecycle, BeanNameAware {
@@ -82,7 +94,7 @@ public class StateMachineConfiguration<S extends Enum<S>, E extends Enum<E>> ext
this.clazzName = clazzName;
this.contextEvents = contextEvents;
}
@Override
public void setBeanName(String name) {
this.beanName = name;
@@ -90,6 +102,12 @@ public class StateMachineConfiguration<S extends Enum<S>, E extends Enum<E>> ext
@Override
public void afterPropertiesSet() throws Exception {
// do not continue without configurers, it would not work
if (getConfigurers() == null || getConfigurers().size() == 0) {
throw new BeanDefinitionStoreException(
"Cannot configure state machine due to missing configurers. Did you remember to use " +
"@EnableStateMachine with a StateMachineConfigurerAdapter.");
}
for (AnnotationConfigurer<StateMachineConfig<S, E>, StateMachineConfigBuilder<S, E>> configurer : getConfigurers()) {
Class<?> clazz = configurer.getClass();
if (ClassUtils.getUserClass(clazz).getName().equals(clazzName)) {

View File

@@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.FactoryBean;
@@ -33,6 +34,7 @@ import org.springframework.core.type.AnnotationMetadata;
import org.springframework.statemachine.config.EnableStateMachineFactory;
import org.springframework.statemachine.config.ObjectStateMachineFactory;
import org.springframework.statemachine.config.StateMachineConfig;
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
import org.springframework.statemachine.config.StateMachineFactory;
import org.springframework.statemachine.config.builders.StateMachineConfigBuilder;
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfig;
@@ -42,8 +44,18 @@ import org.springframework.statemachine.config.common.annotation.AbstractImporti
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurer;
import org.springframework.util.ClassUtils;
/**
* {@link Configuration} which gets imported from {@link EnableStateMachineFactory} and registers
* a {@link StateMachineFactory} build from a {@link StateMachineConfigurerAdapter} via
* a {@link BeanDefinition}.
*
* @author Janne Valkealahti
*
* @param <S> the type of state
* @param <E> the type of event
*/
@Configuration
public class StateMachineFactoryConfiguration<S extends Enum<S>, E extends Enum<E>> extends
public class StateMachineFactoryConfiguration<S, E> extends
AbstractImportingAnnotationConfiguration<StateMachineConfigBuilder<S, E>, StateMachineConfig<S, E>> {
private final StateMachineConfigBuilder<S, E> builder = new StateMachineConfigBuilder<S, E>();
@@ -70,7 +82,7 @@ public class StateMachineFactoryConfiguration<S extends Enum<S>, E extends Enum<
return types;
}
private static class StateMachineFactoryDelegatingFactoryBean<S extends Enum<S>, E extends Enum<E>> implements
private static class StateMachineFactoryDelegatingFactoryBean<S, E> implements
FactoryBean<StateMachineFactory<S, E>>, BeanFactoryAware, InitializingBean {
private final StateMachineConfigBuilder<S, E> builder;
@@ -104,6 +116,12 @@ public class StateMachineFactoryConfiguration<S extends Enum<S>, E extends Enum<
@Override
public void afterPropertiesSet() throws Exception {
// do not continue without configurers, it would not work
if (configurers == null || configurers.size() == 0) {
throw new BeanDefinitionStoreException(
"Cannot configure state machine due to missing configurers. Did you remember to use " +
"@EnableStateMachineFactory with a StateMachineConfigurerAdapter.");
}
for (AnnotationConfigurer<StateMachineConfig<S, E>, StateMachineConfigBuilder<S, E>> configurer : configurers) {
Class<?> clazz = configurer.getClass();
if (ClassUtils.getUserClass(clazz).getName().equals(clazzName)) {

View File

@@ -15,8 +15,8 @@
*/
package org.springframework.statemachine.config;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@@ -27,6 +27,7 @@ import java.util.EnumSet;
import java.util.List;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -149,6 +150,18 @@ public class ConfigurationTests extends AbstractStateMachineTests {
assertThat(((List<?>)o3).size(), is(2));
}
@Test(expected = BeanCreationException.class)
public void testEnableStateMachineNoAdapter() {
context.register(Config12.class);
context.refresh();
}
@Test(expected = BeanCreationException.class)
public void testEnableStateMachineFactoryNoAdapter() {
context.register(Config13.class);
context.refresh();
}
@Configuration
@EnableStateMachine
public static class Config1 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {
@@ -534,4 +547,14 @@ public class ConfigurationTests extends AbstractStateMachineTests {
}
@Configuration
@EnableStateMachine
public static class Config12 {
}
@Configuration
@EnableStateMachineFactory
public static class Config13 {
}
}