From f4f904bb6e7b0f0ddca51158f80d9da2ce1357de Mon Sep 17 00:00:00 2001 From: Janne Valkealahti Date: Fri, 15 Dec 2017 08:54:32 +0000 Subject: [PATCH] Find correct super type generics for configurer adapter - Naively with StateMachineConfigurerAdapter or EnumStateMachineConfigurerAdapter only immediate super type were checked to find user level generics to instruct IOC for proper resolvable types. This worked with almost all cases except if user created new base type out from StateMachineConfigurerAdapter and bean id didn't match what what was trying to get autowired if multiple adapters were in use. - Correctly find resolvable type as StateMachineConfigurerAdapter in ResolvableType which finds an exact correct type to get generics. - Fixes #454 --- .../StateMachineConfiguration.java | 4 +- .../StateMachineFactoryConfiguration.java | 4 +- .../config/MachineTypedTests.java | 148 ++++++++++++++++++ 3 files changed, 152 insertions(+), 4 deletions(-) diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configuration/StateMachineConfiguration.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configuration/StateMachineConfiguration.java index 8e8396b9..a88e17b9 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configuration/StateMachineConfiguration.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configuration/StateMachineConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2016 the original author or authors. + * Copyright 2015-2017 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. @@ -121,7 +121,7 @@ public class StateMachineConfiguration extends private ResolvableType resolveFactoryObjectType(Class enableStateMachineEnclosingClass) { ResolvableType type = null; try { - Class[] generics = ResolvableType.forClass(enableStateMachineEnclosingClass).getSuperType().resolveGenerics(); + Class[] generics = ResolvableType.forClass(enableStateMachineEnclosingClass).as(StateMachineConfigurerAdapter.class).resolveGenerics(); if (generics != null && generics.length == 2) { type = ResolvableType.forClassWithGenerics(StateMachine.class, generics); } diff --git a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configuration/StateMachineFactoryConfiguration.java b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configuration/StateMachineFactoryConfiguration.java index f3cb0953..2c3be23c 100644 --- a/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configuration/StateMachineFactoryConfiguration.java +++ b/spring-statemachine-core/src/main/java/org/springframework/statemachine/config/configuration/StateMachineFactoryConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2016 the original author or authors. + * Copyright 2015-2017 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. @@ -96,7 +96,7 @@ public class StateMachineFactoryConfiguration extends private ResolvableType resolveFactoryObjectType(Class enableStateMachineEnclosingClass) { ResolvableType type = null; try { - Class[] generics = ResolvableType.forClass(enableStateMachineEnclosingClass).getSuperType().resolveGenerics(); + Class[] generics = ResolvableType.forClass(enableStateMachineEnclosingClass).as(StateMachineConfigurerAdapter.class).resolveGenerics(); if (generics != null && generics.length == 2) { type = ResolvableType.forClassWithGenerics(StateMachineFactory.class, generics); } diff --git a/spring-statemachine-core/src/test/java/org/springframework/statemachine/config/MachineTypedTests.java b/spring-statemachine-core/src/test/java/org/springframework/statemachine/config/MachineTypedTests.java index 9d679488..857840e4 100644 --- a/spring-statemachine-core/src/test/java/org/springframework/statemachine/config/MachineTypedTests.java +++ b/spring-statemachine-core/src/test/java/org/springframework/statemachine/config/MachineTypedTests.java @@ -81,6 +81,28 @@ public class MachineTypedTests extends AbstractStateMachineTests { assertThat(myBean4.someMachineFactory1, not(sameInstance(myBean4.someMachineFactory2))); } + @Test + public void testAutowireMachineFactoryByNewBaseTypeNameNotMatches() { + context.register(Config5.class, Config6.class, MyBean5Config.class); + context.refresh(); + + MyBean5 myBean5 = context.getBean(MyBean5.class); + assertThat(myBean5.someMachineFactory3, notNullValue()); + assertThat(myBean5.someMachineFactory4, notNullValue()); + assertThat(myBean5.someMachineFactory3, not(sameInstance(myBean5.someMachineFactory4))); + } + + @Test + public void testAutowireMachineByNewBaseTypeNameNotMatches() { + context.register(Config7.class, Config8.class, MyBean6Config.class); + context.refresh(); + + MyBean6 myBean6 = context.getBean(MyBean6.class); + assertThat(myBean6.someMachine3, notNullValue()); + assertThat(myBean6.someMachine4, notNullValue()); + assertThat(myBean6.someMachine3, not(sameInstance(myBean6.someMachine4))); + } + @Configuration public static class MyBean1Config { @@ -117,6 +139,24 @@ public class MachineTypedTests extends AbstractStateMachineTests { } } + @Configuration + public static class MyBean5Config { + + @Bean + public MyBean5 myBean5() { + return new MyBean5(); + } + } + + @Configuration + public static class MyBean6Config { + + @Bean + public MyBean6 myBean6() { + return new MyBean6(); + } + } + public static class MyBean1 { @Autowired @@ -153,6 +193,24 @@ public class MachineTypedTests extends AbstractStateMachineTests { StateMachineFactory someMachineFactory2; } + public static class MyBean5 { + + @Autowired + StateMachineFactory someMachineFactory3; + + @Autowired + StateMachineFactory someMachineFactory4; + } + + public static class MyBean6 { + + @Autowired + StateMachine someMachine3; + + @Autowired + StateMachine someMachine4; + } + @Configuration @EnableStateMachine(name = "machine1") public static class Config1 extends EnumStateMachineConfigurerAdapter { @@ -237,6 +295,96 @@ public class MachineTypedTests extends AbstractStateMachineTests { } } + @Configuration + @EnableStateMachineFactory(name = "machinefactory3") + public static class Config5 extends MyNewBaseAdapter1 { + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial(MyTestStates1.S1) + .state(MyTestStates1.S2); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source(MyTestStates1.S1).target(MyTestStates1.S2) + .event(MyTestEvents1.E1); + } + } + + @Configuration + @EnableStateMachineFactory(name = "machinefactory4") + public static class Config6 extends MyNewBaseAdapter2 { + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial(MyTestStates2.S1) + .state(MyTestStates2.S2); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source(MyTestStates2.S1).target(MyTestStates2.S2) + .event(MyTestEvents2.E1); + } + } + + @Configuration + @EnableStateMachine(name = "machine3") + public static class Config7 extends MyNewBaseAdapter1 { + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial(MyTestStates1.S1) + .state(MyTestStates1.S2); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source(MyTestStates1.S1).target(MyTestStates1.S2) + .event(MyTestEvents1.E1); + } + } + + @Configuration + @EnableStateMachine(name = "machine4") + public static class Config8 extends MyNewBaseAdapter2 { + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states + .withStates() + .initial(MyTestStates2.S1) + .state(MyTestStates2.S2); + } + + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + transitions + .withExternal() + .source(MyTestStates2.S1).target(MyTestStates2.S2) + .event(MyTestEvents2.E1); + } + } + + public static class MyNewBaseAdapter1 extends EnumStateMachineConfigurerAdapter { + } + + public static class MyNewBaseAdapter2 extends EnumStateMachineConfigurerAdapter { + } + public enum MyTestStates1 { S1, S2; }