Repository: Azure/azure-functions-java-worker
Pull request #87 (2018-04-19 01:38:58)

New preview introduces new annotations
It also includes:
* New testing framework
* New Javadoc framework
* BUG fixes


Patch:
diff --git a/README.md b/README.md
index 353f463..8f00ecf 100644
--- a/README.md
+++ b/README.md
@@ -33,47 +33,19 @@ public class MyClass {
 
 ### Including 3rd Party Libraries
 
-Azure Functions supports the following for referencing dependencies:
+Azure Functions supports the use of 3rd party libraries. This is achieved by extending your build script to copy all dependencies to a lib folder in the function's root directory, which will then be deployed as part of your functions application. All dependencies that are placed in the `lib` directory will be added to the system class loader at runtime. 
 
-1. Creating a single JAR file.
-2. Copying all dependencies to a lib folder in the function's root directory
-
-#### 1. Single JAR
-only accept one single JAR file. Therefore you are required to package all your dependencies into one single JAR. A simple approach is to add the following plugin into your `pom.xml`:
+Adding the following to your Maven `pom.xml` will copy all your dependencies to the Function App's `lib` directory. There are two changes required - configuring a property, and configuring the `maven-dependency-plugin`. 
 
+In the properties section of your `pom.xml` file, you need to set the `functionLib` property as such:
 ```xml
-<plugin>
-  <artifactId>maven-shade-plugin</artifactId>
-  <version>3.1.0</version>
-  <executions>
-    <execution>
-      <phase>package</phase>
-      <goals>
-        <goal>shade</goal>
-      </goals>
-      <configuration>
-        <filters>
-          <filter>
-            <artifact>*:*</artifact>
-            <excludes>
-              <exclude>META-INF/*.SF</exclude>
-              <exclude>META-INF/*.DSA</exclude>
-              <exclude>META-INF/*.RSA</exclude>
-            </excludes>
-          </filter>
-        </filters>
-      </configuration>
-    </execution>
-  </executions>
-</plugin>
+<properties>
+    <functionLib>${project.build.directory}/azure-functions/${functionAppName}/lib</functionLib>
+</properties>
 ```
 
-Sometimes you also need to care about the static constructors used in some libraries (for example, database drivers). You need to call [`Class.forName()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#forName-java.lang.String-) method to invoke the corresponding static constructor (for example `Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");`).
-
-#### 2. Dependencies in the lib/ folder
-All dependencies that are placed in the `lib` directory will be added to the system class loader at runtime. Add the following plugin definition to your `pom.xml`:
-
-```
+In the plugins section of your `pom.xml` file, you need to configure the `maven-dependency-plugin` as such:
+```xml
 <plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-dependency-plugin</artifactId>
@@ -95,7 +67,8 @@ All dependencies that are placed in the `lib` directory will be added to the sys
   </executions>
 </plugin>
 ```
-This will copy all your dependencies to the Function App's `lib` directory. Be sure to package and deploy the lib as part of the Function App.
+
+Finally, be sure to package and deploy the lib as part of the Function App.
 
 ## General Data Types
 
diff --git a/azure-functions-java-core/pom.xml b/azure-functions-java-core/pom.xml
index 027f6bc..1203393 100644
--- a/azure-functions-java-core/pom.xml
+++ b/azure-functions-java-core/pom.xml
@@ -2,7 +2,7 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.microsoft.azure</groupId>
   <artifactId>azure-functions-java-core</artifactId>
-  <version>1.0.0-beta-2</version>
+  <version>1.0.0-beta-3</version>
   <packaging>jar</packaging>
 
   <name>Microsoft Azure Functions Java Core Types</name>
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/ExecutionContext.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/ExecutionContext.java
index 29e3049..1dae4b4 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/ExecutionContext.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/ExecutionContext.java
@@ -2,8 +2,30 @@ package com.microsoft.azure.serverless.functions;
 
 import java.util.logging.Logger;
 
+/**
+ * The execution context enables interaction with the Azure Functions execution environment.
+ *
+ * @since 1.0.0
+ */
 public interface ExecutionContext {
+    /**
+     * Returns the built-in logger, which is integrated with the logging functionality provided in the Azure Functions
+     * portal, as well as in Azure Application Insights.
+     *
+     * @return A Java logger that will see output directed to Azure Portal, as well as any other configured output
+     *      locations.
+     */
     Logger getLogger();
+
+    /**
+     * Returns the invocation ID for the function call.
+     * @return the invocation ID for the function call.
+     */
     String getInvocationId();
+
+    /**
+     * Returns the function name.
+     * @return the function name.
+     */
     String getFunctionName();
 }
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/HttpRequestMessage.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/HttpRequestMessage.java
index 9d689b1..4f1b797 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/HttpRequestMessage.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/HttpRequestMessage.java
@@ -3,12 +3,65 @@ package com.microsoft.azure.serverless.functions;
 import java.net.URI;
 import java.util.Map;
 
+/**
+ * An HttpRequestMessage instance is provided to Azure functions that use
+ * {@link com.microsoft.azure.serverless.functions.annotation.HttpTrigger HTTP Triggers}. For an example of how to use
+ * the http functionality of Azure Functions, refer to the example in the
+ * {@link com.microsoft.azure.serverless.functions.annotation.HttpTrigger}
+ *
+ * @see com.microsoft.azure.serverless.functions.annotation.HttpTrigger
+ * @see HttpResponseMessage
+ * @param <T> The type of the body content that is expected to be received as part of this HTTP request.
+ * @since 1.0.0
+ */
 public interface HttpRequestMessage<T> {
+    /**
+     * Returns the URI that was called that resulted in this HTTP request being submitted.
+     * @return the URI that was called that resulted in this HTTP request being submitted.
+     */
     URI getUri();
+
+    /**
+     * Returns the HTTP method name, such as "GET" and "POST".
+     * @return the HTTP method name, such as "GET" and "POST".
+     */
     String getMethod();
+
+    /**
+     * Returns a map of headers that were contained within this HTTP request.
+     * @return a map of headers that were contained within this HTTP request.
+     */
     Map<String, String> getHeaders();
+
+    /**
+     * Returns a map of query parameters that were included with this HTTP request.
+     * @return a map of query parameters that were included with this HTTP request.
+     */
     Map<String, String> getQueryParameters();
+
+    /**
+     * Returns any body content that was included with this HTTP request.
+     * @return any body content that was included with this HTTP request.
+     */
     T getBody();
 
+    /**
+     * Generates a {@link HttpResponseMessage} instance containing the given HTTP status code and no response body.
+     * Additional headers may be added by calling appropriate methods on {@link HttpResponseMessage}.
+     *
+     * @param status The HTTP status code to return to the caller of the function.
+     * @return An {@link HttpResponseMessage} instance containing the provided status and empty body.
+     */
+    HttpResponseMessage<Object> createResponse(int status);
+
+    /**
+     * Generates a {@link HttpResponseMessage} instance containing the given HTTP status code and response body.
+     * Additional headers may be added by calling appropriate methods on {@link HttpResponseMessage}.
+     *
+     * @param status The HTTP status code to return to the caller of the function.
+     * @param body The body content to return to the caller of the function.
+     * @param <R> The type of the body, as determined by the return type specified on the function itself.
+     * @return An {@link HttpResponseMessage} instance containing the provided status and body content.
+     */
     <R> HttpResponseMessage<R> createResponse(int status, R body);
 }
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/HttpResponseMessage.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/HttpResponseMessage.java
index c852eb9..b4794d8 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/HttpResponseMessage.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/HttpResponseMessage.java
@@ -1,10 +1,51 @@
 package com.microsoft.azure.serverless.functions;
 
+/**
+ * An HttpResponseMessage instance is returned by Azure Functions methods that are triggered by an
+ * {@link com.microsoft.azure.serverless.functions.annotation.HttpTrigger}.
+ *
+ * @see com.microsoft.azure.serverless.functions.annotation.HttpTrigger
+ * @see HttpRequestMessage
+ * @param <T> The type of the body, as determined by the return type specified on the function itself.
+ * @since 1.0.0
+ */
 public interface HttpResponseMessage<T> {
+
+    /**
+     * Returns the status code set on the HttpResponseMessage instance.
+     * @return the status code set on the HttpResponseMessage instance.
+     */
     int getStatus();
+
+    /**
+     * Sets the status code on the HttpResponseMessage instance.
+     * @param status An HTTP status code representing the outcome of the HTTP request.
+     */
     void setStatus(int status);
+
+    /**
+     * Adds a (key,value) header to the response.
+     * @param key The key of the header value.
+     * @param value The value of the header value.
+     */
     void addHeader(String key, String value);
+
+    /**
+     * Returns a header value for the given key.
+     * @param key The key for which the header value is sought.
+     * @return Returns the value if the key has previously been added, or null if it has not.
+     */
     String getHeader(String key);
+
+    /**
+     * Returns the body of the HTTP response.
+     * @return the body of the HTTP response.
+     */
     T getBody();
+
+    /**
+     * Sets the body of the HTTP response.
+     * @param body The body of the HTTP response
+     */
     void setBody(T body);
 }
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/OutputBinding.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/OutputBinding.java
index b65c5ee..caca1fa 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/OutputBinding.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/OutputBinding.java
@@ -1,5 +1,9 @@
 package com.microsoft.azure.serverless.functions;
 
+/**
+ *
+ * @since 1.0.0
+ */
 public interface OutputBinding<T> {
     T getValue();
     void setValue(T value);
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/AccessRights.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/AccessRights.java
index 9e0c50c..1ad2826 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/AccessRights.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/AccessRights.java
@@ -6,6 +6,10 @@
 
 package com.microsoft.azure.serverless.functions.annotation;
 
+/**
+ *
+ * @since 1.0.0
+ */
 public enum AccessRights {
     MANAGE,
     LISTEN
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ApiHubFileInput.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ApiHubFileInput.java
index 3016d3f..065c479 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ApiHubFileInput.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ApiHubFileInput.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.PARAMETER)
 public @interface ApiHubFileInput {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ApiHubFileOutput.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ApiHubFileOutput.java
index 217f274..2fa911d 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ApiHubFileOutput.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ApiHubFileOutput.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.METHOD})
 public @interface ApiHubFileOutput {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ApiHubFileTrigger.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ApiHubFileTrigger.java
index be1a03e..db6293b 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ApiHubFileTrigger.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ApiHubFileTrigger.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.PARAMETER)
 public @interface ApiHubFileTrigger {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/AuthorizationLevel.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/AuthorizationLevel.java
index b475568..de9ca28 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/AuthorizationLevel.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/AuthorizationLevel.java
@@ -6,6 +6,10 @@
 
 package com.microsoft.azure.serverless.functions.annotation;
 
+/**
+ *
+ * @since 1.0.0
+ */
 public enum AuthorizationLevel {
     ANONYMOUS,
     FUNCTION,
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/BindingName.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/BindingName.java
index 68fb70c..a8fc80e 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/BindingName.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/BindingName.java
@@ -5,6 +5,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Target(ElementType.PARAMETER)
 @Retention(RetentionPolicy.RUNTIME)
 public @interface BindingName {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/BlobInput.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/BlobInput.java
index 2df6c15..18af51b 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/BlobInput.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/BlobInput.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.PARAMETER)
 public @interface BlobInput {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/BlobOutput.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/BlobOutput.java
index dee51a1..0105ae8 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/BlobOutput.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/BlobOutput.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.METHOD})
 public @interface BlobOutput {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/BlobTrigger.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/BlobTrigger.java
index ae1b8a5..23355c2 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/BlobTrigger.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/BlobTrigger.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.PARAMETER)
 public @interface BlobTrigger {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/DocumentDBInput.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/CosmosDBInput.java
similarity index 86%
rename from azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/DocumentDBInput.java
rename to azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/CosmosDBInput.java
index f359f18..04b5660 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/DocumentDBInput.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/CosmosDBInput.java
@@ -11,9 +11,13 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.PARAMETER)
-public @interface DocumentDBInput {
+public @interface CosmosDBInput {
     String name();
 
     String dataType() default "";
@@ -26,5 +30,5 @@ public @interface DocumentDBInput {
 
     String sqlQuery() default "";
 
-    String connection();
+    String connectionStringSetting();
 }
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/DocumentDBOutput.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/CosmosDBOutput.java
similarity index 86%
rename from azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/DocumentDBOutput.java
rename to azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/CosmosDBOutput.java
index 971f130..2928baa 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/DocumentDBOutput.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/CosmosDBOutput.java
@@ -11,9 +11,13 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.METHOD})
-public @interface DocumentDBOutput {
+public @interface CosmosDBOutput {
     String name();
 
     String dataType() default "";
@@ -24,5 +28,5 @@ public @interface DocumentDBOutput {
 
     boolean createIfNotExists() default false;
 
-    String connection();
+    String connectionStringSetting();
 }
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/CosmosDBTrigger.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/CosmosDBTrigger.java
new file mode 100644
index 0000000..f85d507
--- /dev/null
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/CosmosDBTrigger.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.serverless.functions.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * @since 1.0.0
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface CosmosDBTrigger {
+    String name();
+
+    String dataType() default "";
+
+    String databaseName();
+
+    String collectionName();
+
+    String leaseCollectionName();
+
+    boolean createLeaseCollectionIfNotExists() default false;
+
+    String connectionStringSetting();
+}
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/EventGridTrigger.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/EventGridTrigger.java
new file mode 100644
index 0000000..e50baca
--- /dev/null
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/EventGridTrigger.java
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.serverless.functions.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface EventGridTrigger {
+    String name();
+
+    String dataType() default "";
+}
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/EventHubOutput.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/EventHubOutput.java
index 286e69d..40e5bf8 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/EventHubOutput.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/EventHubOutput.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.METHOD})
 public @interface EventHubOutput {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/EventHubTrigger.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/EventHubTrigger.java
index 63feb2b..c2481a7 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/EventHubTrigger.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/EventHubTrigger.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.PARAMETER)
 public @interface EventHubTrigger {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/FunctionName.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/FunctionName.java
index f7b53b8..4189a6c 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/FunctionName.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/FunctionName.java
@@ -11,8 +11,32 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ * <p>The {@code FunctionName} annotation is used to specify to the Azure Functions tooling what name is to be applied
+ * to the associated function when the function is deployed onto Azure. This becomes the endpoint (in the case of an
+ * {@link HttpTrigger http triggered} function, for example, but more generally it is what is shown to users in the
+ * Azure Portal, so a succinct and understandable function name is useful.</p>
+ *
+ * <p>An example of how the {@code FunctionName} annotation is shown in the code snippet below. Note that it is applied
+ * to the function that will be called by Azure, based on the specified trigger (in the code below it is a
+ * {@link HttpTrigger}).</p>
+ *
+ * <pre>
+ * {@literal @}FunctionName("redirect")
+ *  public HttpResponseMessage&lt;String&gt; redirectFunction(
+ *    {@literal @}HttpTrigger(name = "req",
+ *                            methods = {"get"}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage&lt;Optional&lt;String&gt;&gt; request) {
+ *     ....
+ *  }</pre>
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.METHOD)
 public @interface FunctionName {
+    /**
+     * The name of the function.
+     * @return The name of the function.
+     */
     String value();
 }
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/HttpOutput.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/HttpOutput.java
index 1852481..b89c7cd 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/HttpOutput.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/HttpOutput.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.METHOD})
 public @interface HttpOutput {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/HttpTrigger.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/HttpTrigger.java
index 4f6c580..8b705da 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/HttpTrigger.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/HttpTrigger.java
@@ -11,18 +11,141 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ * <p>The HttpTrigger annotation is applied to Azure functions that will be triggered by a call to the HTTP endpoint that
+ * the function is located at. The HttpTrigger annotation should be applied to a method parameter of one of the following
+ * types:</p>
+ *
+ * <ul>
+ *     <li>{@link com.microsoft.azure.serverless.functions.HttpRequestMessage HttpRequestMessage&lt;T&gt;}</li>
+ *     <li>Any native Java types such as int, String, byte[]</li>
+ *     <li>Nullable values using Optional&lt;T&gt;</li>
+ *     <li>Any POJO type</li>
+ * </ul>
+ *
+ * <p>For example:</p>
+ *
+ * <pre>
+ * {@literal @}FunctionName("hello")
+ *  public HttpResponseMessage&lt;String&gt; helloFunction(
+ *    {@literal @}HttpTrigger(name = "req",
+ *                  methods = {"get"},
+ *                  authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage&lt;Optional&lt;String&gt;&gt; request) {
+ *     ....
+ *  }</pre>
+ *
+ * <p>In this code snippet you will observe that we have a function annotated with {@code @FunctionName("hello")},
+ * which indicates that this function will be available at the endpoint /api/hello. The name of the method itself, in
+ * this case {@code helloFunction} is irrelevant for all intents and purposes related to Azure Functions. Note however
+ * that the method return type is {@link com.microsoft.azure.serverless.functions.HttpResponseMessage}, and
+ * that the first argument into the function is an {@link com.microsoft.azure.serverless.functions.HttpRequestMessage}
+ * with generic type {@code Optional<String>}. This indicates that the body of the request will potentially contain
+ * a String value.</p>
+ *
+ * <p>Most important of all however is the {@code @HttpTrigger} annotation that has been applied
+ * to this argument. In this annotation you'll note that it has been given a name, as well as told what type of requests
+ * it supports (in this case, only HTTP GET requests), and that the {@link AuthorizationLevel} is anonymous, allowing
+ * access to anyone who can call the endpoint.</p>
+ *
+ * <p>The {@code HttpTrigger} can be further customised by providing a custom {@link #route()}, which allows for custom
+ * endpoints to be specified, and for these endpoints to be parameterized with arguments being bound to arguments
+ * provided to the function at runtime.</p>
+ *
+ * @see com.microsoft.azure.serverless.functions.HttpRequestMessage
+ * @see com.microsoft.azure.serverless.functions.HttpResponseMessage
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.PARAMETER)
 public @interface HttpTrigger {
+    /**
+     * The variable name used in function code for the request or request body.
+     * @return The variable name used in function code for the request or request body.
+     */
     String name();
 
     String dataType() default "";
 
+    /**
+     * <p>Defines the route template, controlling which request URLs your function will respond to. The default value if
+     * no route is provided is the function name specified in the {@link FunctionName} annotation, applied to each
+     * Azure Function.</p>
+     *
+     * <p>By default when you create a function for an HTTP trigger, or WebHook, the function is addressable with a
+     * route of the form {@code http://&lt;yourapp&gt;.azurewebsites.net/api/&lt;funcname&gt;}. You can customize this route using
+     * this route property. For example, a route of {@code "products/{category:alpha}/{id:int}"} would mean that the
+     * function is now addressable with the following route instead of the original route:
+     * {@code http://&lt;yourapp&gt;.azurewebsites.net/api/products/electronics/357}, which allows the function code to support
+     * two parameters in the address: category and id. By specifying the route in this way, developers can then
+     * add the additional route arguments as arguments into the function by using the {@link BindingName} annotation.
+     * For example:</p>
+     *
+     * <pre>
+     * {@literal @}FunctionName("routeTest")
+     *  public HttpResponseMessage&lt;String&gt; routeTest(
+     *      {@literal @}HttpTrigger(name = "req",
+     *                    methods = {"get"},
+     *                    authLevel = AuthorizationLevel.ANONYMOUS,
+     *                    route = "products/{category:alpha}/{id:int}") HttpRequestMessage&lt;Optional&lt;String&gt;&gt; request,
+     *      {@literal @}BindingName("category") String category,
+     *      {@literal @}BindingName("id") int id,
+     *       final ExecutionContext context) {
+     *           ....
+     *           context.getLogger().info("We have " + category + " with id " + id);
+     *           ....
+     *  }
+     * </pre>
+     *
+     * <p>For more details on the route syntax, refer to the
+     * <a href="https://docs.microsoft.com/en-us/aspnet/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2#constraints">
+     *     online documentation</a>.</p>
+     *
+     * @return The route template to use for the annotated function.
+     */
     String route() default "";
 
+    /**
+     * An array of the HTTP methods to which the function responds. If not specified, the function responds to all HTTP
+     * methods.
+     *
+     * @return An array containing all valid HTTP methods.
+     */
     String[] methods() default {};
 
+    /**
+     * <p>Determines what keys, if any, need to be present on the request in order to invoke the function. The authorization
+     * level can be one of the following values:</p>
+     *
+     * <ul>
+     *     <li><strong>anonymous</strong>: No API key is required.</li>
+     *     <li><strong>function</strong>: A function-specific API key is required. This is the default value if none is provided.</li>
+     *     <li><strong>admin</strong>: The master key is required.</li>
+     * </ul>
+     *
+     * <p>For more information, see the
+     * <a href="https://docs.microsoft.com/azure/azure-functions/functions-bindings-http-webhook#authorization-keys">documentation about authorization keys</a>.</p>
+     *
+     * @return An {@link AuthorizationLevel} value representing the level required to access the function.
+     */
     AuthorizationLevel authLevel() default AuthorizationLevel.FUNCTION;
 
+    /**
+     * <p>Configures the HTTP trigger to act as a webhook receiver for the specified provider. Don't set the methods
+     * property if you set this property. The webhook type can be one of the following values:</p>
+     *
+     * <ul>
+     *     <li><strong>genericJson</strong>: A general-purpose webhook endpoint without logic for a specific provider.
+     *     This setting restricts requests to only those using HTTP POST and with the {@code application/json} content
+     *     type.</li>
+     *     <li><strong>github</strong>: The function responds to
+     *     <a href="https://developer.github.com/webhooks/">GitHub webhooks</a>. Do not use the {@link #authLevel()}
+     *     property with GitHub webhooks.</li>
+     *     <li><strong>slack</strong>: The function responds to
+     *     <a href="https://api.slack.com/outgoing-webhooks">Slack webhooks</a>. Do not use the {@link #authLevel()}
+     *     property with Slack webhooks.</li>
+     * </ul>
+     *
+     * @return A string representing the desired webhook type.
+     */
     String webHookType() default "";
 }
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/MobileTableInput.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/MobileTableInput.java
index 54073de..67ee117 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/MobileTableInput.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/MobileTableInput.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.PARAMETER)
 public @interface MobileTableInput {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/MobileTableOutput.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/MobileTableOutput.java
index a24b27a..6ef51f2 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/MobileTableOutput.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/MobileTableOutput.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.METHOD})
 public @interface MobileTableOutput {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/NotificationHubOutput.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/NotificationHubOutput.java
index 1129d60..bbc08af 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/NotificationHubOutput.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/NotificationHubOutput.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.METHOD})
 public @interface NotificationHubOutput {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/QueueOutput.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/QueueOutput.java
index 11bf79f..8ac961f 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/QueueOutput.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/QueueOutput.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.METHOD})
 public @interface QueueOutput {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/QueueTrigger.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/QueueTrigger.java
index 8c33bc1..b80c88e 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/QueueTrigger.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/QueueTrigger.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.PARAMETER)
 public @interface QueueTrigger {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/SendGridOutput.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/SendGridOutput.java
index b094538..a4b2f5b 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/SendGridOutput.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/SendGridOutput.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.METHOD})
 public @interface SendGridOutput {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ServiceBusQueueOutput.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ServiceBusQueueOutput.java
index 4a657ec..641e4d7 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ServiceBusQueueOutput.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ServiceBusQueueOutput.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.METHOD})
 public @interface ServiceBusQueueOutput {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ServiceBusQueueTrigger.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ServiceBusQueueTrigger.java
index b7a8312..57d8dfe 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ServiceBusQueueTrigger.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ServiceBusQueueTrigger.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.PARAMETER)
 public @interface ServiceBusQueueTrigger {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ServiceBusTopicOutput.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ServiceBusTopicOutput.java
index 66f19c4..005cb71 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ServiceBusTopicOutput.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ServiceBusTopicOutput.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.METHOD})
 public @interface ServiceBusTopicOutput {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ServiceBusTopicTrigger.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ServiceBusTopicTrigger.java
index 91d9223..3dbd989 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ServiceBusTopicTrigger.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/ServiceBusTopicTrigger.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.PARAMETER)
 public @interface ServiceBusTopicTrigger {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/StorageAccount.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/StorageAccount.java
index 0a09afb..89563af 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/StorageAccount.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/StorageAccount.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.METHOD)
 public @interface StorageAccount {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/TableInput.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/TableInput.java
index 3d697bc..e97fc06 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/TableInput.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/TableInput.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.PARAMETER)
 public @interface TableInput {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/TableOutput.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/TableOutput.java
index 8347c5e..63de18e 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/TableOutput.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/TableOutput.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.METHOD})
 public @interface TableOutput {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/TimerTrigger.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/TimerTrigger.java
index 75355ef..6d48012 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/TimerTrigger.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/TimerTrigger.java
@@ -11,12 +11,71 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ * The timer trigger lets you run a function on a schedule by specifying a CRON expression for when the function should
+ * run. For more details and examples on how to specify a CRON expression, refer to the {@link #schedule()} attribute of
+ * this annotation.
+ *
+ * <p>An example of using the timer trigger is shown below, where the {@code keepAlive} function is set to trigger and
+ * execute every four minutes:</p>
+ *
+ * <pre>
+ * {@literal @}FunctionName("keepAlive")
+ *  public void keepAlive(@TimerTrigger(name = "keepAliveTrigger", schedule = "0 *&#47;4 * * * *") String timerInfo) { .. }
+ * </pre>
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.PARAMETER)
 public @interface TimerTrigger {
+    /**
+     * The name of the variable that represents the timer object in function code.
+     *
+     * @return The name of the variable that represents the timer object in function code.
+     */
     String name();
 
     String dataType() default "";
 
+    /**
+     * A <a href="http://en.wikipedia.org/wiki/Cron#CRON_expression">CRON expression</a> in the format
+     * {@code {second} {minute} {hour} {day} {month} {day-of-week}}.
+     *
+     * <p>Some examples of CRON expressions that could be used include:</p>
+     *
+     * <table summary="CRON expression examples">
+     *     <tr>
+     *         <th>Goal</th>
+     *         <th>CRON Expression</th>
+     *     </tr>
+     *     <tr>
+     *         <td>To trigger once every five minutes:</td>
+     *         <td>0 *&#47;5 * * * *</td>
+     *     </tr>
+     *     <tr>
+     *         <td>To trigger once at the top of every hour:</td>
+     *         <td>0 0 * * * *</td>
+     *     </tr>
+     *     <tr>
+     *         <td>To trigger once every two hours:</td>
+     *         <td>0 0 *&#47;2 * * *</td>
+     *     </tr>
+     *     <tr>
+     *         <td>To trigger once every hour from 9 AM to 5 PM:</td>
+     *         <td>0 0 9-17 * * *</td>
+     *     </tr>
+     *     <tr>
+     *         <td>To trigger at 9:30 AM every day:</td>
+     *         <td>0 30 9 * * *</td>
+     *     </tr>
+     *     <tr>
+     *         <td>To trigger at 9:30 AM every weekday:</td>
+     *         <td>0 30 9 * * 1-5</td>
+     *     </tr>
+     * </table>
+     *
+     * @return A string representing a CRON expression that will be used to schedule a function to run.
+     */
     String schedule();
 }
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/TwilioSmsOutput.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/TwilioSmsOutput.java
index 7a610fc..51165de 100644
--- a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/TwilioSmsOutput.java
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/TwilioSmsOutput.java
@@ -11,6 +11,10 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ *
+ * @since 1.0.0
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.PARAMETER, ElementType.METHOD})
 public @interface TwilioSmsOutput {
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/package-info.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/package-info.java
new file mode 100644
index 0000000..2ed96af
--- /dev/null
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/annotation/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Annotations and support classes for use as part of the Java API for Azure Functions.
+ */
+package com.microsoft.azure.serverless.functions.annotation;
\ No newline at end of file
diff --git a/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/package-info.java b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/package-info.java
new file mode 100644
index 0000000..f378da4
--- /dev/null
+++ b/azure-functions-java-core/src/main/java/com/microsoft/azure/serverless/functions/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * The root package for the Java API for Azure Functions.
+ */
+package com.microsoft.azure.serverless.functions;
\ No newline at end of file
diff --git a/azure-functions-java-worker/devdoc.md b/azure-functions-java-worker/devdoc.md
index babe5eb..92ad5b4 100644
--- a/azure-functions-java-worker/devdoc.md
+++ b/azure-functions-java-worker/devdoc.md
@@ -21,6 +21,65 @@ This project has adopted the [Microsoft Open Source Code of Conduct](https://ope
 * Set the JRE libraries to JRE 1.8
 * "Ignore optional compiler problems" in "Java Build Path" for "target/generated-sources/\*\*/\*.java"
 
+# Development Cycle
+
+## Build
+
+This is a maven based project, thus you can use any command line tools or IDEs which support maven to build it. Here we will use command line as the example (you could configure your own development environment accordingly).
+
+To build the project, you just need to run one command from the root folder of this project:
+
+```sh
+mvn clean package
+```
+
+And the binary will be built to `"./azure-functions-java-worker/target/azure-functions-java-worker-<version>.jar"`.
+
+If you have updated the core interface (azure-functions-java-core), a `mvn clean install` is required for your test functions app to reference the latest core package.
+
+## Debug
+
+The Java worker alone is not enough to establish the functions app, we also need the support from [Azure Functions Host](https://github.com/Azure/azure-functions-host). You may either use a published host CLI or use the in-development host. But both of the methods require you to attach to the java process if you want a step-by-step debugging experience.
+
+### Published Host
+
+You can install the latest Azure functions CLI tool by:
+
+```sh
+npm install -g azure-functions-core-tools@core
+```
+
+By default, the binaries are located in `"<Home Folder>/.azurefunctions/bin"`. Copy the `"<Azure Functions Java Worker Root>/azure-functions-java-worker/target/azure-functions-java-worker-<version>.jar"` to `"<Home Folder>/.azurefunctions/bin/workers/java/azure-functions-java-worker.jar"`. And start it normally using:
+
+```sh
+func start
+```
+
+### Latest Host
+
+A developer may also use the latest host code by cloning the git repository [Azure Functions Host](https://github.com/Azure/azure-functions-host). Now you need to navigate to the root folder of the host project and build it through:
+
+```sh
+dotnet restore WebJobs.Script.sln
+dotnet build WebJobs.Script.sln
+```
+
+After the build succeeded, set the environment variable `"AzureWebJobsScriptRoot"` to the root folder path (the folder which contains the `host.json`) of your test functions app; and copy the `"<Azure Functions Java Worker Root>/azure-functions-java-worker/target/azure-functions-java-worker-<version>.jar"` to `"<Azure Functions Host Root>/src/WebJobs.Script.WebHost/bin/Debug/netcoreapp2.0/workers/java/azure-functions-java-worker.jar"`. Now it's time to start the host:
+
+```sh
+dotnet ./src/WebJobs.Script.WebHost/bin/Debug/netcoreapp2.0/Microsoft.Azure.WebJobs.Script.WebHost.dll
+```
+
+> Note: Remember to remove `"AzureWebJobsScriptRoot"` environment variable after you have finished debugging, because it will also influence the `func` CLI tool.
+
+## Generate JavaDoc
+
+Simply using the following command to do so (if there are dependency errors, run `mvn clean install` beforehand):
+
+```sh
+mvn javadoc:javadoc
+```
+
 # Coding Convention
 
 ## Version Management
diff --git a/azure-functions-java-worker/pom.xml b/azure-functions-java-worker/pom.xml
index 2e8e010..538c923 100644
--- a/azure-functions-java-worker/pom.xml
+++ b/azure-functions-java-worker/pom.xml
@@ -2,7 +2,7 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.microsoft.azure</groupId>
   <artifactId>azure-functions-java-worker</artifactId>
-  <version>1.0.0-beta-3</version>
+  <version>1.0.0-beta-4</version>
   <packaging>jar</packaging>
 
   <name>Microsoft Azure Functions Java Runtime</name>
@@ -44,7 +44,7 @@
     <dependency>
       <groupId>com.microsoft.azure</groupId>
       <artifactId>azure-functions-java-core</artifactId>
-      <version>1.0.0-beta-2</version>
+      <version>1.0.0-beta-3</version>
     </dependency>
     <dependency>
       <groupId>com.google.protobuf</groupId>
@@ -101,6 +101,12 @@
       <artifactId>javax.annotation-api</artifactId>
       <version>1.3.1</version>
     </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.12</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <build>
@@ -172,6 +178,33 @@
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <version>2.21.0</version>
+        <configuration>
+          <workingDirectory>${project.build.directory}</workingDirectory>
+          <systemProperties>
+            <property>
+              <name>testing-project-jar</name>
+              <value>${project.artifactId}-${project.version}-tests.jar</value>
+            </property>
+          </systemProperties>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <version>3.1.0</version>
+        <executions>
+          <execution>
+            <phase>test-compile</phase>
+            <goals>
+              <goal>test-jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
   
diff --git a/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/Application.java b/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/Application.java
index a93c274..c83c036 100644
--- a/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/Application.java
+++ b/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/Application.java
@@ -10,16 +10,19 @@ import org.apache.commons.cli.*;
  * The entry point of the Java Language Worker. Every component could get the command line options from this singleton
  * Application instance, and typically that instance will be passed to your components as constructor arguments.
  */
-public final class Application {
+public final class Application implements IApplication {
     private Application(String[] args) {
         this.parseCommandLine(args);
     }
 
+    @Override
     public String getHost() { return this.host; }
-    int getPort() { return this.port; }
+    @Override
+    public int getPort() { return this.port; }
+    @Override
+    public boolean logToConsole() { return this.logToConsole; }
     private String getWorkerId() { return this.workerId; }
     private String getRequestId() { return this.requestId; }
-    boolean logToConsole() { return this.logToConsole; }
 
     private void printUsage() {
         HelpFormatter formatter = new HelpFormatter();
@@ -96,7 +99,7 @@ public final class Application {
                     .build());
 
 
-    public static void main(String[] args) throws IOException {
+    public static void main(String[] args) {
         System.out.println("Microsoft Azure Functions Java Runtime [build " + version() + "]");
         Application app = new Application(args);
         if (!app.isCommandlineValid()) {
@@ -104,7 +107,7 @@ public final class Application {
             System.exit(1);
         } else {
             try (JavaWorkerClient client = new JavaWorkerClient(app)) {
-                client.listen(app.getWorkerId(), app.getRequestId());
+                client.listen(app.getWorkerId(), app.getRequestId()).get();
             } catch (Exception ex) {
                 WorkerLogManager.getSystemLogger().log(Level.SEVERE, "Unexpected Exception causes system to exit", ex);
                 System.exit(-1);
diff --git a/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/IApplication.java b/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/IApplication.java
new file mode 100644
index 0000000..01b61e7
--- /dev/null
+++ b/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/IApplication.java
@@ -0,0 +1,7 @@
+package com.microsoft.azure.webjobs.script;
+
+public interface IApplication {
+    boolean logToConsole();
+    String getHost();
+    int getPort();
+}
diff --git a/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/JavaWorkerClient.java b/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/JavaWorkerClient.java
index cfa3cee..599e9ff 100644
--- a/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/JavaWorkerClient.java
+++ b/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/JavaWorkerClient.java
@@ -19,8 +19,8 @@ import com.microsoft.azure.webjobs.script.rpc.messages.*;
  * Grpc client talks with the Azure Functions Runtime Host. It will dispatch to different message handlers according to the inbound message type.
  * Thread-Safety: Single thread.
  */
-class JavaWorkerClient implements AutoCloseable {
-    JavaWorkerClient(Application app) {
+public class JavaWorkerClient implements AutoCloseable {
+    public JavaWorkerClient(IApplication app) {
         WorkerLogManager.initialize(this, app.logToConsole());
         this.channel = ManagedChannelBuilder.forAddress(app.getHost(), app.getPort()).usePlaintext(true).build();
         this.peer = new AtomicReference<>(null);
@@ -39,14 +39,10 @@ class JavaWorkerClient implements AutoCloseable {
         this.handlerSuppliers.put(StreamingMessage.ContentCase.INVOCATION_REQUEST, () -> new InvocationRequestHandler(broker));
     }
 
-    void listen(String workerId, String requestId) throws Exception {
-        try (StreamingMessagePeer peer = new StreamingMessagePeer()) {
-            this.peer.set(peer);
-            peer.send(requestId, new StartStreamHandler(workerId));
-            peer.getListeningTask().get();
-        } finally {
-            this.peer.set(null);
-        }
+    public Future<Void> listen(String workerId, String requestId) {
+        this.peer.set(new StreamingMessagePeer());
+        this.peer.get().send(requestId, new StartStreamHandler(workerId));
+        return this.peer.get().getListeningTask();
     }
 
     void logToHost(LogRecord record, String invocationId) {
@@ -58,8 +54,11 @@ class JavaWorkerClient implements AutoCloseable {
 
     @Override
     public void close() throws Exception {
+        this.peer.get().close();
+        this.peer.set(null);
         this.channel.shutdownNow();
         this.channel.awaitTermination(15, TimeUnit.SECONDS);
+        WorkerLogManager.deinitialize();
     }
 
     private class StreamingMessagePeer implements StreamObserver<StreamingMessage>, AutoCloseable {
diff --git a/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/WorkerLogManager.java b/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/WorkerLogManager.java
index 932429f..5c66a61 100644
--- a/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/WorkerLogManager.java
+++ b/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/WorkerLogManager.java
@@ -13,6 +13,7 @@ public class WorkerLogManager {
     public static Logger getInvocationLogger(String invocationId) { return INSTANCE.getInvocationLoggerImpl(invocationId); }
 
     static void initialize(JavaWorkerClient client, boolean logToConsole) { INSTANCE.initializeImpl(client, logToConsole); }
+    static void deinitialize() { INSTANCE.deinitializempl(); }
 
     private WorkerLogManager() {
         this.client = null;
@@ -30,6 +31,13 @@ public class WorkerLogManager {
         addHostClientHandlers(this.hostLogger, null);
     }
 
+    private void deinitializempl() {
+        assert this.client != null;
+        clearHandlers(this.hostLogger);
+        this.logToConsole = false;
+        this.client = null;
+    }
+
     private Logger getInvocationLoggerImpl(String invocationId) {
         Logger logger = Logger.getAnonymousLogger();
         logger.setLevel(Level.ALL);
diff --git a/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/binding/BindingDefinition.java b/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/binding/BindingDefinition.java
index 940420e..535580b 100644
--- a/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/binding/BindingDefinition.java
+++ b/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/binding/BindingDefinition.java
@@ -15,7 +15,7 @@ public final class BindingDefinition {
     boolean isOutput() { return this.direction == BindingInfo.Direction.out || this.direction == BindingInfo.Direction.inout; }
 
     enum BindingType {
-        TIMER, HTTP, QUEUE, TABLE, BLOB, SERVICEBUS, EVENTHUB, NOTIFICATIONHUB, MANUAL, MOBILETABLE, DOCUMENTDB, TWILIOSMS, SENDGRID, UNKNOWN;
+        TIMER, HTTP, QUEUE, TABLE, BLOB, SERVICEBUS, EVENTHUB, NOTIFICATIONHUB, MANUAL, MOBILETABLE, COSMOSDB, TWILIOSMS, SENDGRID, EVENTGRID, UNKNOWN;
 
         private static BindingType parse(String type) {
             switch (type) {
@@ -29,9 +29,10 @@ public final class BindingDefinition {
                 case "notificationHub": return NOTIFICATIONHUB;
                 case "manualTrigger": return MANUAL;
                 case "mobileTable": return MOBILETABLE;
-                case "documentDB": return DOCUMENTDB;
+                case "cosmosDB": case "cosmosDBTrigger": return COSMOSDB;
                 case "twilioSms": return TWILIOSMS;
                 case "sendGrid": return SENDGRID;
+                case "eventGridTrigger": return EVENTGRID;
                 default: return UNKNOWN;
             }
         }
diff --git a/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/binding/RpcComplexDataSources.java b/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/binding/RpcComplexDataSources.java
index b0f0c01..565ed67 100644
--- a/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/binding/RpcComplexDataSources.java
+++ b/azure-functions-java-worker/src/main/java/com/microsoft/azure/webjobs/script/binding/RpcComplexDataSources.java
@@ -119,6 +119,11 @@ final class RpcHttpRequestDataSource extends DataSource<RpcHttpRequestDataSource
         @Override
         public Object getBody() { return this.body; }
 
+        @Override
+        public HttpResponseMessage createResponse(int status) {
+            return createResponse(status, null);
+        }
+
         @Override
         public HttpResponseMessage createResponse(int status, Object body) {
             RpcHttpDataTarget response = new RpcHttpDataTarget();


Test patch:
diff --git a/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/broker/tests/CoreTypeResolverTests.java b/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/broker/tests/CoreTypeResolverTests.java
new file mode 100644
index 0000000..aa99654
--- /dev/null
+++ b/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/broker/tests/CoreTypeResolverTests.java
@@ -0,0 +1,71 @@
+package com.microsoft.azure.webjobs.script.broker.tests;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import com.microsoft.azure.serverless.functions.OutputBinding;
+import com.microsoft.azure.webjobs.script.test.categories.*;
+import org.junit.*;
+import org.junit.experimental.categories.*;
+
+import static com.microsoft.azure.webjobs.script.broker.CoreTypeResolver.getRuntimeClass;
+import static com.microsoft.azure.webjobs.script.broker.CoreTypeResolver.isValidOutputType;
+import static org.junit.Assert.*;
+
+public class CoreTypeResolverTests {
+    @Test
+    @Category({UnitTesting.class, SmokeTesting.class, FunctionalTesting.class})
+    public void testIsValidOutputType() throws Exception {
+        assertFalse(isValidOutputType(Integer.class));
+        assertFalse(isValidOutputType(int.class));
+        assertTrue(isValidOutputType(returnTypeOf("outputInteger")));
+        assertFalse(isValidOutputType(returnTypeOf("outputOutputInteger")));
+        assertTrue(isValidOutputType(ExtendedOutputBinding.class));
+        assertFalse(isValidOutputType(returnTypeOf("listInteger")));
+        assertTrue(isValidOutputType(returnTypeOf("outputListInteger")));
+        assertTrue(isValidOutputType(returnTypeOf("exoutputInteger")));
+        assertTrue(isValidOutputType(returnTypeOf("exoutputListInteger")));
+        assertFalse(isValidOutputType(returnTypeOf("exoutputOutputInteger")));
+        assertFalse(isValidOutputType(returnTypeOf("outputExoutputInteger")));
+    }
+
+    @Test
+    @Category({UnitTesting.class, SmokeTesting.class, FunctionalTesting.class})
+    public void testGetRuntimeClass() throws Exception {
+        assertEquals(Integer.class, getRuntimeClass(Integer.class));
+        assertEquals(Integer.TYPE, getRuntimeClass(int.class));
+        assertEquals(OutputBinding.class, getRuntimeClass(returnTypeOf("outputInteger")));
+        assertEquals(OutputBinding.class, getRuntimeClass(returnTypeOf("outputOutputInteger")));
+        assertEquals(List.class, getRuntimeClass(returnTypeOf("listInteger")));
+        assertEquals(OutputBinding.class, getRuntimeClass(returnTypeOf("outputListInteger")));
+        assertEquals(GenericExtendedOutputBinding.class, getRuntimeClass(returnTypeOf("exoutputOutputInteger")));
+        assertEquals(OutputBinding.class, getRuntimeClass(returnTypeOf("outputExoutputInteger")));
+    }
+
+    private OutputBinding<Integer> outputInteger() { return null; }
+    private OutputBinding<OutputBinding<Integer>> outputOutputInteger() { return null; }
+    private List<Integer> listInteger() { return null; }
+    private OutputBinding<List<Integer>> outputListInteger() { return null; }
+    private GenericExtendedOutputBinding<Integer> exoutputInteger() { return null; }
+    private GenericExtendedOutputBinding<List<Integer>> exoutputListInteger() { return null; }
+    private GenericExtendedOutputBinding<OutputBinding<Integer>> exoutputOutputInteger() { return null; }
+    private OutputBinding<GenericExtendedOutputBinding<Integer>> outputExoutputInteger() { return null; }
+    private Type returnTypeOf(String type) throws NoSuchMethodException {
+        Method m = CoreTypeResolverTests.class.getDeclaredMethod(type);
+        m.setAccessible(true);
+        return m.getGenericReturnType();
+    }
+
+    private class ExtendedOutputBinding implements OutputBinding<Integer> {
+        @Override
+        public Integer getValue() { return null; }
+        @Override
+        public void setValue(Integer value) {}
+    }
+    private class GenericExtendedOutputBinding<T> implements OutputBinding<T> {
+        @Override
+        public T getValue() { return null; }
+        @Override
+        public void setValue(T value) {}
+    }
+}
diff --git a/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/functional/tests/SimpleParamReturnTests.java b/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/functional/tests/SimpleParamReturnTests.java
new file mode 100644
index 0000000..eac6967
--- /dev/null
+++ b/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/functional/tests/SimpleParamReturnTests.java
@@ -0,0 +1,58 @@
+package com.microsoft.azure.webjobs.script.functional.tests;
+
+import java.util.*;
+
+import com.microsoft.azure.webjobs.script.rpc.messages.*;
+import com.microsoft.azure.webjobs.script.test.categories.*;
+import com.microsoft.azure.webjobs.script.test.utilities.*;
+import org.junit.*;
+import org.junit.experimental.categories.*;
+
+import static org.junit.Assert.*;
+
+public class SimpleParamReturnTests extends FunctionsTestBase {
+    public static String EmptyParameterFunction() {
+        return "Empty Parameter Result";
+    }
+
+    private static int intReturnValue = 0;
+    public static int ReturnIntFunction() {
+        return intReturnValue;
+    }
+
+    @Test
+    @Category({IntegrationTesting.class, SmokeTesting.class, FunctionalTesting.class})
+    public void testEmptyParameter() throws Exception {
+        try (FunctionsTestHost host = new FunctionsTestHost()) {
+            this.loadFunction(host, "emptyparam", "EmptyParameterFunction");
+            InvocationResponse response = host.call("getret", "emptyparam");
+            assertEquals(TypedData.DataCase.STRING, response.getReturnValue().getDataCase());
+            assertEquals("Empty Parameter Result", response.getReturnValue().getString());
+        }
+    }
+
+    @Test
+    @Category({IntegrationTesting.class, SmokeTesting.class, FunctionalTesting.class})
+    public void testIntReturn() throws Exception {
+        try (FunctionsTestHost host = new FunctionsTestHost()) {
+            this.loadFunction(host, "intreturn", "ReturnIntFunction");
+
+            intReturnValue = 13579;
+            InvocationResponse response = host.call("getret13579", "intreturn");
+            assertEquals(TypedData.DataCase.INT, response.getReturnValue().getDataCase());
+            assertEquals(intReturnValue, response.getReturnValue().getInt());
+
+            intReturnValue = 24680;
+            response = host.call("getret24680", "intreturn");
+            assertEquals(TypedData.DataCase.INT, response.getReturnValue().getDataCase());
+            assertEquals(intReturnValue, response.getReturnValue().getInt());
+
+            for (int i = 0; i < 100; i++) {
+                intReturnValue = new Random().nextInt();
+                response = host.call("getretloop" + intReturnValue, "intreturn");
+                assertEquals(TypedData.DataCase.INT, response.getReturnValue().getDataCase());
+                assertEquals(intReturnValue, response.getReturnValue().getInt());
+            }
+        }
+    }
+}
diff --git a/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/test/categories/FunctionalTesting.java b/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/test/categories/FunctionalTesting.java
new file mode 100644
index 0000000..549506b
--- /dev/null
+++ b/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/test/categories/FunctionalTesting.java
@@ -0,0 +1,3 @@
+package com.microsoft.azure.webjobs.script.test.categories;
+
+public interface FunctionalTesting {}
diff --git a/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/test/categories/IntegrationTesting.java b/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/test/categories/IntegrationTesting.java
new file mode 100644
index 0000000..2f3f2b1
--- /dev/null
+++ b/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/test/categories/IntegrationTesting.java
@@ -0,0 +1,3 @@
+package com.microsoft.azure.webjobs.script.test.categories;
+
+public interface IntegrationTesting {}
diff --git a/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/test/categories/SmokeTesting.java b/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/test/categories/SmokeTesting.java
new file mode 100644
index 0000000..19e885f
--- /dev/null
+++ b/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/test/categories/SmokeTesting.java
@@ -0,0 +1,3 @@
+package com.microsoft.azure.webjobs.script.test.categories;
+
+public interface SmokeTesting {}
diff --git a/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/test/categories/UnitTesting.java b/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/test/categories/UnitTesting.java
new file mode 100644
index 0000000..0ee1e87
--- /dev/null
+++ b/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/test/categories/UnitTesting.java
@@ -0,0 +1,3 @@
+package com.microsoft.azure.webjobs.script.test.categories;
+
+public interface UnitTesting {}
diff --git a/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/test/utilities/FunctionsTestBase.java b/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/test/utilities/FunctionsTestBase.java
new file mode 100644
index 0000000..cff8ac7
--- /dev/null
+++ b/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/test/utilities/FunctionsTestBase.java
@@ -0,0 +1,18 @@
+package com.microsoft.azure.webjobs.script.test.utilities;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import com.microsoft.azure.webjobs.script.rpc.messages.*;
+
+public class FunctionsTestBase {
+    protected void loadFunction(FunctionsTestHost host, String id, String method) throws Exception {
+        String fullname = this.getClass().getCanonicalName() + "." + method;
+        Map<String, BindingInfo> bindings = new HashMap<>();
+        Method entry = this.getClass().getMethod(method);
+        if (!entry.getReturnType().equals(Void.TYPE)) {
+            bindings.put("$return", BindingInfo.newBuilder().setDirection(BindingInfo.Direction.out).build());
+        }
+        host.loadFunction(id, fullname, bindings);
+    }
+}
diff --git a/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/test/utilities/FunctionsTestHost.java b/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/test/utilities/FunctionsTestHost.java
new file mode 100644
index 0000000..637043e
--- /dev/null
+++ b/azure-functions-java-worker/src/test/java/com/microsoft/azure/webjobs/script/test/utilities/FunctionsTestHost.java
@@ -0,0 +1,195 @@
+package com.microsoft.azure.webjobs.script.test.utilities;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.atomic.*;
+import java.util.concurrent.locks.*;
+import java.util.function.*;
+import java.util.stream.*;
+import javax.annotation.*;
+import javax.annotation.concurrent.*;
+
+import com.google.protobuf.*;
+import com.microsoft.azure.webjobs.script.*;
+import com.microsoft.azure.webjobs.script.rpc.messages.*;
+import io.grpc.*;
+import io.grpc.stub.*;
+import org.apache.commons.lang3.tuple.*;
+
+public final class FunctionsTestHost implements AutoCloseable, IApplication {
+    public FunctionsTestHost() throws Exception {
+        this.initializeServer();
+        this.initializeClient();
+    }
+
+    @PostConstruct
+    private void initializeServer() throws IOException {
+        ServerBuilder<?> builder = ServerBuilder.forPort(this.getPort());
+        this.grpcHost = new HostGrpcImplementation();
+        this.server = builder.addService(this.grpcHost).build();
+        this.server.start();
+    }
+
+    @PostConstruct
+    private void initializeClient() throws InterruptedException {
+        this.client = new JavaWorkerClient(this);
+        this.client.listen("java-worker-test", HostGrpcImplementation.ESTABLISH_REQID);
+        this.grpcHost.handleMessage(HostGrpcImplementation.ESTABLISH_REQID, m -> this.grpcHost.initWorker());
+    }
+
+    @Override
+    public void close() throws Exception {
+        this.client.close();
+        this.server.shutdownNow().awaitTermination();
+    }
+
+    public void loadFunction(String id, String reflectionName, Map<String, BindingInfo> bindings) throws Exception {
+        this.grpcHost.handleMessage(HostGrpcImplementation.INITWORKER_REQID, m -> this.grpcHost.loadFunction(id, reflectionName, bindings));
+        this.grpcHost.handleMessage(HostGrpcImplementation.LOADFUNC_REQID, null);
+    }
+
+    @SafeVarargs
+    public final InvocationResponse call(String reqId, String funcId, Triple<String, TypedData.DataCase, Object> ...params) throws Exception {
+        AtomicReference<InvocationResponse> response = new AtomicReference<>();
+        this.grpcHost.handleMessage(this.lastCallReqId, m -> this.grpcHost.invokeFunction(reqId, funcId, params));
+        this.grpcHost.handleMessage(reqId, m -> {
+            response.set(m.getInvocationResponse());
+            return null;
+        });
+        this.lastCallReqId = reqId;
+        return response.get();
+    }
+
+    @Override
+    public boolean logToConsole() { return false; }
+    @Override
+    public String getHost() { return "localhost"; }
+    @Override
+    public int getPort() { return 55005; }
+
+    private JavaWorkerClient client;
+    private HostGrpcImplementation grpcHost;
+    private Server server;
+    private String lastCallReqId = HostGrpcImplementation.LOADFUNC_REQID;
+
+
+    @ThreadSafe
+    private class HostGrpcImplementation extends FunctionRpcGrpc.FunctionRpcImplBase {
+        static final String ESTABLISH_REQID = "establish", INITWORKER_REQID = "init-worker", LOADFUNC_REQID = "load-function";
+
+        private final Lock lock = new ReentrantLock();
+        private final Map<String, Condition> respReady = new HashMap<>();
+        private final Map<String, StreamingMessage> respValue = new HashMap<>();
+        private final Map<String, StreamObserver<StreamingMessage>> responder = new HashMap<>();
+
+        private Condition getResponseCondition(String requestId) {
+            return this.respReady.computeIfAbsent(requestId, k -> this.lock.newCondition());
+        }
+
+        private void setResponse(String requestId, StreamingMessage value, StreamObserver<StreamingMessage> client) {
+            this.respValue.put(requestId, value);
+            this.responder.put(requestId, client);
+            this.getResponseCondition(requestId).signal();
+        }
+
+        void handleMessage(String requestId, Function<StreamingMessage, StreamingMessage> handler) throws InterruptedException {
+            this.lock.lock();
+            try {
+                if (this.responder.get(requestId) == null) {
+                    this.getResponseCondition(requestId).await();
+                }
+                StreamingMessage message = this.respValue.get(requestId);
+                StreamingMessage response = null;
+                if (handler != null) {
+                    response = handler.apply(message);
+                }
+                if (response != null) {
+                    this.responder.get(requestId).onNext(response);
+                }
+            } finally {
+                this.lock.unlock();
+            }
+        }
+
+        private StreamingMessage initWorker() {
+            WorkerInitRequest.Builder request = WorkerInitRequest.newBuilder().setHostVersion("2.0.0");
+            return StreamingMessage.newBuilder().setRequestId(INITWORKER_REQID).setWorkerInitRequest(request).build();
+        }
+
+        private StreamingMessage loadFunction(String id, String reflectionName, Map<String, BindingInfo> bindings) {
+            RpcFunctionMetadata.Builder metadata = RpcFunctionMetadata.newBuilder()
+                    .setName(reflectionName.substring(reflectionName.lastIndexOf('.') + 1))
+                    .setDirectory(".")
+                    .setScriptFile(System.getProperty("testing-project-jar"))
+                    .setEntryPoint(reflectionName)
+                    .putAllBindings(bindings);
+            FunctionLoadRequest.Builder request = FunctionLoadRequest.newBuilder()
+                    .setFunctionId(id)
+                    .setMetadata(metadata);
+            return StreamingMessage.newBuilder().setRequestId(LOADFUNC_REQID).setFunctionLoadRequest(request).build();
+        }
+
+        private StreamingMessage invokeFunction(String reqId, String funcId, Triple<String, TypedData.DataCase, Object>[] params) {
+            List<ParameterBinding> bindings = Arrays.stream(params).map(p -> {
+                ParameterBinding.Builder binding = ParameterBinding.newBuilder();
+                TypedData.Builder data = TypedData.newBuilder();
+                if (p.getLeft() != null && !p.getLeft().isEmpty()) {
+                    binding.setName(p.getLeft());
+                }
+                switch (p.getMiddle()) {
+                    case STRING:
+                        data.setString((String) p.getRight());
+                        break;
+                    case JSON:
+                        data.setJson((String) p.getRight());
+                        break;
+                    case BYTES:
+                        data.setBytes((ByteString) p.getRight());
+                        break;
+                    case HTTP:
+                        data.setHttp((RpcHttp.Builder) p.getRight());
+                        break;
+                    case INT:
+                        data.setInt((long)p.getRight());
+                        break;
+                    case DOUBLE:
+                        data.setDouble((double)p.getRight());
+                        break;
+                    default:
+                        throw new UnsupportedOperationException(p.toString());
+                }
+                return binding.setData(data).build();
+            }).collect(Collectors.toList());
+            InvocationRequest.Builder request = InvocationRequest.newBuilder()
+                    .setInvocationId(reqId)
+                    .setFunctionId(funcId)
+                    .addAllInputData(bindings);
+            return StreamingMessage.newBuilder().setRequestId(reqId).setInvocationRequest(request).build();
+        }
+
+        @Override
+        public StreamObserver<StreamingMessage> eventStream(StreamObserver<StreamingMessage> responseObserver) {
+            return new StreamObserver<StreamingMessage>() {
+                @Override
+                public void onNext(StreamingMessage msg) {
+                    HostGrpcImplementation.this.lock.lock();
+                    try {
+                        if (!msg.getContentCase().equals(StreamingMessage.ContentCase.RPC_LOG)) {
+                            HostGrpcImplementation.this.setResponse(msg.getRequestId(), msg, responseObserver);
+                        }
+                    } finally {
+                        HostGrpcImplementation.this.lock.unlock();
+                    }
+                }
+
+                @Override
+                public void onError(Throwable t) {
+                    throw new RuntimeException(t);
+                }
+
+                @Override
+                public void onCompleted() {}
+            };
+        }
+    }
+}