Repository: Azure/azure-functions-java-worker
Pull request #361 (2020-04-23 21:55:46)

Add support for java11.
This PR is for inital support for supporting Java 11 runtime, this PR includes.

- Add support for java11 testing pipeline.
- Fix the dev pipeline.
- Add support for java11.

Next, 
- Investigating updating classloader to lad last first, this should fix the dependency issue.
- Investigating the support for Modules.
- Support the two separate pipelines for java11 and java8.

pragnagopa: @amamounelsayed - Thanks for the PR. Few initial questions:
- Can you point me to build script changes that produce worker jar for Java8 and Java 11?
- Are E2E tests run against Java8 and Java 11
- Worker.config.json updates to figure out worker path for Java 8 and Java 11?
amamounelsayed: @pragnagopa Thank you so much, The changes were not major to have two workers. So the plan is to have the same worker.
- Can you point me to build script changes that produce worker jar for Java8 and Java 11?
It has the same worker so no need to distinguish between both.
- Are E2E tests run against Java8 and Java 11
Yes the pipeline now have a section for java11 and run the same set of the E2E tests.
- Worker.config.json updates to figure out worker path for Java 8 and Java 11? The same worker need to have it.

Background, to insure that this will affects any java8 users, @kevinhillinger suggested to create Factories that will hide this functionality based on the Java runtime process. Current users should not get any impact.

The code will be compiled by java 8 bites which is compatible with java 11 runtime.

The direction built for java 11 should work for java 8. So to not impact java 8 users we will are going to test it with java 11 and then future plans to sunset the current way and be java8 and 11 work in the same way, but this long term plan. 
pragnagopa: > The code will be compiled by java 8 bites which is compatible with java 11 runtime.

Apologies if I misunderstood. This PR is making the code change so that worker jars can be produced for Java 8 and Java 11 right? Or are you planning to ship Java 8 worker for Java 11 apps? If later, is there any advantage of doing it this way? As Java 11 is already available in the Platform, for me it makes more sense to create explicit binaries that will also allow evolving Java worker to take advantage to new feature introduced in Java 11 
amamounelsayed: > Apologies if I misunderstood. This PR is making the code change so that worker jars can be produced for Java 8 and Java 11 right? Or are you planning to ship Java 8 worker for Java 11 apps? If later, is there any advantage of doing it this way? As Java 11 is already available in the Platform, for me it makes more sense to create explicit binaries that will also allow evolving Java worker to take advantage to new feature introduced in Java 11

Yes this is great point. Your second assumption is correct, I will add that java8 worker now support java11. Our initial thought is to have two separate worker but currently we don't have a need to adopt any java 11 new features. 
Plus the support for two different branches for any new feature and maintaining it is a burden we do not currently need it.

Once we have a need to adopt new features then we will for sure follow each branch route. 



pragnagopa: > Plus the support for two different branches for any new feature and maintaining it is a burden we do not currently need it.

You do not have to create two branches until there is a need to diverge. Right now, you just have to produce binaries for each version. Once you have the build setup and tests running for both versions, it will allow you to expand in future and create branches if there is a need.
amamounelsayed: > > Plus the support for two different branches for any new feature and maintaining it is a burden we do not currently need it.
> 
> You do not have to create two branches until there is a need to diverge. Right now, you just have to produce binaries for each version. Once you have the build setup and tests running for both versions, it will allow you to expand in future and create branches if there is a need.

Thank you so much for your help. Yes we can for sure work on this direction I created this issue to track it https://github.com/Azure/azure-functions-java-worker/issues/362. For this release we may use the same java worker as there should not be impact to enhance it in future. 
pragnagopa: > are you planning to ship Java 8 worker for Java 11 apps?

This is a question as I do not have expertise on how JVM handles loading references. Can you please confirm following works:
- Java8 worker with Java 11 function app
- Function App is built for Java 11 only i.e it uses new api etc
- Function App has references to libraries that are built Java 11 only.

You need to verify , when launching Java8 worker in Java 11 JVM, it allows user apps to load Java 11 references.

pragnagopa: @amamounelsayed  -  For Java worker dependencies are listed here: https://github.com/Azure/azure-functions-java-worker/wiki/Azure-Java-Functions-Worker-Dependencies,  When a function app loads and has overlapping dependencies on any of the dependencies listed above, library from java worker take precedence i.e
 -  If any of the libraries are updated for Java 11, it is possible that users will see not see expected behavior when running in Azure Functions.

Addressing: https://github.com/Azure/azure-functions-java-worker/issues/362 will avoid issues with loading libraries. We already have established pattern for managing language worker versions. Please sync up with @AnatoliB  if you need guidance as power shell worker recently added support for PS7.


AnatoliB: > * If any of the libraries are updated for Java 11, it is possible that users will see not see expected behavior when running in Azure Functions.

@amamounelsayed and I discussed this issue and the way versioning for PS6/7 workers is implemented. My recommendation was to avoid the overhead and proceed with a single worker _if this is acceptable for the language runtime_. This condition is _very_ important. In PowerShell, there is no practical way to have a single worker handling both PS6 and PS7, and this is why we separated them, but this separation is not free. I don’t know enough about the Java worker to agree or disagree that the Java worker case is different, but I understand the potential concerns raised by @pragnagopa, so these questions need to be answered first.
mnriem: @AnatoliB For the time being it can be the same as Java11 can run Java8 byte code without any issues, but I foresee that our community will start asking for features (e.g. features geared towards the module system) that can only be delivered by a Java 11 specific runtime.
amamounelsayed: Thank you so much @mnriem and @AnatoliB. @AnatoliB, as @mnriem mentioned it is the case that single worker can handle both java 8 and 11 using java8 bytecode.

@pragnagopa There is two parts in your question compile and runtime.  Any of the jars mentioned it may be complied using any java version and its behavior is guarantee. For run time it should run anywhere and newer runtime version will run it for backward compatible. 

For testing on webapp yes it has been tested for and it worked fine.
Java8 worker with Java 11 function app
Function App has references to libraries that are built Java 11 only.

Last part about the dependencies as we are using the same bytecode it will have the same behavior. 
Using these jars for java8 or java11 does not change its behavior. 
Example Netty has no mandatory external dependencies. JDK 1.5 (1.6 for Netty 4+) or above is all that you need to run Netty.

Thank you so much for bringing this point as @trask and I discussed last week a proposed design I am going to test, this proposal should force the customer jars to take presence over worker jars during running customer code, we are working on it.

Please if you have any specific test or concern just let us know.



pragnagopa: @amamounelsayed  - Than you for the details. Regarding

> Last part about the dependencies as we are using the same bytecode it will have the same behavior.
Using these jars for java8 or java11 does not change its behavior.
Example Netty has no mandatory external dependencies. JDK 1.5 (1.6 for Netty 4+) or above is all that you need to run Netty.

I understand Java worker 8 will itself load and work as expected in JVM 11. But my concern is specially for the following scenario (using gRpc library as an example) :
- Java Worker 8 has dependency on gRpc package version x which is built for  Java 8
- User wants to use a later version of same gRpc package but version y which might have new API introduced. Again this is an example.
- User runs function app. At runtime, since package referenced by Java Worker takes precedence there is a potential to see "MissingMethodException"

I think until you have a fix for "dependency" problem, this would be the case. If you believe above scenario is not true, then I am ok with the change.  Thanks!
amamounelsayed: > I understand Java worker 8 will itself load and work as expected in JVM 11. But my concern is specially for the following scenario (using gRpc library as an example) :
> 
> * Java Worker 8 has dependency on gRpc package version x which is built for  Java 8
> * User wants to use a later version of same gRpc package but version y which might have new API introduced. Again this is an example.
> * User runs function app. At runtime, since package referenced by Java Worker takes precedence there is a potential to see "MissingMethodException"
> 
> I think until you have a fix for "dependency" problem, this would be the case. If you believe above scenario is not true, then I am ok with the change. Thanks!

Your scenario is still the case, but this is the same as Java8. So with java11 will currently have the same behavior. This issue will not be fixed with creating new worker with java11 or even new branch. This issue will need to be fixed by changing the classloader behavior which we are working on it for java11 as a new feature to give customers more flexibility, still we are testing approaches to it. 

If the customer uses new library just java11 and we do not have it in worker this should work as it is expected. 
amamounelsayed: @TsuyoshiUshio Thank you for your review, yes we will update it once we are close to roll it out. For the APPVEYOR I totally agree with you, I will work on it for the next PR.

Patch:
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 318dca8..85ecaa4 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -11,7 +11,7 @@ steps:
    checkLatest: true
 - pwsh: |
      Get-Command mvn
-  displayName: 'Installing Maven'
+  displayName: 'Check Maven is installed'
 - pwsh: |
       $buildNumber = 0      
       if($env:APPVEYOR_REPO_TAG -eq "true") {
@@ -32,10 +32,10 @@ steps:
     CleanTargetFolder: true
   displayName: 'Copying files for artifacts'
 - pwsh: |
-      .\setup-tests.ps1
+      .\setup-tests-pipeline.ps1
   displayName: 'Setting tests'
 - pwsh: |
-      .\run-tests.ps1
+      .\build-run-tests-pipeline.ps1
   env:
     AzureWebJobsStorage: $(AzureWebJobsStorage)
     AzureWebJobsCosmosDBConnectionString: $(AzureWebJobsCosmosDBConnectionString)
@@ -47,8 +47,25 @@ steps:
     SBTopicSubName: $(SBTopicSubName)
     CosmosDBDatabaseName: $(CosmosDBDatabaseName)
     SBQueueName: $(SBQueueName)
-  displayName: 'running tests'
-  continueOnError: true
+  displayName: 'Build & Run tests for java 8'
+  continueOnError: false
+- pwsh: |
+    .\build-run-tests-pipeline.ps1
+  env:
+    JAVA_HOME: 'C:\Program Files\Java\zulu-11-azure-jdk_11.33.15-11.0.4-win_x64'
+    AzureWebJobsStorage: $(AzureWebJobsStorage)
+    AzureWebJobsCosmosDBConnectionString: $(AzureWebJobsCosmosDBConnectionString)
+    AzureWebJobsServiceBus: $(AzureWebJobsServiceBus)
+    AzureWebJobsEventHubSender_2: $(AzureWebJobsEventHubSender_2)
+    AzureWebJobsEventHubReceiver: $(AzureWebJobsEventHubReceiver)
+    AzureWebJobsEventHubSender: $(AzureWebJobsEventHubSender)
+    AzureWebJobsEventHubPath: $(AzureWebJobsEventHubPath)
+    SBTopicName: $(SBTopicName)
+    SBTopicSubName: $(SBTopicSubName)
+    CosmosDBDatabaseName: $(CosmosDBDatabaseName)
+    SBQueueName: $(SBQueueName)
+  displayName: 'Build & Run tests for java 11'
+  continueOnError: false
 - task: CopyFiles@2
   inputs:
     SourceFolder: '$(System.DefaultWorkingDirectory)/testResults'
diff --git a/pom.xml b/pom.xml
index 62d944c..1654312 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
 
 	<properties>
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-		<azure.functions.java.library.version>1.3.1-SNAPSHOT</azure.functions.java.library.version>
+		<azure.functions.java.library.version>1.3.1</azure.functions.java.library.version>
 	</properties>
 
 	<licenses>
diff --git a/src/main/java/com/microsoft/azure/functions/worker/JavaWorkerClient.java b/src/main/java/com/microsoft/azure/functions/worker/JavaWorkerClient.java
index 5c13d25..3063fee 100644
--- a/src/main/java/com/microsoft/azure/functions/worker/JavaWorkerClient.java
+++ b/src/main/java/com/microsoft/azure/functions/worker/JavaWorkerClient.java
@@ -28,7 +28,7 @@ public class JavaWorkerClient implements AutoCloseable {
         this.channel = chanBuilder.build();
         this.peer = new AtomicReference<>(null);
         this.handlerSuppliers = new HashMap<>();
-        this.classPathProvider = new DefaultClassLoaderProvider();
+        this.classPathProvider = new FactoryClassLoader().createClassLoaderProvider();
         
         this.addHandlers();
     }
@@ -117,5 +117,5 @@ public class JavaWorkerClient implements AutoCloseable {
     private final ManagedChannel channel;
     private final AtomicReference<StreamingMessagePeer> peer;
     private final Map<StreamingMessage.ContentCase, Supplier<MessageHandler<?, ?>>> handlerSuppliers;
-    private final DefaultClassLoaderProvider classPathProvider;
+    private final ClassLoaderProvider classPathProvider;
 }
diff --git a/src/main/java/com/microsoft/azure/functions/worker/broker/EnhancedJavaMethodExecutorImpl.java b/src/main/java/com/microsoft/azure/functions/worker/broker/EnhancedJavaMethodExecutorImpl.java
new file mode 100644
index 0000000..26e3c28
--- /dev/null
+++ b/src/main/java/com/microsoft/azure/functions/worker/broker/EnhancedJavaMethodExecutorImpl.java
@@ -0,0 +1,70 @@
+package com.microsoft.azure.functions.worker.broker;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import com.microsoft.azure.functions.worker.binding.*;
+import com.microsoft.azure.functions.worker.description.*;
+import com.microsoft.azure.functions.worker.reflect.*;
+import com.microsoft.azure.functions.rpc.messages.*;
+
+/**
+ * Used to executor of arbitrary Java method in any JAR using reflection.
+ * Thread-Safety: Multiple thread.
+ */
+public class EnhancedJavaMethodExecutorImpl implements JavaMethodExecutor {
+    public EnhancedJavaMethodExecutorImpl(FunctionMethodDescriptor descriptor, Map<String, BindingInfo> bindingInfos, ClassLoaderProvider classLoaderProvider)
+            throws ClassNotFoundException, NoSuchMethodException
+    {
+        descriptor.validateMethodInfo();
+
+        this.classLoader = classLoaderProvider.createClassLoader();
+        this.containingClass = getContainingClass(descriptor.getFullClassName());
+        this.overloadResolver = new ParameterResolver();
+
+        for (Method method : this.containingClass.getMethods()) {
+            if (method.getName().equals(descriptor.getMethodName())) {
+                this.overloadResolver.addCandidate(method);
+            }
+        }
+
+        if (!this.overloadResolver.hasCandidates()) {
+            throw new NoSuchMethodException("There are no methods named \"" + descriptor.getName() + "\" in class \"" + descriptor.getFullClassName() + "\"");
+        }
+
+        if (this.overloadResolver.hasMultipleCandidates()) {
+            throw new UnsupportedOperationException("Found more than one function with method name \"" + descriptor.getName() + "\" in class \"" + descriptor.getFullClassName() + "\"");
+        }
+
+        this.bindingDefinitions = new HashMap<>();
+
+        for (Map.Entry<String, BindingInfo> entry : bindingInfos.entrySet()) {
+            this.bindingDefinitions.put(entry.getKey(), new BindingDefinition(entry.getKey(), entry.getValue()));
+        }
+    }
+
+    public Map<String, BindingDefinition> getBindingDefinitions() { return this.bindingDefinitions; }
+
+    public ParameterResolver getOverloadResolver() { return this.overloadResolver; }
+
+    public void execute(BindingDataStore dataStore) throws Exception {
+        try {
+            Thread.currentThread().setContextClassLoader(this.classLoader);
+            Object retValue = this.overloadResolver.resolve(dataStore)
+                    .orElseThrow(() -> new NoSuchMethodException("Cannot locate the method signature with the given input"))
+                    .invoke(() -> this.containingClass.newInstance());
+            dataStore.setDataTargetValue(BindingDataStore.RETURN_NAME, retValue);
+        } finally {
+            Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
+        }
+    }
+
+    private Class<?> getContainingClass(String className) throws ClassNotFoundException {
+        return Class.forName(className, true, this.classLoader);
+    }
+
+    private final Class<?> containingClass;
+    private final ClassLoader classLoader;
+    private final ParameterResolver overloadResolver;
+    private final Map<String, BindingDefinition> bindingDefinitions;
+}
diff --git a/src/main/java/com/microsoft/azure/functions/worker/broker/FactoryJavaMethodExecutor.java b/src/main/java/com/microsoft/azure/functions/worker/broker/FactoryJavaMethodExecutor.java
new file mode 100644
index 0000000..f2c4bab
--- /dev/null
+++ b/src/main/java/com/microsoft/azure/functions/worker/broker/FactoryJavaMethodExecutor.java
@@ -0,0 +1,23 @@
+package com.microsoft.azure.functions.worker.broker;
+
+import com.microsoft.azure.functions.rpc.messages.BindingInfo;
+import com.microsoft.azure.functions.worker.WorkerLogManager;
+import com.microsoft.azure.functions.worker.description.FunctionMethodDescriptor;
+import com.microsoft.azure.functions.worker.reflect.ClassLoaderProvider;
+import org.apache.commons.lang3.SystemUtils;
+
+import java.net.MalformedURLException;
+import java.util.Map;
+
+public class FactoryJavaMethodExecutor {
+    public JavaMethodExecutor getJavaMethodExecutor(FunctionMethodDescriptor descriptor, Map<String, BindingInfo> bindings, ClassLoaderProvider classLoaderProvider)
+            throws MalformedURLException, ClassNotFoundException, NoSuchMethodException {
+        if(SystemUtils.IS_JAVA_1_8) {
+            WorkerLogManager.getSystemLogger().info("Loading JavaMethodExecutorImpl");
+            return new JavaMethodExecutorImpl(descriptor, bindings, classLoaderProvider);
+        } else {
+            WorkerLogManager.getSystemLogger().info("Loading EnhancedJavaMethodExecutorImpl");
+            return new EnhancedJavaMethodExecutorImpl(descriptor, bindings, classLoaderProvider);
+        }
+    }
+}
diff --git a/src/main/java/com/microsoft/azure/functions/worker/broker/JavaFunctionBroker.java b/src/main/java/com/microsoft/azure/functions/worker/broker/JavaFunctionBroker.java
index 8471df1..3838f05 100644
--- a/src/main/java/com/microsoft/azure/functions/worker/broker/JavaFunctionBroker.java
+++ b/src/main/java/com/microsoft/azure/functions/worker/broker/JavaFunctionBroker.java
@@ -31,7 +31,7 @@ public class JavaFunctionBroker {
 		descriptor.validate();
 
 		addSearchPathsToClassLoader(descriptor);
-		JavaMethodExecutor executor = new JavaMethodExecutor(descriptor, bindings, classLoaderProvider);
+		JavaMethodExecutor executor = new FactoryJavaMethodExecutor().getJavaMethodExecutor(descriptor, bindings, classLoaderProvider);
 
 		this.methods.put(descriptor.getId(), new ImmutablePair<>(descriptor.getName(), executor));
 	}
diff --git a/src/main/java/com/microsoft/azure/functions/worker/broker/JavaMethodExecutor.java b/src/main/java/com/microsoft/azure/functions/worker/broker/JavaMethodExecutor.java
index b87b427..00e1d87 100644
--- a/src/main/java/com/microsoft/azure/functions/worker/broker/JavaMethodExecutor.java
+++ b/src/main/java/com/microsoft/azure/functions/worker/broker/JavaMethodExecutor.java
@@ -14,53 +14,10 @@ import com.microsoft.azure.functions.rpc.messages.*;
  * Used to executor of arbitrary Java method in any JAR using reflection.
  * Thread-Safety: Multiple thread.
  */
-public class JavaMethodExecutor {
-    public JavaMethodExecutor(FunctionMethodDescriptor descriptor, Map<String, BindingInfo> bindingInfos, ClassLoaderProvider classLoaderProvider)
-            throws MalformedURLException, ClassNotFoundException, NoSuchMethodException
-    {
-        descriptor.validateMethodInfo();
+public interface JavaMethodExecutor {
+    Map<String, BindingDefinition> getBindingDefinitions();
 
-        this.containingClass = getContainingClass(descriptor.getFullClassName(), classLoaderProvider);
-        this.overloadResolver = new ParameterResolver();
+    ParameterResolver getOverloadResolver();
 
-        for (Method method : this.containingClass.getMethods()) {                     
-            if (method.getName().equals(descriptor.getMethodName())) {
-                this.overloadResolver.addCandidate(method);                
-            }
-        }
-
-        if (!this.overloadResolver.hasCandidates()) {
-            throw new NoSuchMethodException("There are no methods named \"" + descriptor.getName() + "\" in class \"" + descriptor.getFullClassName() + "\"");
-        }
-
-        if (this.overloadResolver.hasMultipleCandidates()) {
-            throw new UnsupportedOperationException("Found more than one function with method name \"" + descriptor.getName() + "\" in class \"" + descriptor.getFullClassName() + "\"");
-        }
-
-        this.bindingDefinitions = new HashMap<>();
-        
-        for (Map.Entry<String, BindingInfo> entry : bindingInfos.entrySet()) {
-            this.bindingDefinitions.put(entry.getKey(), new BindingDefinition(entry.getKey(), entry.getValue()));
-        }
-    }
-    
-    Map<String, BindingDefinition> getBindingDefinitions() { return this.bindingDefinitions; }
-    
-    public ParameterResolver getOverloadResolver() { return this.overloadResolver; }
-
-    void execute(BindingDataStore dataStore) throws Exception {
-        Object retValue = this.overloadResolver.resolve(dataStore)
-            .orElseThrow(() -> new NoSuchMethodException("Cannot locate the method signature with the given input"))
-            .invoke(() -> this.containingClass.newInstance());
-        dataStore.setDataTargetValue(BindingDataStore.RETURN_NAME, retValue);
-    }
-    
-    Class<?> getContainingClass(String className, ClassLoaderProvider classLoaderProvider) throws ClassNotFoundException {
-        ClassLoader classLoader = classLoaderProvider.getClassLoader();
-        return Class.forName(className, true, classLoader);
-    }
-
-    private Class<?> containingClass;
-    private final ParameterResolver overloadResolver;
-    private final Map<String, BindingDefinition> bindingDefinitions;
+    void execute(BindingDataStore dataStore) throws Exception;
 }
diff --git a/src/main/java/com/microsoft/azure/functions/worker/broker/JavaMethodExecutorImpl.java b/src/main/java/com/microsoft/azure/functions/worker/broker/JavaMethodExecutorImpl.java
new file mode 100644
index 0000000..9e58fb9
--- /dev/null
+++ b/src/main/java/com/microsoft/azure/functions/worker/broker/JavaMethodExecutorImpl.java
@@ -0,0 +1,66 @@
+package com.microsoft.azure.functions.worker.broker;
+
+import java.lang.reflect.*;
+import java.net.*;
+import java.util.*;
+
+import com.microsoft.azure.functions.annotation.*;
+import com.microsoft.azure.functions.worker.binding.*;
+import com.microsoft.azure.functions.worker.description.*;
+import com.microsoft.azure.functions.worker.reflect.*;
+import com.microsoft.azure.functions.rpc.messages.*;
+
+/**
+ * Used to executor of arbitrary Java method in any JAR using reflection.
+ * Thread-Safety: Multiple thread.
+ */
+public class JavaMethodExecutorImpl implements JavaMethodExecutor {
+    public JavaMethodExecutorImpl(FunctionMethodDescriptor descriptor, Map<String, BindingInfo> bindingInfos, ClassLoaderProvider classLoaderProvider)
+            throws MalformedURLException, ClassNotFoundException, NoSuchMethodException
+    {
+        descriptor.validateMethodInfo();
+
+        this.containingClass = getContainingClass(descriptor.getFullClassName(), classLoaderProvider);
+        this.overloadResolver = new ParameterResolver();
+
+        for (Method method : this.containingClass.getMethods()) {
+            if (method.getName().equals(descriptor.getMethodName())) {
+                this.overloadResolver.addCandidate(method);
+            }
+        }
+
+        if (!this.overloadResolver.hasCandidates()) {
+            throw new NoSuchMethodException("There are no methods named \"" + descriptor.getName() + "\" in class \"" + descriptor.getFullClassName() + "\"");
+        }
+
+        if (this.overloadResolver.hasMultipleCandidates()) {
+            throw new UnsupportedOperationException("Found more than one function with method name \"" + descriptor.getName() + "\" in class \"" + descriptor.getFullClassName() + "\"");
+        }
+
+        this.bindingDefinitions = new HashMap<>();
+
+        for (Map.Entry<String, BindingInfo> entry : bindingInfos.entrySet()) {
+            this.bindingDefinitions.put(entry.getKey(), new BindingDefinition(entry.getKey(), entry.getValue()));
+        }
+    }
+
+    public Map<String, BindingDefinition> getBindingDefinitions() { return this.bindingDefinitions; }
+
+    public ParameterResolver getOverloadResolver() { return this.overloadResolver; }
+
+    public void execute(BindingDataStore dataStore) throws Exception {
+        Object retValue = this.overloadResolver.resolve(dataStore)
+                .orElseThrow(() -> new NoSuchMethodException("Cannot locate the method signature with the given input"))
+                .invoke(() -> this.containingClass.newInstance());
+        dataStore.setDataTargetValue(BindingDataStore.RETURN_NAME, retValue);
+    }
+
+    private Class<?> getContainingClass(String className, ClassLoaderProvider classLoaderProvider) throws ClassNotFoundException {
+        ClassLoader classLoader = classLoaderProvider.createClassLoader();
+        return Class.forName(className, true, classLoader);
+    }
+
+    private Class<?> containingClass;
+    private final ParameterResolver overloadResolver;
+    private final Map<String, BindingDefinition> bindingDefinitions;
+}
diff --git a/src/main/java/com/microsoft/azure/functions/worker/reflect/ClassLoaderProvider.java b/src/main/java/com/microsoft/azure/functions/worker/reflect/ClassLoaderProvider.java
index ecef2d2..a8e52e6 100644
--- a/src/main/java/com/microsoft/azure/functions/worker/reflect/ClassLoaderProvider.java
+++ b/src/main/java/com/microsoft/azure/functions/worker/reflect/ClassLoaderProvider.java
@@ -16,7 +16,7 @@ public interface ClassLoaderProvider {
     void addDirectory(File directory) throws MalformedURLException, IOException;
     
     /*
-     * Gets the class loader with the required search paths
+     * Create the class loader with the required search paths
      */
-    ClassLoader getClassLoader();
+    ClassLoader createClassLoader();
 }
diff --git a/src/main/java/com/microsoft/azure/functions/worker/reflect/DefaultClassLoaderProvider.java b/src/main/java/com/microsoft/azure/functions/worker/reflect/DefaultClassLoaderProvider.java
index 67a7475..4aece1f 100644
--- a/src/main/java/com/microsoft/azure/functions/worker/reflect/DefaultClassLoaderProvider.java
+++ b/src/main/java/com/microsoft/azure/functions/worker/reflect/DefaultClassLoaderProvider.java
@@ -19,10 +19,10 @@ public class DefaultClassLoaderProvider implements ClassLoaderProvider {
   }
 
   /*
-   * @see com.microsoft.azure.functions.reflect.ClassLoaderProvider#getClassLoader()
+   * @see com.microsoft.azure.functions.reflect.ClassLoaderProvider#createClassLoader()
    */
   @Override
-  public ClassLoader getClassLoader() {
+  public ClassLoader createClassLoader() {
     URL[] urlsForClassLoader = new URL[urls.size()];
     urls.toArray(urlsForClassLoader);
 
@@ -59,6 +59,8 @@ public class DefaultClassLoaderProvider implements ClassLoaderProvider {
     WorkerLogManager.getSystemLogger().info("Loading file URL: " + url);    
 
     urls.add(url);
+
+
     addUrlToSystemClassLoader(url);
   }
 
diff --git a/src/main/java/com/microsoft/azure/functions/worker/reflect/EnhancedClassLoaderProvider.java b/src/main/java/com/microsoft/azure/functions/worker/reflect/EnhancedClassLoaderProvider.java
new file mode 100644
index 0000000..7e2bf92
--- /dev/null
+++ b/src/main/java/com/microsoft/azure/functions/worker/reflect/EnhancedClassLoaderProvider.java
@@ -0,0 +1,76 @@
+package com.microsoft.azure.functions.worker.reflect;
+
+import java.io.*;
+import java.net.*;
+import java.sql.Driver;
+import java.util.*;
+import java.util.concurrent.*;
+
+
+import com.microsoft.azure.functions.worker.*;
+
+public class EnhancedClassLoaderProvider implements ClassLoaderProvider {
+    public EnhancedClassLoaderProvider() {
+        urls = Collections.newSetFromMap(new ConcurrentHashMap<URL, Boolean>());
+    }
+
+    /*
+     * @see com.microsoft.azure.functions.reflect.ClassLoaderProvider#createClassLoader()
+     */
+    @Override
+    public ClassLoader createClassLoader() {
+        URL[] urlsForClassLoader = new URL[urls.size()];
+        urls.toArray(urlsForClassLoader);
+
+        URLClassLoader classLoader = new URLClassLoader(urlsForClassLoader);
+        loadDrivers(classLoader);
+        return classLoader;
+    }
+
+    private void loadDrivers(URLClassLoader classLoader) {
+        Thread.currentThread().setContextClassLoader(classLoader);
+        try {
+            ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
+            Iterator<Driver> driversIterator = loadedDrivers.iterator();
+            try {
+                while (driversIterator.hasNext()) {
+                    driversIterator.next();
+                }
+            } catch (Throwable t) {
+                // Do nothing
+            }
+        } finally {
+            Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
+        }
+    }
+
+    @Override
+    public void addDirectory(File directory) throws MalformedURLException, IOException {
+        if (!directory.exists()) {
+            return;
+        }
+
+        File[] jarFiles = directory.listFiles(new FileFilter() {
+            @Override
+            public boolean accept(File file) {
+                return file.isFile() && file.getName().endsWith(".jar");
+            }
+        });
+
+        for (File file : jarFiles) {
+            addUrl(file.toURI().toURL());
+        }
+    }
+
+    @Override
+    public void addUrl(URL url) throws IOException {
+        if (urls.contains(url)) {
+            return;
+        }
+
+        WorkerLogManager.getSystemLogger().info("Loading file URL: " + url);
+
+        urls.add(url);
+    }
+    private final Set<URL> urls;
+}
diff --git a/src/main/java/com/microsoft/azure/functions/worker/reflect/FactoryClassLoader.java b/src/main/java/com/microsoft/azure/functions/worker/reflect/FactoryClassLoader.java
new file mode 100644
index 0000000..dcb5c86
--- /dev/null
+++ b/src/main/java/com/microsoft/azure/functions/worker/reflect/FactoryClassLoader.java
@@ -0,0 +1,13 @@
+package com.microsoft.azure.functions.worker.reflect;
+
+import org.apache.commons.lang3.SystemUtils;
+
+public class FactoryClassLoader {
+    public ClassLoaderProvider createClassLoaderProvider(){
+        if(SystemUtils.IS_JAVA_1_8) {
+            return new DefaultClassLoaderProvider();
+        } else {
+            return new EnhancedClassLoaderProvider();
+        }
+    }
+}


Test patch:
diff --git a/build-run-tests-pipeline.ps1 b/build-run-tests-pipeline.ps1
new file mode 100644
index 0000000..956b47c
--- /dev/null
+++ b/build-run-tests-pipeline.ps1
@@ -0,0 +1,53 @@
+# A function that checks exit codes and fails script if an error is found
+function StopOnFailedExecution {
+    if ($LastExitCode)
+    {
+        exit $LastExitCode
+    }
+}
+
+function RunTest([string] $project, [string] $description,[bool] $skipBuild = $false, $filter = $null) {
+    Write-Host "Running test: $description" -ForegroundColor DarkCyan
+    Write-Host "-----------------------------------------------------------------------------" -ForegroundColor DarkCyan
+    Write-Host
+
+    $cmdargs = "test", "$project", "-v", "q", "-l", "trx", "-r",".\testResults"
+    
+    if ($filter) {
+       $cmdargs += "--filter", "$filter"
+    }
+
+    & dotnet $cmdargs | Out-Host
+    $r = $?
+    
+    Write-Host
+    Write-Host "-----------------------------------------------------------------------------" -ForegroundColor DarkCyan
+    Write-Host
+
+    return $r
+}
+
+$currDir =  Get-Location
+
+Write-Host "Building endtoendtests...."
+$Env:Path = $Env:Path+";$currDir\Azure.Functions.Cli"
+Push-Location -Path "./endtoendtests" -StackName javaWorkerDir
+Write-Host "Building azure-functions-maven-com.microsoft.azure.functions.endtoendtests"
+cmd.exe /c '.\..\mvnBuildSkipTests.bat'
+StopOnFailedExecution
+Pop-Location -StackName "javaWorkerDir"
+
+$tests = @(
+  @{project ="endtoendtests\Azure.Functions.Java.Tests.E2E\Azure.Functions.Java.Tests.E2E\Azure.Functions.Java.Tests.E2E.csproj"; description="E2E integration tests"}
+)
+
+$success = $true
+$testRunSucceeded = $true
+
+foreach ($test in $tests){
+    $testRunSucceeded = RunTest $test.project $test.description $testRunSucceeded $test.filter
+    $success = $testRunSucceeded -and $success
+}
+
+if (-not $success) { exit 1 }
+
diff --git a/endtoendtests/pom.xml b/endtoendtests/pom.xml
index 8edecac..f0edcf2 100644
--- a/endtoendtests/pom.xml
+++ b/endtoendtests/pom.xml
@@ -67,6 +67,34 @@
 			<groupId>com.microsoft.azure.functions</groupId>
 			<artifactId>azure-functions-java-library</artifactId>
 		</dependency>
+		<dependency>
+			<groupId>org.apache.httpcomponents</groupId>
+			<artifactId>httpclient</artifactId>
+			<version>4.5.9</version>
+		</dependency>
+		<dependency>
+			<groupId>com.google.guava</groupId>
+			<artifactId>guava</artifactId>
+			<version>28.1-jre</version>
+		</dependency>
+		<dependency>
+			<groupId>com.h2database</groupId>
+			<artifactId>h2</artifactId>
+			<version>1.4.199</version>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>com.google.code.gson</groupId>
+			<artifactId>gson</artifactId>
+			<version>2.8.6</version>
+		</dependency>
+		<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-lang3</artifactId>
+			<version>3.10</version>
+		</dependency>
+
 	</dependencies>
 
 	<build>
diff --git a/endtoendtests/src/main/java/com/microsoft/azure/functions/endtoend/HttpTriggerTests.java b/endtoendtests/src/main/java/com/microsoft/azure/functions/endtoend/HttpTriggerTests.java
index b67c283..cf57768 100644
--- a/endtoendtests/src/main/java/com/microsoft/azure/functions/endtoend/HttpTriggerTests.java
+++ b/endtoendtests/src/main/java/com/microsoft/azure/functions/endtoend/HttpTriggerTests.java
@@ -4,6 +4,23 @@ import com.microsoft.azure.functions.annotation.*;
 import com.microsoft.azure.functions.*;
 import java.util.*;
 
+import com.google.gson.Gson;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.Statement;
+
+import java.io.InputStream;
+import com.google.common.io.CharStreams;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import org.apache.commons.lang3.SystemUtils;
+
 /**
  * Azure Functions with HTTP trigger.
  */
@@ -15,7 +32,7 @@ public class HttpTriggerTests {
     public HttpResponseMessage HttpTriggerJava(
         @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
         final ExecutionContext context
-    ) {
+    ) throws Exception {
         context.getLogger().info("Java HTTP trigger processed a request.");
 
         // Parse query parameters
@@ -23,6 +40,20 @@ public class HttpTriggerTests {
         String name = request.getBody().orElse(query);
         String readEnv = System.getenv("AzureWebJobsStorage");
 
+        try (Connection connection = DriverManager.getConnection("jdbc:h2:mem:test")) {
+            try (Statement statement = connection.createStatement()) {
+                statement.execute("select 1");
+            }
+        }
+
+        Gson a = new Gson();
+
+//        if(!SystemUtils.IS_JAVA_15) {
+//            context.getLogger().info("Java version not 15");
+//        }
+
+        get("https://httpstat.us/200");
+
         if (name == null ) {
             return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build();
         }
@@ -32,6 +63,18 @@ public class HttpTriggerTests {
         return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
     }
 
+    private static String get(String url) throws IOException {
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        HttpGet httpGet = new HttpGet(url);
+        httpGet.setHeader("Accept", "application/json");
+        HttpResponse response = httpClient.execute(httpGet);
+        InputStream content = response.getEntity().getContent();
+        String body = CharStreams.toString(new InputStreamReader(content));
+        content.close();
+        httpClient.close();
+        return "Response from " + url + " was: " + body;
+    }
+
     @FunctionName("HttpTriggerJavaThrows")
     public HttpResponseMessage HttpTriggerThrows(
         @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
diff --git a/setup-tests-pipeline.ps1 b/setup-tests-pipeline.ps1
new file mode 100644
index 0000000..d03017b
--- /dev/null
+++ b/setup-tests-pipeline.ps1
@@ -0,0 +1,39 @@
+Write-Host "$args[0]"
+Write-Host $args[0]
+
+$skipCliDownload = $false
+if($args[0])
+{
+  $skipCliDownload = $args[0]
+}
+Write-Host $skipCliDownload
+
+$currDir =  Get-Location
+if(!$skipCliDownload)
+{
+  Write-Host "Deleting Functions Core Tools if exists...."
+  Remove-Item -Force ./Azure.Functions.Cli.zip -ErrorAction Ignore
+  Remove-Item -Recurse -Force ./Azure.Functions.Cli -ErrorAction Ignore
+
+  Write-Host "Downloading Functions Core Tools...."
+  Invoke-RestMethod -Uri 'https://functionsclibuilds.blob.core.windows.net/builds/3/latest/version.txt' -OutFile version.txt
+  Write-Host "Using Functions Core Tools version: $(Get-Content -Raw version.txt)"
+  $version = "$(Get-Content -Raw version.txt)"
+  Remove-Item version.txt
+
+  if ($version -and $version.trim())
+  {
+    $env:CORE_TOOLS_URL = "https://functionsclibuilds.blob.core.windows.net/builds/3/latest/Azure.Functions.Cli.win-x86.zip"
+  }
+  Write-Host "CORE_TOOLS_URL: $env:CORE_TOOLS_URL"
+  $output = "$currDir\Azure.Functions.Cli.zip"
+  $wc = New-Object System.Net.WebClient
+  $wc.DownloadFile($env:CORE_TOOLS_URL, $output)
+
+  Write-Host "Extracting Functions Core Tools...."
+  Expand-Archive ".\Azure.Functions.Cli.zip" -DestinationPath ".\Azure.Functions.Cli"
+}
+Write-Host "Copying azure-functions-java-worker to  Functions Host workers directory...."
+Get-ChildItem -Path .\target\* -Include 'azure*' -Exclude '*shaded.jar','*tests.jar' | %{ Copy-Item $_.FullName ".\Azure.Functions.Cli\workers\java\azure-functions-java-worker.jar" }
+Copy-Item ".\worker.config.json" ".\Azure.Functions.Cli\workers\java"
+
diff --git a/setup-tests.ps1 b/setup-tests.ps1
index 3fae4bc..eb81225 100644
--- a/setup-tests.ps1
+++ b/setup-tests.ps1
@@ -1,9 +1,9 @@
 
 # A function that checks exit codes and fails script if an error is found 
 function StopOnFailedExecution {
-  if ($LastExitCode) 
-  { 
-    exit $LastExitCode 
+  if ($LastExitCode)
+  {
+    exit $LastExitCode
   }
 }
 Write-Host "$args[0]"
@@ -24,13 +24,14 @@ if(!$skipCliDownload)
   Remove-Item -Recurse -Force ./Azure.Functions.Cli -ErrorAction Ignore
 
   Write-Host "Downloading Functions Core Tools...."
-  Invoke-RestMethod -Uri 'https://functionsclibuilds.blob.core.windows.net/builds/2/latest/version.txt' -OutFile version.txt
+  Invoke-RestMethod -Uri 'https://functionsclibuilds.blob.core.windows.net/builds/3/latest/version.txt' -OutFile version.txt
   Write-Host "Using Functions Core Tools version: $(Get-Content -Raw version.txt)"
+  $version = "$(Get-Content -Raw version.txt)"
   Remove-Item version.txt
 
-  if (-not (Test-Path env:CORE_TOOLS_URL)) 
-  { 
-    $env:CORE_TOOLS_URL = "https://functionsclibuilds.blob.core.windows.net/builds/2/latest/Azure.Functions.Cli.win-x86.zip"
+  if ($version -and $version.trim())
+  {
+    $env:CORE_TOOLS_URL = "https://functionsclibuilds.blob.core.windows.net/builds/3/latest/Azure.Functions.Cli.win-x86.zip"
   }
   Write-Host "CORE_TOOLS_URL: $env:CORE_TOOLS_URL"
   $output = "$currDir\Azure.Functions.Cli.zip"
@@ -41,13 +42,13 @@ if(!$skipCliDownload)
   Expand-Archive ".\Azure.Functions.Cli.zip" -DestinationPath ".\Azure.Functions.Cli"
 }
 Write-Host "Copying azure-functions-java-worker to  Functions Host workers directory...."
-Get-ChildItem -Path .\target\* -Include 'azure*' -Exclude '*shaded.jar' | %{ Copy-Item $_.FullName ".\Azure.Functions.Cli\workers\java\azure-functions-java-worker.jar" }
+Get-ChildItem -Path .\target\* -Include 'azure*' -Exclude '*shaded.jar','*tests.jar' | %{ Copy-Item $_.FullName ".\Azure.Functions.Cli\workers\java\azure-functions-java-worker.jar" }
 Copy-Item ".\worker.config.json" ".\Azure.Functions.Cli\workers\java"
 
 Write-Host "Building endtoendtests...."
 $Env:Path = $Env:Path+";$currDir\Azure.Functions.Cli"
 Push-Location -Path "./endtoendtests" -StackName javaWorkerDir
-Write-Host "Building azure-functions-maven-com.microsoft.azure.functions.endtoendtests" 
+Write-Host "Building azure-functions-maven-com.microsoft.azure.functions.endtoendtests"
 cmd.exe /c '.\..\mvnBuildSkipTests.bat'
 StopOnFailedExecution
 Pop-Location -StackName "javaWorkerDir"
\ No newline at end of file
diff --git a/src/test/java/com/microsoft/azure/functions/worker/broker/tests/JavaMethodExecutorTests.java b/src/test/java/com/microsoft/azure/functions/worker/broker/tests/JavaMethodExecutorTests.java
index b9750d2..c1bad3a 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/broker/tests/JavaMethodExecutorTests.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/broker/tests/JavaMethodExecutorTests.java
@@ -14,29 +14,59 @@ import com.microsoft.azure.functions.worker.reflect.*;
 public class JavaMethodExecutorTests {
 	
 	@Test    
-    public void functionMethodLoadSucceeds() throws Exception {
+    public void functionMethodLoadSucceeds_8() throws Exception {
 		FunctionMethodDescriptor descriptor = new FunctionMethodDescriptor("testid", "TestHttpTrigger","com.microsoft.azure.functions.worker.broker.tests.TestFunctionsClass.TestHttpTrigger","TestFunctionsClass.jar");
 		Map<String, BindingInfo> bindings = new HashMap<>();
 		bindings.put("$return", BindingInfo.newBuilder().setDirection(BindingInfo.Direction.out).build());
-		JavaMethodExecutor executor = new JavaMethodExecutor(descriptor, bindings, new DefaultClassLoaderProvider());
+		JavaMethodExecutor executor = new FactoryJavaMethodExecutor().getJavaMethodExecutor(descriptor, bindings, new FactoryClassLoader().createClassLoaderProvider());
 		assertTrue(executor.getOverloadResolver().hasCandidates());
 		assertFalse(executor.getOverloadResolver().hasMultipleCandidates());
     }
 	
 	@Test(expected = NoSuchMethodException.class)   
-    public void functionMethod_doesnotexist_LoadFails() throws Exception {
+    public void functionMethod_doesnotexist_LoadFails_8() throws Exception {
 		FunctionMethodDescriptor descriptor = new FunctionMethodDescriptor("testid", "TestHttpTrigger1","com.microsoft.azure.functions.worker.broker.tests.TestFunctionsClass.TestHttpTrigger1","TestFunctionsClass.jar");
 		Map<String, BindingInfo> bindings = new HashMap<>();
 		bindings.put("$return", BindingInfo.newBuilder().setDirection(BindingInfo.Direction.out).build());
-		JavaMethodExecutor executor = new JavaMethodExecutor(descriptor, bindings, new DefaultClassLoaderProvider());	
+		JavaMethodExecutor executor = new FactoryJavaMethodExecutor().getJavaMethodExecutor(descriptor, bindings, new FactoryClassLoader().createClassLoaderProvider());
 		
     }
 	
 	@Test(expected = UnsupportedOperationException.class)   
-    public void functionMethod_DuplicateAnnotations_LoadFails() throws Exception {
+    public void functionMethod_DuplicateAnnotations_LoadFails_8() throws Exception {
 		FunctionMethodDescriptor descriptor = new FunctionMethodDescriptor("testid", "TestHttpTriggerOverload","com.microsoft.azure.functions.worker.broker.tests.TestFunctionsClass.TestHttpTriggerOverload","TestFunctionsClass.jar");
 		Map<String, BindingInfo> bindings = new HashMap<>();
 		bindings.put("$return", BindingInfo.newBuilder().setDirection(BindingInfo.Direction.out).build());
-		JavaMethodExecutor executor = new JavaMethodExecutor(descriptor, bindings, new DefaultClassLoaderProvider());	
+		JavaMethodExecutor executor = new FactoryJavaMethodExecutor().getJavaMethodExecutor(descriptor, bindings, new FactoryClassLoader().createClassLoaderProvider());
     }
+
+	@Test
+	public void functionMethodLoadSucceeds_11() throws Exception {
+		FunctionMethodDescriptor descriptor = new FunctionMethodDescriptor("testid", "TestHttpTrigger","com.microsoft.azure.functions.worker.broker.tests.TestFunctionsClass.TestHttpTrigger","TestFunctionsClass.jar");
+		Map<String, BindingInfo> bindings = new HashMap<>();
+		bindings.put("$return", BindingInfo.newBuilder().setDirection(BindingInfo.Direction.out).build());
+		System.setProperty("java.specification.version", "11");
+		JavaMethodExecutor executor = new FactoryJavaMethodExecutor().getJavaMethodExecutor(descriptor, bindings, new FactoryClassLoader().createClassLoaderProvider());
+		assertTrue(executor.getOverloadResolver().hasCandidates());
+		assertFalse(executor.getOverloadResolver().hasMultipleCandidates());
+	}
+
+	@Test(expected = NoSuchMethodException.class)
+	public void functionMethod_doesnotexist_LoadFails_11() throws Exception {
+		System.setProperty("java.specification.version", "11");
+		FunctionMethodDescriptor descriptor = new FunctionMethodDescriptor("testid", "TestHttpTrigger1","com.microsoft.azure.functions.worker.broker.tests.TestFunctionsClass.TestHttpTrigger1","TestFunctionsClass.jar");
+		Map<String, BindingInfo> bindings = new HashMap<>();
+		bindings.put("$return", BindingInfo.newBuilder().setDirection(BindingInfo.Direction.out).build());
+		JavaMethodExecutor executor = new FactoryJavaMethodExecutor().getJavaMethodExecutor(descriptor, bindings, new FactoryClassLoader().createClassLoaderProvider());
+
+	}
+
+	@Test(expected = UnsupportedOperationException.class)
+	public void functionMethod_DuplicateAnnotations_LoadFails_11() throws Exception {
+		System.setProperty("java.specification.version", "11");
+		FunctionMethodDescriptor descriptor = new FunctionMethodDescriptor("testid", "TestHttpTriggerOverload","com.microsoft.azure.functions.worker.broker.tests.TestFunctionsClass.TestHttpTriggerOverload","TestFunctionsClass.jar");
+		Map<String, BindingInfo> bindings = new HashMap<>();
+		bindings.put("$return", BindingInfo.newBuilder().setDirection(BindingInfo.Direction.out).build());
+		JavaMethodExecutor executor = new FactoryJavaMethodExecutor().getJavaMethodExecutor(descriptor, bindings, new FactoryClassLoader().createClassLoaderProvider());
+	}
 }