Repository: Azure/azure-functions-java-worker
Pull request #636 (2022-08-25 18:55:18)

migrate java8 to java11
<!-- Please provide all the information below.  -->

### Issue describing the changes in this PR

migrate java8 to java11 worker logics. Remove redundant codes. 

### Pull request checklist

* [X] My changes **do not** require documentation changes
  * [ ] Otherwise: Documentation issue linked to PR
* [X] My changes **should not** be added to the release notes for the next release
  * [ ] Otherwise: I've added my notes to `release_notes.md`
* [X] My changes **do not** need to be backported to a previous version
  * [ ] Otherwise: Backport tracked by issue/PR #issue_or_pr
* [ ] I have added all required tests (Unit tests, E2E tests)

<!-- Optional: delete if not applicable  -->
### Additional information

Additional PR information

kaibocai: Hi Team, @shreyas-gopalakrishna , @amamounelsayed , @trask , this PR is ready for review now, please take a look, thanks very much!

Patch:
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index b322ca6..389db3c 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -126,6 +126,7 @@ 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:
@@ -149,7 +150,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 3122935..e64cb8e 100644
--- a/package-pipeline.ps1
+++ b/package-pipeline.ps1
@@ -13,6 +13,10 @@ 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 52d005b..371cb7f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -291,6 +291,23 @@
 					</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 49aed25..d50c576 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 FactoryClassLoader().createClassLoaderProvider();
+        this.classPathProvider = new FunctionClassLoaderProvider();
         
         this.addHandlers();
     }
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
deleted file mode 100644
index f2c4bab..0000000
--- a/src/main/java/com/microsoft/azure/functions/worker/broker/FactoryJavaMethodExecutor.java
+++ /dev/null
@@ -1,23 +0,0 @@
-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/EnhancedJavaMethodExecutorImpl.java b/src/main/java/com/microsoft/azure/functions/worker/broker/FunctionMethodExecutorImpl.java
similarity index 92%
rename from src/main/java/com/microsoft/azure/functions/worker/broker/EnhancedJavaMethodExecutorImpl.java
rename to src/main/java/com/microsoft/azure/functions/worker/broker/FunctionMethodExecutorImpl.java
index 2a6a031..c4a4da1 100644
--- a/src/main/java/com/microsoft/azure/functions/worker/broker/EnhancedJavaMethodExecutorImpl.java
+++ b/src/main/java/com/microsoft/azure/functions/worker/broker/FunctionMethodExecutorImpl.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 EnhancedJavaMethodExecutorImpl implements JavaMethodExecutor {
-    public EnhancedJavaMethodExecutorImpl(FunctionMethodDescriptor descriptor, Map<String, BindingInfo> bindingInfos, ClassLoaderProvider classLoaderProvider)
+public class FunctionMethodExecutorImpl implements JavaMethodExecutor {
+    public FunctionMethodExecutorImpl(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/JavaFunctionBroker.java b/src/main/java/com/microsoft/azure/functions/worker/broker/JavaFunctionBroker.java
index 7a10ac1..52ae9ba 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,7 +10,6 @@ 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;
@@ -35,7 +34,7 @@ public class JavaFunctionBroker {
 		descriptor.validate();
 
 		addSearchPathsToClassLoader(descriptor);
-		JavaMethodExecutor executor = new FactoryJavaMethodExecutor().getJavaMethodExecutor(descriptor, bindings, classLoaderProvider);
+		JavaMethodExecutor executor = new FunctionMethodExecutorImpl(descriptor, bindings, classLoaderProvider);
 
 		this.methods.put(descriptor.getId(), new ImmutablePair<>(descriptor.getName(), executor));
 	}
@@ -148,22 +147,6 @@ 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
deleted file mode 100644
index bad1d2e..0000000
--- a/src/main/java/com/microsoft/azure/functions/worker/broker/JavaMethodExecutorImpl.java
+++ /dev/null
@@ -1,65 +0,0 @@
-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 e46ff66..d9af149 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,8 +6,7 @@ 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 static com.microsoft.azure.functions.worker.Util.getJavaVersion;
+import com.microsoft.azure.functions.worker.util.Util;
 
 public class InvocationRequestHandler extends MessageHandler<InvocationRequest, InvocationResponse.Builder> {
     public InvocationRequestHandler(JavaFunctionBroker broker) {
@@ -25,7 +24,7 @@ public class InvocationRequestHandler extends MessageHandler<InvocationRequest,
 
     @Override
     String execute(InvocationRequest request, InvocationResponse.Builder response) throws Exception {
-        WorkerLogManager.getSystemLogger().log(Level.INFO, "Java version - " + getJavaVersion());
+        WorkerLogManager.getSystemLogger().log(Level.INFO, "Java version - " + Util.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
deleted file mode 100644
index fecc55b..0000000
--- a/src/main/java/com/microsoft/azure/functions/worker/reflect/DefaultClassLoaderProvider.java
+++ /dev/null
@@ -1,78 +0,0 @@
-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/FactoryClassLoader.java b/src/main/java/com/microsoft/azure/functions/worker/reflect/FactoryClassLoader.java
deleted file mode 100644
index dcb5c86..0000000
--- a/src/main/java/com/microsoft/azure/functions/worker/reflect/FactoryClassLoader.java
+++ /dev/null
@@ -1,13 +0,0 @@
-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();
-        }
-    }
-}
diff --git a/src/main/java/com/microsoft/azure/functions/worker/reflect/EnhancedClassLoaderProvider.java b/src/main/java/com/microsoft/azure/functions/worker/reflect/FunctionClassLoaderProvider.java
similarity index 94%
rename from src/main/java/com/microsoft/azure/functions/worker/reflect/EnhancedClassLoaderProvider.java
rename to src/main/java/com/microsoft/azure/functions/worker/reflect/FunctionClassLoaderProvider.java
index 77647b2..141c46c 100644
--- a/src/main/java/com/microsoft/azure/functions/worker/reflect/EnhancedClassLoaderProvider.java
+++ b/src/main/java/com/microsoft/azure/functions/worker/reflect/FunctionClassLoaderProvider.java
@@ -8,8 +8,8 @@ import java.util.concurrent.*;
 
 import com.microsoft.azure.functions.worker.*;
 
-public class EnhancedClassLoaderProvider implements ClassLoaderProvider {
-    public EnhancedClassLoaderProvider() {
+public class FunctionClassLoaderProvider implements ClassLoaderProvider {
+    public FunctionClassLoaderProvider() {
         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/Util.java b/src/main/java/com/microsoft/azure/functions/worker/util/Util.java
similarity index 85%
rename from src/main/java/com/microsoft/azure/functions/worker/Util.java
rename to src/main/java/com/microsoft/azure/functions/worker/util/Util.java
index 2b083ed..cadd425 100644
--- a/src/main/java/com/microsoft/azure/functions/worker/Util.java
+++ b/src/main/java/com/microsoft/azure/functions/worker/util/Util.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker;
+package com.microsoft.azure.functions.worker.util;
 
 public class Util {
     public static boolean isTrue(String value) {


Test patch:
diff --git a/src/test/java/com/microsoft/azure/functions/worker/test/ExecutionTraceContextTests.java b/src/test/java/com/microsoft/azure/functions/worker/binding/ExecutionTraceContextTest.java
similarity index 91%
rename from src/test/java/com/microsoft/azure/functions/worker/test/ExecutionTraceContextTests.java
rename to src/test/java/com/microsoft/azure/functions/worker/binding/ExecutionTraceContextTest.java
index 9d21620..2c2ada4 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/test/ExecutionTraceContextTests.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/ExecutionTraceContextTest.java
@@ -1,14 +1,13 @@
-package com.microsoft.azure.functions.worker.test;
+package com.microsoft.azure.functions.worker.binding;
 
 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 ExecutionTraceContextTests {
+public class ExecutionTraceContextTest {
 
     @Test
     public void TraceContext_test_getAndset_nonEmpty() {
diff --git a/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcByteArrayDataSourceTests.java b/src/test/java/com/microsoft/azure/functions/worker/binding/RpcByteArrayDataSourceTest.java
similarity index 92%
rename from src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcByteArrayDataSourceTests.java
rename to src/test/java/com/microsoft/azure/functions/worker/binding/RpcByteArrayDataSourceTest.java
index fe4c04d..1444587 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcByteArrayDataSourceTests.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/RpcByteArrayDataSourceTest.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.binding.tests;
+package com.microsoft.azure.functions.worker.binding;
 
 import static org.junit.Assert.assertEquals;
 
@@ -9,10 +9,8 @@ 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 RpcByteArrayDataSourceTests {
+public class RpcByteArrayDataSourceTest {
 
   @Test
   public void rpcByteArrayDataSource_To_byteArray() {
diff --git a/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionByteArrayDataSourceTest.java b/src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionByteArrayDataSourceTest.java
similarity index 99%
rename from src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionByteArrayDataSourceTest.java
rename to src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionByteArrayDataSourceTest.java
index 53c582d..73715a6 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionByteArrayDataSourceTest.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionByteArrayDataSourceTest.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.binding.tests;
+package com.microsoft.azure.functions.worker.binding;
 
 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/tests/RpcCollectionDoubleDataSourceTest.java b/src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionDoubleDataSourceTest.java
similarity index 98%
rename from src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionDoubleDataSourceTest.java
rename to src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionDoubleDataSourceTest.java
index 78f39af..732d5f0 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionDoubleDataSourceTest.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionDoubleDataSourceTest.java
@@ -1,5 +1,5 @@
 
-package com.microsoft.azure.functions.worker.binding.tests;
+package com.microsoft.azure.functions.worker.binding;
 
 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/tests/RpcCollectionLongDataSourceTest.java b/src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionLongDataSourceTest.java
similarity index 98%
rename from src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionLongDataSourceTest.java
rename to src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionLongDataSourceTest.java
index a48f078..58ed16f 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionLongDataSourceTest.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionLongDataSourceTest.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.binding.tests;
+package com.microsoft.azure.functions.worker.binding;
 
 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/tests/RpcCollectionStringDataSourceTest.java b/src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionStringDataSourceTest.java
similarity index 98%
rename from src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionStringDataSourceTest.java
rename to src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionStringDataSourceTest.java
index 114a046..c9445a5 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcCollectionStringDataSourceTest.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/RpcCollectionStringDataSourceTest.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.binding.tests;
+package com.microsoft.azure.functions.worker.binding;
 
 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/tests/RpcHttpRequestDataSourceTests.java b/src/test/java/com/microsoft/azure/functions/worker/binding/RpcHttpRequestDataSourceTest.java
similarity index 92%
rename from src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcHttpRequestDataSourceTests.java
rename to src/test/java/com/microsoft/azure/functions/worker/binding/RpcHttpRequestDataSourceTest.java
index 6cf11b5..8fb4ee2 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcHttpRequestDataSourceTests.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/RpcHttpRequestDataSourceTest.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.binding.tests;
+package com.microsoft.azure.functions.worker.binding;
 
 import static org.junit.Assert.assertEquals;
 
@@ -11,9 +11,8 @@ 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 RpcHttpRequestDataSourceTests {
+public class RpcHttpRequestDataSourceTest {
 
   public void HttpRequestStringBody(HttpRequestMessage<String> request) {
   }
@@ -92,8 +91,8 @@ public class RpcHttpRequestDataSourceTests {
   }
 
   private Method getFunctionMethod(String methodName) {
-    RpcHttpRequestDataSourceTests httpDataSourceTests = new RpcHttpRequestDataSourceTests();
-    Class<? extends RpcHttpRequestDataSourceTests> httpDataSourceTestsClass = httpDataSourceTests
+    RpcHttpRequestDataSourceTest httpDataSourceTests = new RpcHttpRequestDataSourceTest();
+    Class<? extends RpcHttpRequestDataSourceTest> httpDataSourceTestsClass = httpDataSourceTests
         .getClass();
     Method[] methods = httpDataSourceTestsClass.getMethods();
     Method functionMethod = null;
diff --git a/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcIntegerDataSourceTests.java b/src/test/java/com/microsoft/azure/functions/worker/binding/RpcIntegerDataSourceTest.java
similarity index 79%
rename from src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcIntegerDataSourceTests.java
rename to src/test/java/com/microsoft/azure/functions/worker/binding/RpcIntegerDataSourceTest.java
index 0e74301..061c77d 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcIntegerDataSourceTests.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/RpcIntegerDataSourceTest.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.binding.tests;
+package com.microsoft.azure.functions.worker.binding;
 
 import static org.junit.Assert.assertEquals;
 
@@ -7,10 +7,7 @@ import java.util.Optional;
 
 import org.junit.Test;
 
-import com.microsoft.azure.functions.worker.binding.BindingData;
-import com.microsoft.azure.functions.worker.binding.RpcIntegerDataSource;
-
-public class RpcIntegerDataSourceTests {
+public class RpcIntegerDataSourceTest {
 
 	@Test
 	public void rpcIntegerDataSource_To_Integer() {
diff --git a/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcStringDataSourceTests.java b/src/test/java/com/microsoft/azure/functions/worker/binding/RpcStringDataSourceTest.java
similarity index 93%
rename from src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcStringDataSourceTests.java
rename to src/test/java/com/microsoft/azure/functions/worker/binding/RpcStringDataSourceTest.java
index b786e76..fe3b0fb 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/binding/tests/RpcStringDataSourceTests.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/binding/RpcStringDataSourceTest.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.binding.tests;
+package com.microsoft.azure.functions.worker.binding;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -14,11 +14,8 @@ 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 RpcStringDataSourceTests {
+public class RpcStringDataSourceTest {
 
 	public static class TestPOJO {
 		public Integer id;
@@ -151,8 +148,8 @@ public class RpcStringDataSourceTests {
 	}
 
 	private static Type getParameterType(String functionName) {
-		RpcStringDataSourceTests stringDataSourceTests = new RpcStringDataSourceTests();
-		Class<? extends RpcStringDataSourceTests> stringDataSourceTestsClass = stringDataSourceTests.getClass();
+		RpcStringDataSourceTest stringDataSourceTests = new RpcStringDataSourceTest();
+		Class<? extends RpcStringDataSourceTest> 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/tests/CoreTypeResolverTests.java b/src/test/java/com/microsoft/azure/functions/worker/broker/CoreTypeResolverTest.java
similarity index 90%
rename from src/test/java/com/microsoft/azure/functions/worker/broker/tests/CoreTypeResolverTests.java
rename to src/test/java/com/microsoft/azure/functions/worker/broker/CoreTypeResolverTest.java
index 1a69120..dc6640e 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/broker/tests/CoreTypeResolverTests.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/broker/CoreTypeResolverTest.java
@@ -1,13 +1,10 @@
-package com.microsoft.azure.functions.worker.broker.tests;
+package com.microsoft.azure.functions.worker.broker;
 
-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.*;
@@ -16,7 +13,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 CoreTypeResolverTests {
+public class CoreTypeResolverTest {
 
 	public void CustomBinding_Valid(
 			@HttpTrigger(name = "req", methods = { HttpMethod.GET,
@@ -125,7 +122,7 @@ public class CoreTypeResolverTests {
 	}
 
 	private Type returnTypeOf(String type) throws NoSuchMethodException {
-		Method m = CoreTypeResolverTests.class.getDeclaredMethod(type);
+		Method m = CoreTypeResolverTest.class.getDeclaredMethod(type);
 		m.setAccessible(true);
 		return m.getGenericReturnType();
 	}
@@ -153,8 +150,8 @@ public class CoreTypeResolverTests {
 	}
 
 	private Method getFunctionMethod(String methodName) {
-		CoreTypeResolverTests coreTypeResolverTests = new CoreTypeResolverTests();
-		Class<? extends CoreTypeResolverTests> testsClass = coreTypeResolverTests.getClass();
+		CoreTypeResolverTest coreTypeResolverTest = new CoreTypeResolverTest();
+		Class<? extends CoreTypeResolverTest> testsClass = coreTypeResolverTest.getClass();
 		Method[] methods = testsClass.getMethods();
 		Method functionMethod = null;
 		for (Method method : methods) {
diff --git a/src/test/java/com/microsoft/azure/functions/worker/broker/tests/InvalidCustomBinding.java b/src/test/java/com/microsoft/azure/functions/worker/broker/InvalidCustomBinding.java
similarity index 83%
rename from src/test/java/com/microsoft/azure/functions/worker/broker/tests/InvalidCustomBinding.java
rename to src/test/java/com/microsoft/azure/functions/worker/broker/InvalidCustomBinding.java
index 30fa73e..69f8d20 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/broker/tests/InvalidCustomBinding.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/broker/InvalidCustomBinding.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.broker.tests;
+package com.microsoft.azure.functions.worker.broker;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
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 231c1d6..732544e 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.DefaultClassLoaderProvider;
+import com.microsoft.azure.functions.worker.reflect.FunctionClassLoaderProvider;
 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(Arrays.asList(binding));
+        when(request.getInputDataList()).thenReturn(Collections.singletonList(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 DefaultClassLoaderProvider());
+        JavaFunctionBroker broker = new JavaFunctionBroker(new FunctionClassLoaderProvider());
         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(Arrays.asList(binding));
+        when(request.getInputDataList()).thenReturn(Collections.singletonList(binding));
 
         lenient().when(queueTrigger.getString()).thenReturn("string: \"hello queue\"\n");
         lenient().when(dequeueCount.getString()).thenReturn("json: \"1\"\n");
@@ -97,23 +97,9 @@ public class JavaFunctionBrokerTest {
         when(request.getTriggerMetadataMap()).thenReturn(Collections.unmodifiableMap(triggerMetadata));
 
         int expectedCount = request.getTriggerMetadataMap().size();
-        JavaFunctionBroker broker = new JavaFunctionBroker(new DefaultClassLoaderProvider());
+        JavaFunctionBroker broker = new JavaFunctionBroker(new FunctionClassLoaderProvider());
         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
new file mode 100644
index 0000000..8c89673
--- /dev/null
+++ b/src/test/java/com/microsoft/azure/functions/worker/broker/JavaMethodExecutorTest.java
@@ -0,0 +1,57 @@
+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/tests/TestCustomBinding.java b/src/test/java/com/microsoft/azure/functions/worker/broker/TestCustomBinding.java
similarity index 88%
rename from src/test/java/com/microsoft/azure/functions/worker/broker/tests/TestCustomBinding.java
rename to src/test/java/com/microsoft/azure/functions/worker/broker/TestCustomBinding.java
index 0113731..2118ace 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/broker/tests/TestCustomBinding.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/broker/TestCustomBinding.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.broker.tests;
+package com.microsoft.azure.functions.worker.broker;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
diff --git a/src/test/java/com/microsoft/azure/functions/worker/broker/tests/TestCustomBindingNoName.java b/src/test/java/com/microsoft/azure/functions/worker/broker/TestCustomBindingNoName.java
similarity index 88%
rename from src/test/java/com/microsoft/azure/functions/worker/broker/tests/TestCustomBindingNoName.java
rename to src/test/java/com/microsoft/azure/functions/worker/broker/TestCustomBindingNoName.java
index 296f7cf..1e79b1b 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/broker/tests/TestCustomBindingNoName.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/broker/TestCustomBindingNoName.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.broker.tests;
+package com.microsoft.azure.functions.worker.broker;
 
 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
deleted file mode 100644
index c1bad3a..0000000
--- a/src/test/java/com/microsoft/azure/functions/worker/broker/tests/JavaMethodExecutorTests.java
+++ /dev/null
@@ -1,72 +0,0 @@
-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/tests/TestFunctionsClass.java b/src/test/java/com/microsoft/azure/functions/worker/broker/tests/TestFunctionsClass.java
deleted file mode 100644
index a1bab74..0000000
--- a/src/test/java/com/microsoft/azure/functions/worker/broker/tests/TestFunctionsClass.java
+++ /dev/null
@@ -1,41 +0,0 @@
-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/handler/tests/FunctionEnvironmentReloadRequestHandlerTests.java b/src/test/java/com/microsoft/azure/functions/worker/handler/FunctionEnvironmentReloadRequestHandlerTest.java
similarity index 74%
rename from src/test/java/com/microsoft/azure/functions/worker/handler/tests/FunctionEnvironmentReloadRequestHandlerTests.java
rename to src/test/java/com/microsoft/azure/functions/worker/handler/FunctionEnvironmentReloadRequestHandlerTest.java
index 4793d52..1549d6a 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/handler/tests/FunctionEnvironmentReloadRequestHandlerTests.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/handler/FunctionEnvironmentReloadRequestHandlerTest.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.handler.tests;
+package com.microsoft.azure.functions.worker.handler;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -7,17 +7,16 @@ 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 FunctionEnvironmentReloadRequestHandlerTests {
+public class FunctionEnvironmentReloadRequestHandlerTest {
 
 	@Test
 	public void SetEnv_Succeeds() throws Exception {
-		DefaultClassLoaderProvider classLoader = new DefaultClassLoaderProvider();
+		FunctionClassLoaderProvider classLoader = new FunctionClassLoaderProvider();
 		JavaFunctionBroker broker = new JavaFunctionBroker(classLoader);
 		FunctionEnvironmentReloadRequestHandler envHandler = new FunctionEnvironmentReloadRequestHandler(broker);
 
@@ -35,7 +34,7 @@ public class FunctionEnvironmentReloadRequestHandlerTests {
 
 	@Test
 	public void SetEnv_Null_Succeeds() throws Exception {
-		DefaultClassLoaderProvider classLoader = new DefaultClassLoaderProvider();
+		FunctionClassLoaderProvider classLoader = new FunctionClassLoaderProvider();
 		JavaFunctionBroker broker = new JavaFunctionBroker(classLoader);
 		FunctionEnvironmentReloadRequestHandler envHandler = new FunctionEnvironmentReloadRequestHandler(broker);
 
diff --git a/src/test/java/com/microsoft/azure/functions/worker/functional/tests/SimpleParamReturnTest.java b/src/test/java/com/microsoft/azure/functions/worker/integration/SimpleParamReturnIT.java
similarity index 90%
rename from src/test/java/com/microsoft/azure/functions/worker/functional/tests/SimpleParamReturnTest.java
rename to src/test/java/com/microsoft/azure/functions/worker/integration/SimpleParamReturnIT.java
index 92d32c1..df2d4dc 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/functional/tests/SimpleParamReturnTest.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/integration/SimpleParamReturnIT.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker.functional.tests;
+package com.microsoft.azure.functions.worker.integration;
 
 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 SimpleParamReturnTest extends FunctionsTestBase {
+public class SimpleParamReturnIT extends FunctionsTestBase {
 
 	@Parameters
 	public static Object[] data() {
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
new file mode 100644
index 0000000..77f4d45
--- /dev/null
+++ b/src/test/java/com/microsoft/azure/functions/worker/reflect/FunctionClassLoaderProviderTest.java
@@ -0,0 +1,35 @@
+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
deleted file mode 100644
index 7bcd562..0000000
--- a/src/test/java/com/microsoft/azure/functions/worker/reflect/tests/DefaultClassLoaderProviderTests.java
+++ /dev/null
@@ -1,45 +0,0 @@
-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/UtilTests.java b/src/test/java/com/microsoft/azure/functions/worker/util/UtilTests.java
similarity index 84%
rename from src/test/java/com/microsoft/azure/functions/worker/UtilTests.java
rename to src/test/java/com/microsoft/azure/functions/worker/util/UtilTests.java
index 0b47031..7328a17 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/UtilTests.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/util/UtilTests.java
@@ -1,4 +1,4 @@
-package com.microsoft.azure.functions.worker;
+package com.microsoft.azure.functions.worker.util;
 
 import org.junit.Test;