diff --git a/src/main/java/com/microsoft/azure/functions/worker/binding/BindingDataStore.java b/src/main/java/com/microsoft/azure/functions/worker/binding/BindingDataStore.java index 3ab1637b..a9d5b62e 100644 --- a/src/main/java/com/microsoft/azure/functions/worker/binding/BindingDataStore.java +++ b/src/main/java/com/microsoft/azure/functions/worker/binding/BindingDataStore.java @@ -119,11 +119,11 @@ public Optional getDataTargetTypedValue(String name) throws Exception }); } - public Optional getOrAddDataTarget(UUID outputId, String name, Type target, boolean hasImplicitOutput) { + public Optional getOrAddDataTarget(UUID outputId, String name, Type target, boolean ignoreDefinition) { DataTarget output = null; if (this.isDataTargetValid(name, target)) { output = this.getTarget(outputId).get(name); - if (output == null && (this.isDefinitionOutput(name) || hasImplicitOutput)) { + if (output == null && (this.isDefinitionOutput(name) || ignoreDefinition)) { this.getTarget(outputId).put(name, output = rpcDataTargetFromType(target)); } } diff --git a/src/main/java/com/microsoft/azure/functions/worker/broker/MethodBindInfo.java b/src/main/java/com/microsoft/azure/functions/worker/broker/MethodBindInfo.java index ba8258f0..32ec92b1 100644 --- a/src/main/java/com/microsoft/azure/functions/worker/broker/MethodBindInfo.java +++ b/src/main/java/com/microsoft/azure/functions/worker/broker/MethodBindInfo.java @@ -28,9 +28,22 @@ public List getParams() { return params; } + public boolean hasEffectiveReturnType(){ + boolean nonVoidReturn = this.hasNonVoidReturnType(); + // For function annotated with @HasImplicitOutput, we should allow it to send back data even function's return type is void + // Reference to https://github.com/microsoft/durabletask-java/issues/126 + boolean implicitOutput = this.hasImplicitOutput(); + return nonVoidReturn || implicitOutput; + } + public boolean hasImplicitOutput() { return hasImplicitOutput; } + + public boolean hasNonVoidReturnType() { + Class returnType = this.getMethod().getReturnType(); + return !returnType.equals(void.class) && !returnType.equals(Void.class); + } } diff --git a/src/main/java/com/microsoft/azure/functions/worker/broker/ParameterResolver.java b/src/main/java/com/microsoft/azure/functions/worker/broker/ParameterResolver.java index e4b605b0..884ae85b 100644 --- a/src/main/java/com/microsoft/azure/functions/worker/broker/ParameterResolver.java +++ b/src/main/java/com/microsoft/azure/functions/worker/broker/ParameterResolver.java @@ -52,13 +52,11 @@ else if (paramName == null && !paramBindingNameAnnotation.isEmpty()) { BindingData actualArg = argument.orElseThrow(WrongMethodTypeException::new); invokeInfo.appendArgument(actualArg.getValue()); } - // For function annotated with @HasImplicitOutput, we should allow it to send back data even function's return type is void - // Reference to https://github.com/microsoft/durabletask-java/issues/126 - if (!method.getMethod().getReturnType().equals(void.class) - && !method.getMethod().getReturnType().equals(Void.class) - || method.hasImplicitOutput()) { - dataStore.getOrAddDataTarget(invokeInfo.getOutputsId(), BindingDataStore.RETURN_NAME, method.getMethod().getReturnType(), method.hasImplicitOutput()); + + if (method.hasEffectiveReturnType()){ + dataStore.getOrAddDataTarget(invokeInfo.getOutputsId(), BindingDataStore.RETURN_NAME, method.getMethod().getReturnType(), true); } + return invokeInfo; } catch (Exception ex) { ExceptionUtils.rethrow(ex); diff --git a/src/test/java/com/microsoft/azure/functions/worker/broker/ParameterResolverTest.java b/src/test/java/com/microsoft/azure/functions/worker/broker/ParameterResolverTest.java index 385edade..7e9b3e3e 100644 --- a/src/test/java/com/microsoft/azure/functions/worker/broker/ParameterResolverTest.java +++ b/src/test/java/com/microsoft/azure/functions/worker/broker/ParameterResolverTest.java @@ -56,7 +56,9 @@ public T getInstance(Class functionClass) throws Exception { @Test public void testResolveArgumentsHasImplicitOutputTrue() throws Exception { - Method testMethod = this.getClass().getDeclaredMethod("testMethod"); + Method testMethod = this.getClass().getDeclaredMethod("testMethodVoid"); + when(methodBindInfo.hasNonVoidReturnType()).thenCallRealMethod(); + when(methodBindInfo.hasEffectiveReturnType()).thenCallRealMethod(); when(methodBindInfo.hasImplicitOutput()).thenReturn(true); when(methodBindInfo.getMethod()).thenReturn(testMethod); when(methodBindInfo.getParams()).thenReturn(new ArrayList<>()); @@ -66,7 +68,9 @@ public void testResolveArgumentsHasImplicitOutputTrue() throws Exception { @Test public void testResolveArgumentsHasImplicitOutputFalse() throws Exception { - Method testMethod = this.getClass().getDeclaredMethod("testMethod"); + Method testMethod = this.getClass().getDeclaredMethod("testMethodVoid"); + when(methodBindInfo.hasNonVoidReturnType()).thenCallRealMethod(); + when(methodBindInfo.hasEffectiveReturnType()).thenCallRealMethod(); when(methodBindInfo.hasImplicitOutput()).thenReturn(false); when(methodBindInfo.getMethod()).thenReturn(testMethod); when(methodBindInfo.getParams()).thenReturn(new ArrayList<>()); @@ -74,5 +78,30 @@ public void testResolveArgumentsHasImplicitOutputFalse() throws Exception { assertFalse(executionContextDataSource.getDataStore().getDataTargetTypedValue(BindingDataStore.RETURN_NAME).isPresent()); } - public void testMethod() {} + @Test + public void testResolveArgumentsNonVoidReturnTypeTrue() throws Exception { + Method testMethod = this.getClass().getDeclaredMethod("testMethodNonVoid"); + when(methodBindInfo.getMethod()).thenReturn(testMethod); + when(methodBindInfo.getParams()).thenReturn(new ArrayList<>()); + when(methodBindInfo.hasNonVoidReturnType()).thenCallRealMethod(); // Ensures real logic is executed + when(methodBindInfo.hasImplicitOutput()).thenReturn(false); + when(methodBindInfo.hasEffectiveReturnType()).thenCallRealMethod(); + ParameterResolver.resolveArguments(executionContextDataSource); + assertTrue(executionContextDataSource.getDataStore().getDataTargetTypedValue(BindingDataStore.RETURN_NAME).isPresent()); + } + + @Test + public void testResolveArgumentsNonVoidReturnTypeFalse() throws Exception { + Method testMethod = this.getClass().getDeclaredMethod("testMethodVoid"); + when(methodBindInfo.getMethod()).thenReturn(testMethod); + when(methodBindInfo.getParams()).thenReturn(new ArrayList<>()); + when(methodBindInfo.hasNonVoidReturnType()).thenCallRealMethod(); // Ensures real logic is executed + when(methodBindInfo.hasImplicitOutput()).thenReturn(false); + when(methodBindInfo.hasEffectiveReturnType()).thenCallRealMethod(); + ParameterResolver.resolveArguments(executionContextDataSource); + assertFalse(executionContextDataSource.getDataStore().getDataTargetTypedValue(BindingDataStore.RETURN_NAME).isPresent()); + } + + public void testMethodVoid() {} + public String testMethodNonVoid() { return "test"; } }