Repository: Azure/azure-functions-java-worker
Pull request #613 (2022-08-12 17:26:54)

Revert "migrate java8 to same logic as java11"
Reverts Azure/azure-functions-java-worker#611


Patch:
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 ed3f1b5..49aed25 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/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 b95a786..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));
 	}
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/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 70%
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 066a965..7ebd723 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
@@ -9,8 +9,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>());
     }
@@ -28,6 +28,7 @@ public class FunctionClassLoaderProvider implements ClassLoaderProvider {
                     urlsList.addAll(workerUrls);
                     URL[] urlsForClassLoader = urlsList.toArray(new URL[0]);
                     URLClassLoader loader = new URLClassLoader(urlsForClassLoader);
+                    loadDrivers(loader);
                     classLoaderInstance = loader;
                 }
             }
@@ -35,6 +36,23 @@ public class FunctionClassLoaderProvider implements ClassLoaderProvider {
         return classLoaderInstance;
     }
 
+    private void loadDrivers(URLClassLoader classLoader) {
+        Thread.currentThread().setContextClassLoader(classLoader);
+        try {
+            ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
+            Iterator<Driver> driversIterator = loadedDrivers.iterator();
+            try {
+                while (driversIterator.hasNext()) {
+                    driversIterator.next();
+                }
+            } catch (Throwable t) {
+                // Do nothing
+            }
+        } finally {
+            Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
+        }
+    }
+
     @Override
     public void addCustomerUrl(URL url) throws IOException {
         if (customerUrls.contains(url)) {
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/broker/JavaFunctionBrokerTest.java b/src/test/java/com/microsoft/azure/functions/worker/broker/JavaFunctionBrokerTest.java
index 13f0f25..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;
@@ -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);
@@ -97,7 +97,7 @@ 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());
diff --git a/src/test/java/com/microsoft/azure/functions/worker/broker/tests/JavaMethodExecutorTests.java b/src/test/java/com/microsoft/azure/functions/worker/broker/tests/JavaMethodExecutorTests.java
index 48a8ebb..c1bad3a 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/broker/tests/JavaMethodExecutorTests.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/broker/tests/JavaMethodExecutorTests.java
@@ -18,7 +18,7 @@ public class JavaMethodExecutorTests {
 		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, new FunctionClassLoaderProvider());
+		JavaMethodExecutor executor = new FactoryJavaMethodExecutor().getJavaMethodExecutor(descriptor, bindings, new FactoryClassLoader().createClassLoaderProvider());
 		assertTrue(executor.getOverloadResolver().hasCandidates());
 		assertFalse(executor.getOverloadResolver().hasMultipleCandidates());
     }
@@ -28,7 +28,7 @@ public class JavaMethodExecutorTests {
 		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, new FunctionClassLoaderProvider());
+		JavaMethodExecutor executor = new FactoryJavaMethodExecutor().getJavaMethodExecutor(descriptor, bindings, new FactoryClassLoader().createClassLoaderProvider());
 		
     }
 	
@@ -37,7 +37,7 @@ public class JavaMethodExecutorTests {
 		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, new FunctionClassLoaderProvider());
+		JavaMethodExecutor executor = new FactoryJavaMethodExecutor().getJavaMethodExecutor(descriptor, bindings, new FactoryClassLoader().createClassLoaderProvider());
     }
 
 	@Test
@@ -46,7 +46,7 @@ public class JavaMethodExecutorTests {
 		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 FunctionMethodExecutorImpl(descriptor, bindings, new FunctionClassLoaderProvider());
+		JavaMethodExecutor executor = new FactoryJavaMethodExecutor().getJavaMethodExecutor(descriptor, bindings, new FactoryClassLoader().createClassLoaderProvider());
 		assertTrue(executor.getOverloadResolver().hasCandidates());
 		assertFalse(executor.getOverloadResolver().hasMultipleCandidates());
 	}
@@ -57,7 +57,7 @@ public class JavaMethodExecutorTests {
 		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, new FunctionClassLoaderProvider());
+		JavaMethodExecutor executor = new FactoryJavaMethodExecutor().getJavaMethodExecutor(descriptor, bindings, new FactoryClassLoader().createClassLoaderProvider());
 
 	}
 
@@ -67,6 +67,6 @@ public class JavaMethodExecutorTests {
 		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, new FunctionClassLoaderProvider());
+		JavaMethodExecutor executor = new FactoryJavaMethodExecutor().getJavaMethodExecutor(descriptor, bindings, new FactoryClassLoader().createClassLoaderProvider());
 	}
 }
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/tests/FunctionEnvironmentReloadRequestHandlerTests.java
index e07e0d1..4793d52 100644
--- a/src/test/java/com/microsoft/azure/functions/worker/handler/tests/FunctionEnvironmentReloadRequestHandlerTests.java
+++ b/src/test/java/com/microsoft/azure/functions/worker/handler/tests/FunctionEnvironmentReloadRequestHandlerTests.java
@@ -7,17 +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 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);
 
@@ -35,7 +35,7 @@ public class FunctionEnvironmentReloadRequestHandlerTests {
 
 	@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/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/reflect/tests/FunctionClassLoaderProviderTests.java b/src/test/java/com/microsoft/azure/functions/worker/reflect/tests/FunctionClassLoaderProviderTests.java
deleted file mode 100644
index 5bad0d2..0000000
--- a/src/test/java/com/microsoft/azure/functions/worker/reflect/tests/FunctionClassLoaderProviderTests.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.microsoft.azure.functions.worker.reflect.tests;
-
-import static org.junit.Assert.*;
-
-import com.microsoft.azure.functions.worker.reflect.FunctionClassLoaderProvider;
-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 FunctionClassLoaderProviderTests {
-
-	@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);
-	}
-}