WorkflowDefinitionScanner { public Map<String, WorkflowStateMethod> getStateMethods(Class<?> definition) { final Map<String, WorkflowStateMethod> methods = new LinkedHashMap<>(); doWithMethods(definition, method -> { List<StateParameter> params = new ArrayList<>(); Type[] genericParameterTypes = method.getGenericParameterTypes(); Class<?>[] parameterTypes = method.getParameterTypes(); Annotation[][] parameterAnnotations = method.getParameterAnnotations(); for (int i = 1; i < genericParameterTypes.length; ++i) { for (Annotation a : parameterAnnotations[i]) { if (StateVar.class.equals(a.annotationType())) { StateVar stateInfo = (StateVar) a; Type type = genericParameterTypes[i]; Class<?> clazz = parameterTypes[i]; boolean mutable = false; boolean readOnly = isReadOnly(type); if (Mutable.class.isAssignableFrom(clazz)) { ParameterizedType pType = (ParameterizedType) type; type = pType.getActualTypeArguments()[0]; readOnly = false; mutable = true; } params.add(new StateParameter(stateInfo.value(), type, defaultValue(stateInfo, clazz), readOnly || stateInfo.readOnly(), mutable)); break; } } } if (params.size() != genericParameterTypes.length - 1) { throw new IllegalStateException( "Not all parameter names could be resolved for " + method + ". Maybe missing @StateVar annotation?"); } if (methods.containsKey(method.getName())) { throw new IllegalStateException("Method " + method + " was overloaded. Overloading state methods is not allowed."); } methods.put(method.getName(), new WorkflowStateMethod(method, params.toArray(new StateParameter[params.size()]))); }, new WorkflowTransitionMethod()); return methods; }  Map<String, WorkflowStateMethod> getStateMethods(Class<?> definition);  }
@Test public void onlyPublicMethodsWithCorrectSignatureAreReturned() { Map<String, WorkflowStateMethod> methods = scanner.getStateMethods(NonStateMethodsWorkflow.class); assertThat(methods.keySet(), hasItemsOf(asList("start", "end", "doesNotReturnNextState"))); assertThat(methods.keySet().size(), is(3)); }
@Test public void readOnlyStateVarFlagSetsFlagInStateParameter() { Map<String, WorkflowStateMethod> methods = scanner.getStateMethods(ReadOnlyStateVarWorkflow.class); assertThat(methods.keySet(), hasItemsOf(asList("start", "end"))); assertThat(methods.get("end").params[0], stateParam("paramKey", String.class, true, false)); }
@Test public void overloadingStateMethodShouldThrowException() { IllegalStateException thrown = assertThrows(IllegalStateException.class, () -> scanner.getStateMethods(OverloadedStateMethodWorkflow.class)); assertThat(thrown.getMessage(), containsString("OverloadedStateMethodWorkflow.end")); assertThat(thrown.getMessage(), containsString("Overloading state methods is not allowed.")); }
@Test public void missingStateVarAnnotationShouldThrowException() { IllegalStateException thrown = assertThrows(IllegalStateException.class, () -> scanner.getStateMethods(MissingStateVarWorkflow.class)); assertThat(thrown.getMessage(), containsString("MissingStateVarWorkflow.end")); assertThat(thrown.getMessage(), containsString("missing @StateVar annotation")); }
@Test public void unknownAnnotationOnParameterIsIgnored() { Map<String, WorkflowStateMethod> methods = scanner.getStateMethods(UnknownAnnotationWorkflow.class); assertThat(methods.keySet(), hasItemsOf(asList("start", "end"))); assertThat(methods.get("end").params[0], stateParam("paramKey", String.class, true, false)); }
@Test public void mutableStateParamSetsMutableFlag() { Map<String, WorkflowStateMethod> methods = scanner.getStateMethods(MutableParamWorkflow.class); assertThat(methods.keySet(), hasItemsOf(asList("start", "end"))); assertThat(methods.get("end").params[0], stateParam("paramKey", String.class, false, true)); }
@Test public void instantiateNullFlagCausesParameterObjectToInstantiate() { Map<String, WorkflowStateMethod> methods = scanner.getStateMethods(InitiateParameterWorkflow.class); assertThat(methods.keySet(), hasItemsOf(asList("start", "end"))); assertNotNull(methods.get("end").params[0].nullValue); assertThat(methods.get("end").params[0], stateParam("paramKey", ParamObj.class, false, false)); StateParameter longParam = methods.get("end").params[1]; assertThat(longParam, stateParam("paramKey2", long.class, true, false)); assertEquals(0L, longParam.nullValue); }
@Test public void instantiateWithBoolean() { Map<String, WorkflowStateMethod> methods = scanner.getStateMethods(BooleanObjectWorkflow.class); assertThat(methods.keySet(), hasItemsOf(asList("start", "end"))); assertNotNull(methods.get("end").params[0].nullValue); assertThat(methods.get("end").params[0], stateParam("paramPrimitive", boolean.class, true, false)); StateParameter param = methods.get("end").params[1]; assertThat(param, stateParam("paramBoxed", Boolean.class, true, false)); assertEquals(Boolean.FALSE, param.nullValue); }
@Test public void instantiateWithByte() { Map<String, WorkflowStateMethod> methods = scanner.getStateMethods(ByteObjectWorkflow.class); assertThat(methods.keySet(), hasItemsOf(asList("start", "end"))); assertNotNull(methods.get("end").params[0].nullValue); assertThat(methods.get("end").params[0], stateParam("paramPrimitive", byte.class, true, false)); StateParameter param = methods.get("end").params[1]; assertThat(param, stateParam("paramBoxed", Byte.class, true, false)); assertEquals((byte)0, param.nullValue); }
@Test public void instantiateWithCharacter() { Map<String, WorkflowStateMethod> methods = scanner.getStateMethods(CharacterObjectWorkflow.class); assertThat(methods.keySet(), hasItemsOf(asList("start", "end"))); assertNotNull(methods.get("end").params[0].nullValue); assertThat(methods.get("end").params[0], stateParam("paramPrimitive", char.class, true, false)); StateParameter param = methods.get("end").params[1]; assertThat(param, stateParam("paramBoxed", Character.class, true, false)); assertEquals((char)0, param.nullValue); }
@Test public void instantiateWithShort() { Map<String, WorkflowStateMethod> methods = scanner.getStateMethods(ShortObjectWorkflow.class); assertThat(methods.keySet(), hasItemsOf(asList("start", "end"))); assertNotNull(methods.get("end").params[0].nullValue); assertThat(methods.get("end").params[0], stateParam("paramPrimitive", short.class, true, false)); StateParameter param = methods.get("end").params[1]; assertThat(param, stateParam("paramBoxed", Short.class, true, false)); assertEquals(Short.valueOf((short)0), param.nullValue); }
@Test public void instantiateWithInteger() { Map<String, WorkflowStateMethod> methods = scanner.getStateMethods(IntegerObjectWorkflow.class); assertThat(methods.keySet(), hasItemsOf(asList("start", "end"))); assertNotNull(methods.get("end").params[0].nullValue); assertThat(methods.get("end").params[0], stateParam("paramPrimitive", int.class, true, false)); StateParameter param = methods.get("end").params[1]; assertThat(param, stateParam("paramBoxed", Integer.class, true, false)); assertEquals(Integer.valueOf(0), param.nullValue); }
@Test public void instantiateWithLong() { Map<String, WorkflowStateMethod> methods = scanner.getStateMethods(LongObjectWorkflow.class); assertThat(methods.keySet(), hasItemsOf(asList("start", "end"))); assertNotNull(methods.get("end").params[0].nullValue); assertThat(methods.get("end").params[0], stateParam("paramPrimitive", long.class, true, false)); StateParameter param = methods.get("end").params[1]; assertThat(param, stateParam("paramBoxed", Long.class, true, false)); assertEquals(Long.valueOf(0), param.nullValue); }
@Test public void instantiateWithFloat() { Map<String, WorkflowStateMethod> methods = scanner.getStateMethods(FloatObjectWorkflow.class); assertThat(methods.keySet(), hasItemsOf(asList("start", "end"))); assertNotNull(methods.get("end").params[0].nullValue); assertThat(methods.get("end").params[0], stateParam("paramPrimitive", float.class, true, false)); StateParameter param = methods.get("end").params[1]; assertThat(param, stateParam("paramBoxed", Float.class, true, false)); assertEquals(Float.valueOf(0), param.nullValue); }
@Test public void instantiateWithDouble() { Map<String, WorkflowStateMethod> methods = scanner.getStateMethods(DoubleObjectWorkflow.class); assertThat(methods.keySet(), hasItemsOf(asList("start", "end"))); assertNotNull(methods.get("end").params[0].nullValue); assertThat(methods.get("end").params[0], stateParam("paramPrimitive", double.class, true, false)); StateParameter longParam = methods.get("end").params[1]; assertThat(longParam, stateParam("paramBoxed", Double.class, true, false)); assertEquals(Double.valueOf(0), longParam.nullValue); }