Repository: Azure/azure-functions-java-worker
Pull request #649 (2022-09-16 15:31:28)

Revert "migrate java8 to java11"
Reverts Azure/azure-functions-java-worker#636


Patch:
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 389db3c..b322ca6 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -126,7 +126,6 @@ jobs:
         displayName: 'Install NuGet Tool'
       - pwsh: |
           Get-Command mvn
-          mvn -version
         displayName: 'Check Maven is installed'
       - task: JavaToolInstaller@0 # This step is necessary as Linux image has Java 11 as default
         inputs:
@@ -150,7 +149,7 @@ jobs:
           curl -sSL https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain/dotnet-install.sh | bash /dev/stdin -v '6.0.100-rc.2.21505.57' -c 'release' --install-dir /usr/share/dotnet
         displayName: 'Install the .Net version used by the Core Tools for Linux'
         condition: eq( variables['Agent.OS'], 'Linux' )
-      - pwsh: | # Download JDK for later installation
+      - pwsh: | # Download JDK for later installation 
           Invoke-WebRequest $(JDK_DOWNLOAD_LINK) -O "$(JAVA_VERSION).tar.gz"
           $current = get-location | select -ExpandProperty Path
           Write-Host "##vso[task.setvariable variable=downloadPath;]$current"
diff --git a/package-pipeline.ps1 b/package-pipeline.ps1
index e64cb8e..3122935 100644
--- a/package-pipeline.ps1
+++ b/package-pipeline.ps1
@@ -13,10 +13,6 @@ Write-Host "Building azure-functions-java-worker"
 mvn clean package --no-transfer-progress -B
 StopOnFailedExecution
 
-Write-Host "Running Integration tests of azure-functions-java-worker"
-mvn failsafe:integration-test --no-transfer-progress -B
-StopOnFailedExecution
-
 Write-Host "Creating nuget package Microsoft.Azure.Functions.JavaWorker" 
 Write-Host "buildNumber: " $buildNumber
 Get-Command nuget
diff --git a/pom.xml b/pom.xml
index 371cb7f..52d005b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -291,23 +291,6 @@
 					</execution>
 				</executions>
 			</plugin>
-			<plugin>
-				<artifactId>maven-failsafe-plugin</artifactId>
-				<version>2.22.2</version>
-				<configuration>
-					<systemPropertyVariables>
-						<testing-project-jar>${project.artifactId}-${project.version}-tests.jar</testing-project-jar>
-					</systemPropertyVariables>
-				</configuration>
-				<executions>
-					<execution>
-						<goals>
-							<goal>integration-test</goal>
-							<goal>verify</goal>
-						</goals>
-					</execution>
-				</executions>
-			</plugin>
 
 			<!-- This plugin is used to generated test jar which contains all test classes -->
 			<plugin>
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 8f52568..211d18b 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 FunctionClassLoaderProvider();
+        this.classPathProvider = new FactoryClassLoader().createClassLoaderProvider();
         
         this.addHandlers();
     }
diff --git a/src/main/java/com/microsoft/azure/functions/worker/util/Util.java b/src/main/java/com/microsoft/azure/functions/worker/Util.java
similarity index 85%
rename from src/main/java/com/microsoft/azure/functions/worker/util/Util.java
rename to src/main/java/com/microsoft/azure/functions/worker/Util.java
index cadd425..2b083ed 100644
--- a/src/main/java/com/microsoft/azure/functions/worker/util/Util.java
+++ b/src/main/java/com/microsoft/azure/functions/worker/Util.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.util;
+package com.microsoft.azure.functions.worker;
 
 public class Util {
     public static boolean isTrue(String value) {
diff --git a/src/main/java/com/microsoft/azure/functions/worker/broker/FunctionMethodExecutorImpl.java b/src/main/java/com/microsoft/azure/functions/worker/broker/EnhancedJavaMethodExecutorImpl.java
similarity index 92%
rename from src/main/java/com/microsoft/azure/functions/worker/broker/FunctionMethodExecutorImpl.java
rename to src/main/java/com/microsoft/azure/functions/worker/broker/EnhancedJavaMethodExecutorImpl.java
index c4a4da1..2a6a031 100644
--- a/src/main/java/com/microsoft/azure/functions/worker/broker/FunctionMethodExecutorImpl.java
+++ b/src/main/java/com/microsoft/azure/functions/worker/broker/EnhancedJavaMethodExecutorImpl.java
@@ -12,8 +12,8 @@ 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 FunctionMethodExecutorImpl implements JavaMethodExecutor {
-    public FunctionMethodExecutorImpl(FunctionMethodDescriptor descriptor, Map<String, BindingInfo> bindingInfos, ClassLoaderProvider classLoaderProvider)
+public class EnhancedJavaMethodExecutorImpl implements JavaMethodExecutor {
+    public EnhancedJavaMethodExecutorImpl(FunctionMethodDescriptor descriptor, Map<String, BindingInfo> bindingInfos, ClassLoaderProvider classLoaderProvider)
             throws ClassNotFoundException, NoSuchMethodException
     {
         descriptor.validateMethodInfo();
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 52ae9ba..7a10ac1 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
@@ -10,6 +10,7 @@ import java.util.concurrent.ConcurrentHashMap;
 
 import com.microsoft.azure.functions.rpc.messages.*;
 import com.microsoft.azure.functions.worker.Constants;
+import com.microsoft.azure.functions.worker.WorkerLogManager;
 import com.microsoft.azure.functions.worker.binding.BindingDataStore;
 import com.microsoft.azure.functions.worker.binding.ExecutionRetryContext;
 import com.microsoft.azure.functions.worker.binding.ExecutionTraceContext;
@@ -34,7 +35,7 @@ public class JavaFunctionBroker {
 		descriptor.validate();
 
 		addSearchPathsToClassLoader(descriptor);
-		JavaMethodExecutor executor = new FunctionMethodExecutorImpl(descriptor, bindings, classLoaderProvider);
+		JavaMethodExecutor executor = new FactoryJavaMethodExecutor().getJavaMethodExecutor(descriptor, bindings, classLoaderProvider);
 
 		this.methods.put(descriptor.getId(), new ImmutablePair<>(descriptor.getName(), executor));
 	}
@@ -147,6 +148,22 @@ public class JavaFunctionBroker {
 		}
 	}
 
+	void verifyLibrariesExist (File workerLib, String workerLibPath) throws FileNotFoundException{
+		if(!workerLib.exists()) {
+			throw new FileNotFoundException("Error loading worker jars, from path:  " + workerLibPath);
+		} else {
+			File[] jarFiles = workerLib.listFiles(new FileFilter() {
+				@Override
+				public boolean accept(File file) {
+					return file.isFile() && file.getName().endsWith(".jar");
+				}
+			});
+			if(jarFiles.length == 0) {
+				throw new FileNotFoundException("Error loading worker jars, from path:  " + workerLibPath + ". Jars size is zero");
+			}
+		}
+	}
+
 	public void setWorkerDirectory(String workerDirectory) {
 		this.workerDirectory = workerDirectory;
 	}
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..bad1d2e
--- /dev/null
+++ b/src/main/java/com/microsoft/azure/functions/worker/broker/JavaMethodExecutorImpl.java
@@ -0,0 +1,65 @@
+package com.microsoft.azure.functions.worker.broker;
+
+import java.lang.reflect.*;
+import java.net.*;
+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 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.getDeclaringClass().getName().equals(descriptor.getFullClassName()) && 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/handler/InvocationRequestHandler.java b/src/main/java/com/microsoft/azure/functions/worker/handler/InvocationRequestHandler.java
index d9af149..e46ff66 100644
--- a/src/main/java/com/microsoft/azure/functions/worker/handler/InvocationRequestHandler.java
+++ b/src/main/java/com/microsoft/azure/functions/worker/handler/InvocationRequestHandler.java
@@ -6,7 +6,8 @@ import java.util.logging.*;
 import com.microsoft.azure.functions.worker.*;
 import com.microsoft.azure.functions.worker.broker.*;
 import com.microsoft.azure.functions.rpc.messages.*;
-import com.microsoft.azure.functions.worker.util.Util;
+
+import static com.microsoft.azure.functions.worker.Util.getJavaVersion;
 
 public class InvocationRequestHandler extends MessageHandler<InvocationRequest, InvocationResponse.Builder> {
     public InvocationRequestHandler(JavaFunctionBroker broker) {
@@ -24,7 +25,7 @@ public class InvocationRequestHandler extends MessageHandler<InvocationRequest,
 
     @Override
     String execute(InvocationRequest request, InvocationResponse.Builder response) throws Exception {
-        WorkerLogManager.getSystemLogger().log(Level.INFO, "Java version - " + Util.getJavaVersion());
+        WorkerLogManager.getSystemLogger().log(Level.INFO, "Java version - " + getJavaVersion());
         WorkerLogManager.getSystemLogger().log(Level.INFO, "InvocationRequest received by the Java worker");
         final String functionId = request.getFunctionId();
         final String invocationId = request.getInvocationId();
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
new file mode 100644
index 0000000..fecc55b
--- /dev/null
+++ b/src/main/java/com/microsoft/azure/functions/worker/reflect/DefaultClassLoaderProvider.java
@@ -0,0 +1,78 @@
+package com.microsoft.azure.functions.worker.reflect;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.net.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+import com.microsoft.azure.functions.worker.*;
+
+/**
+ * @author Kevin Hillinger Default implementation of the class loader provider
+ */
+public class DefaultClassLoaderProvider implements ClassLoaderProvider {
+  public DefaultClassLoaderProvider() {
+    customerUrls = Collections.newSetFromMap(new ConcurrentHashMap<URL, Boolean>());
+    workerUrls = Collections.newSetFromMap(new ConcurrentHashMap<URL, Boolean>());
+  }
+
+  /*
+   * @see com.microsoft.azure.functions.reflect.ClassLoaderProvider#createClassLoader()
+   */
+  @Override
+  public ClassLoader createClassLoader() {
+    List<URL> urlsList = new ArrayList<>();
+    urlsList.addAll(customerUrls);
+    urlsList.addAll(workerUrls);
+    URL[] urlsForClassLoader = urlsList.toArray(new URL[0]);
+    URLClassLoader classLoader = new URLClassLoader(urlsForClassLoader);
+    Thread.currentThread().setContextClassLoader(classLoader);
+    return classLoader;
+  }
+
+  @Override
+  public void addCustomerUrl(URL url) throws IOException {
+    if (customerUrls.contains(url)) {
+      return;
+    }
+    WorkerLogManager.getSystemLogger().info("Loading customer file URL: " + url);
+    customerUrls.add(url);
+    addUrlToSystemClassLoader(url);
+  }
+
+  @Override
+  public void addWorkerUrl(URL url) throws IOException {
+    if (workerUrls.contains(url)) {
+      return;
+    }
+    WorkerLogManager.getSystemLogger().info("Loading worker file URL: " + url);
+    workerUrls.add(url);
+    addUrlToSystemClassLoader(url);
+  }
+
+  public static boolean isUrlPointingToAFile(URL url) throws UnsupportedEncodingException {
+    String decodedPath = URLDecoder.decode(url.getPath(), "UTF-8");
+    File file = new File(decodedPath);
+    return file.exists();
+  }
+
+  private void addUrlToSystemClassLoader(URL url) throws IOException {
+    URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
+    Class<?> sysclass = URLClassLoader.class;
+
+    try {
+      Method method = sysclass.getDeclaredMethod(SYS_LOADER_ADDURL_METHOD_NAME, parameters);
+      method.setAccessible(true);
+      method.invoke(sysloader, new Object[] { url });
+    } catch (Throwable t) {
+      throw new IOException("Error adding " + url + " to system classloader");
+    }
+
+  }
+
+  private static final String SYS_LOADER_ADDURL_METHOD_NAME = "addURL";
+  private static final Class<?>[] parameters = new Class[] { URL.class };
+  private final Set<URL> customerUrls;
+  private final Set<URL> workerUrls;
+}
diff --git a/src/main/java/com/microsoft/azure/functions/worker/reflect/FunctionClassLoaderProvider.java b/src/main/java/com/microsoft/azure/functions/worker/reflect/EnhancedClassLoaderProvider.java
similarity index 94%
rename from src/main/java/com/microsoft/azure/functions/worker/reflect/FunctionClassLoaderProvider.java
rename to src/main/java/com/microsoft/azure/functions/worker/reflect/EnhancedClassLoaderProvider.java
index 141c46c..77647b2 100644
--- a/src/main/java/com/microsoft/azure/functions/worker/reflect/FunctionClassLoaderProvider.java
+++ b/src/main/java/com/microsoft/azure/functions/worker/reflect/EnhancedClassLoaderProvider.java
@@ -8,8 +8,8 @@ import java.util.concurrent.*;
 
 import com.microsoft.azure.functions.worker.*;
 
-public class FunctionClassLoaderProvider implements ClassLoaderProvider {
-    public FunctionClassLoaderProvider() {
+public class EnhancedClassLoaderProvider implements ClassLoaderProvider {
+    public EnhancedClassLoaderProvider() {
         customerUrls = Collections.newSetFromMap(new ConcurrentHashMap<URL, Boolean>());
         workerUrls = Collections.newSetFromMap(new ConcurrentHashMap<URL, Boolean>());
     }
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/src/test/java/com/microsoft/azure/functions/worker/util/UtilTests.java b/src/test/java/com/microsoft/azure/functions/worker/UtilTests.java
similarity index 84%
rename from src/test/java/com/microsoft/azure/functions/worker/util/UtilTests.java
rename to src/test/java/com/microsoft/azure/functions/worker/UtilTests.java
index 7328a17..0b47031 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/util/UtilTests.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/UtilTests.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.util;
+package com.microsoft.azure.functions.worker;
 
 import org.junit.Test;
 
diff --git a/src/test/java/com/microsoft/azure/functions/worker/binding/RpcByteArrayDataSourceTest.java b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcByteArrayDataSourceTests.java
similarity index 92%
rename from src/test/java/com/microsoft/azure/functions/worker/binding/RpcByteArrayDataSourceTest.java
rename to src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcByteArrayDataSourceTests.java
index 1444587..fe4c04d 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/binding/RpcByteArrayDataSourceTest.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcByteArrayDataSourceTests.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.binding;
+package com.microsoft.azure.functions.worker.binding.tests;
 
 import static org.junit.Assert.assertEquals;
 
@@ -9,8 +9,10 @@ import org.apache.commons.lang3.ArrayUtils;
 import org.junit.Test;
 
 import com.google.protobuf.ByteString;
+import com.microsoft.azure.functions.worker.binding.BindingData;
+import com.microsoft.azure.functions.worker.binding.RpcByteArrayDataSource;
 
-public class RpcByteArrayDataSourceTest {
+public class RpcByteArrayDataSourceTests {
 
   @Test
   public void rpcByteArrayDataSource_To_byteArray() {
diff --git a/src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionByteArrayDataSourceTest.java b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionByteArrayDataSourceTest.java
similarity index 99%
rename from src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionByteArrayDataSourceTest.java
rename to src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionByteArrayDataSourceTest.java
index 73715a6..53c582d 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionByteArrayDataSourceTest.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionByteArrayDataSourceTest.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.binding;
+package com.microsoft.azure.functions.worker.binding.tests;
 
 import com.google.protobuf.ByteString;
 import com.microsoft.azure.functions.worker.binding.BindingData;
diff --git a/src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionDoubleDataSourceTest.java b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionDoubleDataSourceTest.java
similarity index 98%
rename from src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionDoubleDataSourceTest.java
rename to src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionDoubleDataSourceTest.java
index 732d5f0..78f39af 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionDoubleDataSourceTest.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionDoubleDataSourceTest.java
@@ -1,5 +1,5 @@
 
-package com.microsoft.azure.functions.worker.binding;
+package com.microsoft.azure.functions.worker.binding.tests;
 
 import com.microsoft.azure.functions.rpc.messages.CollectionDouble;
 import com.microsoft.azure.functions.worker.binding.BindingData;
diff --git a/src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionLongDataSourceTest.java b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionLongDataSourceTest.java
similarity index 98%
rename from src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionLongDataSourceTest.java
rename to src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionLongDataSourceTest.java
index 58ed16f..a48f078 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionLongDataSourceTest.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionLongDataSourceTest.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.binding;
+package com.microsoft.azure.functions.worker.binding.tests;
 
 import com.microsoft.azure.functions.rpc.messages.CollectionSInt64;
 import com.microsoft.azure.functions.rpc.messages.CollectionSInt64.Builder;
diff --git a/src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionStringDataSourceTest.java b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionStringDataSourceTest.java
similarity index 98%
rename from src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionStringDataSourceTest.java
rename to src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionStringDataSourceTest.java
index c9445a5..114a046 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionStringDataSourceTest.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionStringDataSourceTest.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.binding;
+package com.microsoft.azure.functions.worker.binding.tests;
 
 import com.microsoft.azure.functions.rpc.messages.CollectionString.Builder;
 import com.microsoft.azure.functions.rpc.messages.CollectionString;
diff --git a/src/test/java/com/microsoft/azure/functions/worker/binding/RpcHttpRequestDataSourceTest.java b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcHttpRequestDataSourceTests.java
similarity index 92%
rename from src/test/java/com/microsoft/azure/functions/worker/binding/RpcHttpRequestDataSourceTest.java
rename to src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcHttpRequestDataSourceTests.java
index 8fb4ee2..6cf11b5 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/binding/RpcHttpRequestDataSourceTest.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcHttpRequestDataSourceTests.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.binding;
+package com.microsoft.azure.functions.worker.binding.tests;
 
 import static org.junit.Assert.assertEquals;
 
@@ -11,8 +11,9 @@ import com.microsoft.azure.functions.HttpRequestMessage;
 import com.microsoft.azure.functions.HttpStatus;
 import com.microsoft.azure.functions.rpc.messages.RpcHttp;
 import com.microsoft.azure.functions.rpc.messages.TypedData;
+import com.microsoft.azure.functions.worker.binding.*;
 
-public class RpcHttpRequestDataSourceTest {
+public class RpcHttpRequestDataSourceTests {
 
   public void HttpRequestStringBody(HttpRequestMessage<String> request) {
   }
@@ -91,8 +92,8 @@ public class RpcHttpRequestDataSourceTest {
   }
 
   private Method getFunctionMethod(String methodName) {
-    RpcHttpRequestDataSourceTest httpDataSourceTests = new RpcHttpRequestDataSourceTest();
-    Class<? extends RpcHttpRequestDataSourceTest> httpDataSourceTestsClass = httpDataSourceTests
+    RpcHttpRequestDataSourceTests httpDataSourceTests = new RpcHttpRequestDataSourceTests();
+    Class<? extends RpcHttpRequestDataSourceTests> httpDataSourceTestsClass = httpDataSourceTests
         .getClass();
     Method[] methods = httpDataSourceTestsClass.getMethods();
     Method functionMethod = null;
diff --git a/src/test/java/com/microsoft/azure/functions/worker/binding/RpcIntegerDataSourceTest.java b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcIntegerDataSourceTests.java
similarity index 79%
rename from src/test/java/com/microsoft/azure/functions/worker/binding/RpcIntegerDataSourceTest.java
rename to src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcIntegerDataSourceTests.java
index 061c77d..0e74301 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/binding/RpcIntegerDataSourceTest.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcIntegerDataSourceTests.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.binding;
+package com.microsoft.azure.functions.worker.binding.tests;
 
 import static org.junit.Assert.assertEquals;
 
@@ -7,7 +7,10 @@ import java.util.Optional;
 
 import org.junit.Test;
 
-public class RpcIntegerDataSourceTest {
+import com.microsoft.azure.functions.worker.binding.BindingData;
+import com.microsoft.azure.functions.worker.binding.RpcIntegerDataSource;
+
+public class RpcIntegerDataSourceTests {
 
 	@Test
 	public void rpcIntegerDataSource_To_Integer() {
diff --git a/src/test/java/com/microsoft/azure/functions/worker/binding/RpcStringDataSourceTest.java b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcStringDataSourceTests.java
similarity index 93%
rename from src/test/java/com/microsoft/azure/functions/worker/binding/RpcStringDataSourceTest.java
rename to src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcStringDataSourceTests.java
index fe3b0fb..b786e76 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/binding/RpcStringDataSourceTest.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcStringDataSourceTests.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.binding;
+package com.microsoft.azure.functions.worker.binding.tests;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -14,8 +14,11 @@ import java.util.Optional;
 import org.junit.Test;
 
 import com.google.gson.JsonSyntaxException;
+import com.microsoft.azure.functions.worker.binding.BindingData;
+import com.microsoft.azure.functions.worker.binding.RpcJsonDataSource;
+import com.microsoft.azure.functions.worker.binding.RpcStringDataSource;
 
-public class RpcStringDataSourceTest {
+public class RpcStringDataSourceTests {
 
 	public static class TestPOJO {
 		public Integer id;
@@ -148,8 +151,8 @@ public class RpcStringDataSourceTest {
 	}
 
 	private static Type getParameterType(String functionName) {
-		RpcStringDataSourceTest stringDataSourceTests = new RpcStringDataSourceTest();
-		Class<? extends RpcStringDataSourceTest> stringDataSourceTestsClass = stringDataSourceTests.getClass();
+		RpcStringDataSourceTests stringDataSourceTests = new RpcStringDataSourceTests();
+		Class<? extends RpcStringDataSourceTests> stringDataSourceTestsClass = stringDataSourceTests.getClass();
 		Method[] methods = stringDataSourceTestsClass.getMethods();
 		Method functionWithStringListInputMethod = null;
 		for (Method method : methods) {
diff --git a/src/test/java/com/microsoft/azure/functions/worker/broker/JavaFunctionBrokerTest.java b/src/test/java/com/microsoft/azure/functions/worker/broker/JavaFunctionBrokerTest.java
index 732544e..231c1d6 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/broker/JavaFunctionBrokerTest.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/broker/JavaFunctionBrokerTest.java
@@ -3,7 +3,7 @@ package com.microsoft.azure.functions.worker.broker;
 import com.microsoft.azure.functions.rpc.messages.InvocationRequest;
 import com.microsoft.azure.functions.rpc.messages.ParameterBinding;
 import com.microsoft.azure.functions.rpc.messages.TypedData;
-import com.microsoft.azure.functions.worker.reflect.FunctionClassLoaderProvider;
+import com.microsoft.azure.functions.worker.reflect.DefaultClassLoaderProvider;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -43,7 +43,7 @@ public class JavaFunctionBrokerTest {
         when(bindingData.getString()).thenReturn(expectedData);
         when(binding.getName()).thenReturn(expectedName);
         when(binding.getData()).thenReturn(bindingData);
-        when(request.getInputDataList()).thenReturn(Collections.singletonList(binding));
+        when(request.getInputDataList()).thenReturn(Arrays.asList(binding));
 
         lenient().when(name.getString()).thenReturn("string: \"John\"\n");
         lenient().when(query.getString()).thenReturn("json: \"{\"name\":\"ushio\"}\"");
@@ -57,7 +57,7 @@ public class JavaFunctionBrokerTest {
         triggerMetadata.put("sys", sys);
         when(request.getTriggerMetadataMap()).thenReturn(Collections.unmodifiableMap(triggerMetadata));
 
-        JavaFunctionBroker broker = new JavaFunctionBroker(new FunctionClassLoaderProvider());
+        JavaFunctionBroker broker = new JavaFunctionBroker(new DefaultClassLoaderProvider());
         Map<String, TypedData> actualTriggerMetadata = broker.getTriggerMetadataMap(request);
         TypedData actual = actualTriggerMetadata.get("$request");
         assertEquals(actual.getString(), expectedData);
@@ -74,7 +74,7 @@ public class JavaFunctionBrokerTest {
         lenient().when(bindingData.getString()).thenReturn(data);
         lenient().when(binding.getName()).thenReturn(name);
         when(binding.getData()).thenReturn(bindingData);
-        when(request.getInputDataList()).thenReturn(Collections.singletonList(binding));
+        when(request.getInputDataList()).thenReturn(Arrays.asList(binding));
 
         lenient().when(queueTrigger.getString()).thenReturn("string: \"hello queue\"\n");
         lenient().when(dequeueCount.getString()).thenReturn("json: \"1\"\n");
@@ -97,9 +97,23 @@ public class JavaFunctionBrokerTest {
         when(request.getTriggerMetadataMap()).thenReturn(Collections.unmodifiableMap(triggerMetadata));
 
         int expectedCount = request.getTriggerMetadataMap().size();
-        JavaFunctionBroker broker = new JavaFunctionBroker(new FunctionClassLoaderProvider());
+        JavaFunctionBroker broker = new JavaFunctionBroker(new DefaultClassLoaderProvider());
         Map<String, TypedData> actualTriggerMetadata = broker.getTriggerMetadataMap(request);
         // In case of non-http request, it will not modify the triggerMetadata
         assertEquals(expectedCount, actualTriggerMetadata.size());
     }
+
+    @Test(expected = FileNotFoundException.class)
+    public void checkLibFolderNoWorkerLib() throws Exception {
+        JavaFunctionBroker broker = new JavaFunctionBroker(null);
+        broker.verifyLibrariesExist (new File(""), null);
+    }
+
+    @Test(expected = FileNotFoundException.class)
+    public void checkLibFolderNoJarsInLib() throws Exception {
+        JavaFunctionBroker broker = new JavaFunctionBroker(null);
+        String path = "../";
+        File file = new File(path);
+        broker.verifyLibrariesExist (file, path);
+    }
 }
diff --git a/src/test/java/com/microsoft/azure/functions/worker/broker/JavaMethodExecutorTest.java b/src/test/java/com/microsoft/azure/functions/worker/broker/JavaMethodExecutorTest.java
deleted file mode 100644
index 8c89673..0000000
--- a/src/test/java/com/microsoft/azure/functions/worker/broker/JavaMethodExecutorTest.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.microsoft.azure.functions.worker.broker;
-
-import org.junit.*;
-
-import static junit.framework.TestCase.*;
-
-import java.io.File;
-import java.lang.reflect.Field;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.*;
-
-
-import com.microsoft.azure.functions.rpc.messages.*;
-import com.microsoft.azure.functions.worker.description.*;
-import com.microsoft.azure.functions.worker.reflect.*;
-
-public class JavaMethodExecutorTest {
-
-	private static FunctionClassLoaderProvider functionClassLoaderProvider = new FunctionClassLoaderProvider();
-
-	@BeforeClass
-	public static void setClassLoaderProvider() throws Exception {
-		Field classLoaderInstance = FunctionClassLoaderProvider.class.getDeclaredField("classLoaderInstance");
-		classLoaderInstance.setAccessible(true);
-		classLoaderInstance.set(null, null);
-		String targetPath = JavaMethodExecutorTest.class.getProtectionDomain().getCodeSource().getLocation().getPath();
-		File testJar = new File(targetPath + "/TestFunctionsClass.jar");
-		functionClassLoaderProvider.addCustomerUrl(testJar.toURI().toURL());
-	}
-
-	@Test
-    public void functionMethodLoadSucceeds() 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 FunctionMethodExecutorImpl(descriptor, bindings, functionClassLoaderProvider);
-		assertTrue(executor.getOverloadResolver().hasCandidates());
-		assertFalse(executor.getOverloadResolver().hasMultipleCandidates());
-    }
-
-	@Test(expected = NoSuchMethodException.class)
-    public void functionMethodLoadFails_DoesnotExist() 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 FunctionMethodExecutorImpl(descriptor, bindings, functionClassLoaderProvider);
-    }
-
-	@Test(expected = UnsupportedOperationException.class)
-    public void functionMethodLoadFails_DuplicateAnnotations() 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 FunctionMethodExecutorImpl(descriptor, bindings, functionClassLoaderProvider);
-    }
-}
diff --git a/src/test/java/com/microsoft/azure/functions/worker/broker/CoreTypeResolverTest.java b/src/test/java/com/microsoft/azure/functions/worker/broker/tests/CoreTypeResolverTests.java
similarity index 90%
rename from src/test/java/com/microsoft/azure/functions/worker/broker/CoreTypeResolverTest.java
rename to src/test/java/com/microsoft/azure/functions/worker/broker/tests/CoreTypeResolverTests.java
index dc6640e..1a69120 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/broker/CoreTypeResolverTest.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/broker/tests/CoreTypeResolverTests.java
@@ -1,10 +1,13 @@
-package com.microsoft.azure.functions.worker.broker;
+package com.microsoft.azure.functions.worker.broker.tests;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.*;
 import java.util.*;
 
 import com.microsoft.azure.functions.*;
 import com.microsoft.azure.functions.annotation.*;
+import com.microsoft.azure.functions.worker.binding.tests.RpcHttpRequestDataSourceTests;
+import com.microsoft.azure.functions.worker.broker.CoreTypeResolver;
 
 import org.apache.commons.lang3.StringUtils;
 import org.junit.*;
@@ -13,7 +16,7 @@ import static com.microsoft.azure.functions.worker.broker.CoreTypeResolver.getRu
 import static com.microsoft.azure.functions.worker.broker.CoreTypeResolver.isValidOutputType;
 import static org.junit.Assert.*;
 
-public class CoreTypeResolverTest {
+public class CoreTypeResolverTests {
 
 	public void CustomBinding_Valid(
 			@HttpTrigger(name = "req", methods = { HttpMethod.GET,
@@ -122,7 +125,7 @@ public class CoreTypeResolverTest {
 	}
 
 	private Type returnTypeOf(String type) throws NoSuchMethodException {
-		Method m = CoreTypeResolverTest.class.getDeclaredMethod(type);
+		Method m = CoreTypeResolverTests.class.getDeclaredMethod(type);
 		m.setAccessible(true);
 		return m.getGenericReturnType();
 	}
@@ -150,8 +153,8 @@ public class CoreTypeResolverTest {
 	}
 
 	private Method getFunctionMethod(String methodName) {
-		CoreTypeResolverTest coreTypeResolverTest = new CoreTypeResolverTest();
-		Class<? extends CoreTypeResolverTest> testsClass = coreTypeResolverTest.getClass();
+		CoreTypeResolverTests coreTypeResolverTests = new CoreTypeResolverTests();
+		Class<? extends CoreTypeResolverTests> testsClass = coreTypeResolverTests.getClass();
 		Method[] methods = testsClass.getMethods();
 		Method functionMethod = null;
 		for (Method method : methods) {
diff --git a/src/test/java/com/microsoft/azure/functions/worker/broker/InvalidCustomBinding.java b/src/test/java/com/microsoft/azure/functions/worker/broker/tests/InvalidCustomBinding.java
similarity index 83%
rename from src/test/java/com/microsoft/azure/functions/worker/broker/InvalidCustomBinding.java
rename to src/test/java/com/microsoft/azure/functions/worker/broker/tests/InvalidCustomBinding.java
index 69f8d20..30fa73e 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/broker/InvalidCustomBinding.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/broker/tests/InvalidCustomBinding.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.broker;
+package com.microsoft.azure.functions.worker.broker.tests;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
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
new file mode 100644
index 0000000..c1bad3a
--- /dev/null
+++ b/src/test/java/com/microsoft/azure/functions/worker/broker/tests/JavaMethodExecutorTests.java
@@ -0,0 +1,72 @@
+package com.microsoft.azure.functions.worker.broker.tests;
+
+import org.junit.*;
+
+import static junit.framework.TestCase.*;
+import java.util.*;
+
+
+import com.microsoft.azure.functions.rpc.messages.*;
+import com.microsoft.azure.functions.worker.broker.*;
+import com.microsoft.azure.functions.worker.description.*;
+import com.microsoft.azure.functions.worker.reflect.*;
+
+public class JavaMethodExecutorTests {
+	
+	@Test    
+    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 FactoryJavaMethodExecutor().getJavaMethodExecutor(descriptor, bindings, new FactoryClassLoader().createClassLoaderProvider());
+		assertTrue(executor.getOverloadResolver().hasCandidates());
+		assertFalse(executor.getOverloadResolver().hasMultipleCandidates());
+    }
+	
+	@Test(expected = NoSuchMethodException.class)   
+    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 FactoryJavaMethodExecutor().getJavaMethodExecutor(descriptor, bindings, new FactoryClassLoader().createClassLoaderProvider());
+		
+    }
+	
+	@Test(expected = UnsupportedOperationException.class)   
+    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 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());
+	}
+}
diff --git a/src/test/java/com/microsoft/azure/functions/worker/broker/TestCustomBinding.java b/src/test/java/com/microsoft/azure/functions/worker/broker/tests/TestCustomBinding.java
similarity index 88%
rename from src/test/java/com/microsoft/azure/functions/worker/broker/TestCustomBinding.java
rename to src/test/java/com/microsoft/azure/functions/worker/broker/tests/TestCustomBinding.java
index 2118ace..0113731 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/broker/TestCustomBinding.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/broker/tests/TestCustomBinding.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.broker;
+package com.microsoft.azure.functions.worker.broker.tests;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
diff --git a/src/test/java/com/microsoft/azure/functions/worker/broker/TestCustomBindingNoName.java b/src/test/java/com/microsoft/azure/functions/worker/broker/tests/TestCustomBindingNoName.java
similarity index 88%
rename from src/test/java/com/microsoft/azure/functions/worker/broker/TestCustomBindingNoName.java
rename to src/test/java/com/microsoft/azure/functions/worker/broker/tests/TestCustomBindingNoName.java
index 1e79b1b..296f7cf 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/broker/TestCustomBindingNoName.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/broker/tests/TestCustomBindingNoName.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.broker;
+package com.microsoft.azure.functions.worker.broker.tests;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
diff --git a/src/test/resources/TestFunctionsClass.jar b/src/test/java/com/microsoft/azure/functions/worker/broker/tests/TestFunctionsClass.jar
similarity index 100%
rename from src/test/resources/TestFunctionsClass.jar
rename to src/test/java/com/microsoft/azure/functions/worker/broker/tests/TestFunctionsClass.jar
diff --git a/src/test/java/com/microsoft/azure/functions/worker/broker/tests/TestFunctionsClass.java b/src/test/java/com/microsoft/azure/functions/worker/broker/tests/TestFunctionsClass.java
new file mode 100644
index 0000000..a1bab74
--- /dev/null
+++ b/src/test/java/com/microsoft/azure/functions/worker/broker/tests/TestFunctionsClass.java
@@ -0,0 +1,41 @@
+package com.microsoft.azure.functions.worker.broker.tests;
+
+import java.lang.*;
+import java.util.*;
+import com.microsoft.azure.functions.annotation.*;
+import com.microsoft.azure.functions.*;
+
+/**
+ * Azure Functions with HTTP Trigger.
+ */
+public class TestFunctionsClass
+{
+	
+	public HttpResponseMessage TestHttpTrigger(
+		        @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
+		        final ExecutionContext context
+		    ) {
+		        return request.createResponseBuilder(HttpStatus.OK).build();		        
+		    }
+	
+	public HttpResponseMessage TestHttpTriggerWithOutAnnotation(
+		        @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
+		        final ExecutionContext context
+		    ) {
+		        return request.createResponseBuilder(HttpStatus.OK).build();		        
+		    }
+	
+	public String TestHttpTriggerOverload(
+		        @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) String inputRequest,
+		        final ExecutionContext context
+		    ) {
+		        return "Hello";		        
+		    }
+	
+	public HttpResponseMessage TestHttpTriggerOverload(
+		        @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
+		        final ExecutionContext context
+		    ) {
+		        return request.createResponseBuilder(HttpStatus.OK).build();		        
+		    }
+}
diff --git a/src/test/java/com/microsoft/azure/functions/worker/integration/SimpleParamReturnIT.java b/src/test/java/com/microsoft/azure/functions/worker/functional/tests/SimpleParamReturnTest.java
similarity index 90%
rename from src/test/java/com/microsoft/azure/functions/worker/integration/SimpleParamReturnIT.java
rename to src/test/java/com/microsoft/azure/functions/worker/functional/tests/SimpleParamReturnTest.java
index df2d4dc..92d32c1 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/integration/SimpleParamReturnIT.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/functional/tests/SimpleParamReturnTest.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.integration;
+package com.microsoft.azure.functions.worker.functional.tests;
 
 import com.microsoft.azure.functions.rpc.messages.*;
 import com.microsoft.azure.functions.worker.test.utilities.*;
@@ -10,7 +10,7 @@ import org.junit.runners.Parameterized.Parameter;
 import static org.junit.Assert.*;
 
 @RunWith(Parameterized.class)
-public class SimpleParamReturnIT extends FunctionsTestBase {
+public class SimpleParamReturnTest extends FunctionsTestBase {
 
 	@Parameters
 	public static Object[] data() {
diff --git a/src/test/java/com/microsoft/azure/functions/worker/handler/FunctionEnvironmentReloadRequestHandlerTest.java b/src/test/java/com/microsoft/azure/functions/worker/handler/tests/FunctionEnvironmentReloadRequestHandlerTests.java
similarity index 74%
rename from src/test/java/com/microsoft/azure/functions/worker/handler/FunctionEnvironmentReloadRequestHandlerTest.java
rename to src/test/java/com/microsoft/azure/functions/worker/handler/tests/FunctionEnvironmentReloadRequestHandlerTests.java
index 1549d6a..4793d52 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/handler/FunctionEnvironmentReloadRequestHandlerTest.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/handler/tests/FunctionEnvironmentReloadRequestHandlerTests.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.handler;
+package com.microsoft.azure.functions.worker.handler.tests;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -7,16 +7,17 @@ import static org.junit.Assert.assertNull;
 import java.util.HashMap;
 import java.util.Map;
 
-import com.microsoft.azure.functions.worker.reflect.FunctionClassLoaderProvider;
 import org.junit.Test;
 
 import com.microsoft.azure.functions.worker.broker.JavaFunctionBroker;
+import com.microsoft.azure.functions.worker.handler.FunctionEnvironmentReloadRequestHandler;
+import com.microsoft.azure.functions.worker.reflect.DefaultClassLoaderProvider;
 
-public class FunctionEnvironmentReloadRequestHandlerTest {
+public class FunctionEnvironmentReloadRequestHandlerTests {
 
 	@Test
 	public void SetEnv_Succeeds() throws Exception {
-		FunctionClassLoaderProvider classLoader = new FunctionClassLoaderProvider();
+		DefaultClassLoaderProvider classLoader = new DefaultClassLoaderProvider();
 		JavaFunctionBroker broker = new JavaFunctionBroker(classLoader);
 		FunctionEnvironmentReloadRequestHandler envHandler = new FunctionEnvironmentReloadRequestHandler(broker);
 
@@ -34,7 +35,7 @@ public class FunctionEnvironmentReloadRequestHandlerTest {
 
 	@Test
 	public void SetEnv_Null_Succeeds() throws Exception {
-		FunctionClassLoaderProvider classLoader = new FunctionClassLoaderProvider();
+		DefaultClassLoaderProvider classLoader = new DefaultClassLoaderProvider();
 		JavaFunctionBroker broker = new JavaFunctionBroker(classLoader);
 		FunctionEnvironmentReloadRequestHandler envHandler = new FunctionEnvironmentReloadRequestHandler(broker);
 
diff --git a/src/test/java/com/microsoft/azure/functions/worker/reflect/FunctionClassLoaderProviderTest.java b/src/test/java/com/microsoft/azure/functions/worker/reflect/FunctionClassLoaderProviderTest.java
deleted file mode 100644
index 77f4d45..0000000
--- a/src/test/java/com/microsoft/azure/functions/worker/reflect/FunctionClassLoaderProviderTest.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.microsoft.azure.functions.worker.reflect;
-
-import static org.junit.Assert.*;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.*;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-
-@RunWith(Parameterized.class)
-public class FunctionClassLoaderProviderTest {
-
-	@Parameters
-	public static Object[] data() {
-		return new Object[] { "nospace.txt", "with space.txt" };
-	}
-
-	@Parameter
-	public String filePath;
-
-	@Rule
-	public TemporaryFolder testFolder = new TemporaryFolder();
-
-	@Test
-	public void testSingleton() {
-		ClassLoader classLoader1 = new FunctionClassLoaderProvider().createClassLoader();
-		ClassLoader classLoader2 = new FunctionClassLoaderProvider().createClassLoader();
-		assertEquals(classLoader1, classLoader2);
-	}
-
-}
diff --git a/src/test/java/com/microsoft/azure/functions/worker/reflect/tests/DefaultClassLoaderProviderTests.java b/src/test/java/com/microsoft/azure/functions/worker/reflect/tests/DefaultClassLoaderProviderTests.java
new file mode 100644
index 0000000..7bcd562
--- /dev/null
+++ b/src/test/java/com/microsoft/azure/functions/worker/reflect/tests/DefaultClassLoaderProviderTests.java
@@ -0,0 +1,45 @@
+package com.microsoft.azure.functions.worker.reflect.tests;
+
+import java.io.*;
+import java.net.*;
+
+import static org.junit.Assert.*;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.*;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import com.microsoft.azure.functions.worker.reflect.DefaultClassLoaderProvider;
+
+@RunWith(Parameterized.class)
+public class DefaultClassLoaderProviderTests {
+
+	@Parameters
+	public static Object[] data() {
+		return new Object[] { "nospace.txt", "with space.txt" };
+	}
+
+	@Parameter
+	public String filePath;
+
+	@Rule
+	public TemporaryFolder testFolder = new TemporaryFolder();
+
+	@Test
+	public void isUrlPointingToAFile_Returns_True() throws IOException {
+		File createdFile = testFolder.newFile(filePath);
+		boolean fileExists = DefaultClassLoaderProvider.isUrlPointingToAFile(createdFile.toURI().toURL());
+		assertTrue(fileExists);
+	}
+
+	@Test
+	public void isUrlPointingToAFile_False() throws IOException {
+		String dummyFile = "filedoesnotexist.txt";
+		URL jarUrl = new File(dummyFile).toURI().toURL();
+		boolean fileExists = DefaultClassLoaderProvider.isUrlPointingToAFile(jarUrl);
+		assertFalse(fileExists);
+	}
+}
diff --git a/src/test/java/com/microsoft/azure/functions/worker/binding/ExecutionTraceContextTest.java b/src/test/java/com/microsoft/azure/functions/worker/test/ExecutionTraceContextTests.java
similarity index 91%
rename from src/test/java/com/microsoft/azure/functions/worker/binding/ExecutionTraceContextTest.java
rename to src/test/java/com/microsoft/azure/functions/worker/test/ExecutionTraceContextTests.java
index 2c2ada4..9d21620 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/binding/ExecutionTraceContextTest.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/test/ExecutionTraceContextTests.java
@@ -1,13 +1,14 @@
-package com.microsoft.azure.functions.worker.binding;
+package com.microsoft.azure.functions.worker.test;
 
 import static org.junit.Assert.assertEquals;
 
 import java.util.HashMap;
 import com.microsoft.azure.functions.TraceContext;
+import com.microsoft.azure.functions.worker.binding.ExecutionTraceContext;
 
 import org.junit.Test;
 
-public class ExecutionTraceContextTest {
+public class ExecutionTraceContextTests {
 
     @Test
     public void TraceContext_test_getAndset_nonEmpty() {