From 2de8fad05cb622e1141ab589370e159fbcee3f60 Mon Sep 17 00:00:00 2001 From: Zack Macomber Date: Fri, 28 Sep 2018 18:01:39 -0400 Subject: [PATCH 1/8] Added 'public static List getBaseClasses(final Class desiredBase, final String packageName)' which returns a list of base classes/interfaces that match the supplied type underneath the supplied package --- .../org/apache/commons/lang3/ClassUtils.java | 70 +++++++++++++++++++ .../apache/commons/lang3/ClassUtilsTest.java | 54 ++++++++++++++ 2 files changed, 124 insertions(+) diff --git a/src/main/java/org/apache/commons/lang3/ClassUtils.java b/src/main/java/org/apache/commons/lang3/ClassUtils.java index 28500a5545f..b8ad1850d5e 100644 --- a/src/main/java/org/apache/commons/lang3/ClassUtils.java +++ b/src/main/java/org/apache/commons/lang3/ClassUtils.java @@ -16,8 +16,16 @@ */ package org.apache.commons.lang3; +import java.io.IOException; +import java.lang.IllegalArgumentException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -1059,6 +1067,68 @@ public static Class getClass(final String className, final boolean initialize return getClass(loader, className, initialize); } + /** + * Returns a list of base classes/interfaces underneath the supplied package + * This method only retrieves base classes/interfaces that have children that can be instantiated + * via a no-args constructor + * The class loader is retrieved via Thread.currentThread().getContextClassLoader() + * This only retrieves base classes/interfaces directly underneath the supplied package + * + * @param desiredBase the desired base class/interface to retrieve + * @param packageName the package name in the standard import format (i.e. "java.lang.String") + * @param The desired base class or interface type to retrieve + * @return a list of base classes/interfaces that match the supplied type underneath the supplied package + * @throws URISyntaxException if the packageName is not found in the class loader + * @throws IOException if an I/O error occurs in getting a new directory stream + * @throws IllegalArgumentException if the desiredBase or packageName are invalid + */ + public static List getBaseClasses(final Class desiredBase, final String packageName) + throws URISyntaxException, IOException, IllegalArgumentException { + + if (desiredBase == null) { + throw new IllegalArgumentException("desiredBase must not be null"); + } + + if (StringUtils.isBlank(packageName)) { + throw new IllegalArgumentException("packageName must not be blank"); + } + + if (packageName.contains("/")) { + throw new IllegalArgumentException("packageName is not properly formatted (i.e. 'java.lang.String')"); + } + + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + URL url = classLoader.getResource(packageName.replaceAll("[.]", "/")); + if (url == null) { + throw new URISyntaxException(packageName, "Supplied package not found"); + } + + Path classesPath = Paths.get(url.toURI()); + + List classes = new ArrayList<>(); + + try (DirectoryStream stream = Files.newDirectoryStream(classesPath)) { + for (Path file: stream) { + if ( ! Files.isDirectory(file)) { + String fullClassName = packageName + "." + + file.getFileName().toString().replace(".class", ""); + + // Only add classes that can be instantiated via newInstance() + try { + Object obj = Class.forName(fullClassName).newInstance(); + if (desiredBase.isInstance(obj)) { + classes.add((T) obj); + } + } catch (Exception e) { + // Class was not instantiable via newInstance() + } + } + } + } + + return classes; + } + // Public method // ---------------------------------------------------------------------- /** diff --git a/src/test/java/org/apache/commons/lang3/ClassUtilsTest.java b/src/test/java/org/apache/commons/lang3/ClassUtilsTest.java index 59c9dad649e..ce486e6df27 100644 --- a/src/test/java/org/apache/commons/lang3/ClassUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/ClassUtilsTest.java @@ -29,6 +29,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -39,6 +40,9 @@ import java.util.Set; import org.apache.commons.lang3.ClassUtils.Interfaces; +import org.apache.commons.lang3.concurrent.AbstractConcurrentInitializerTest; +import org.apache.commons.lang3.reflect.testbed.AnotherParent; +import org.apache.commons.lang3.reflect.testbed.Foo; import org.apache.commons.lang3.reflect.testbed.GenericConsumer; import org.apache.commons.lang3.reflect.testbed.GenericParent; import org.apache.commons.lang3.reflect.testbed.StringParameterizedChild; @@ -1193,6 +1197,56 @@ public void testGetInnerClass() throws ClassNotFoundException { assertEquals( Inner.DeeplyNested.class, ClassUtils.getClass( "org.apache.commons.lang3.ClassUtilsTest$Inner.DeeplyNested" ) ); } + @Test + public void testGetBaseClassesExtends() throws Exception { + List classes = ClassUtils.getBaseClasses(AnotherParent.class, "org.apache.commons.lang3.reflect.testbed"); + assertTrue(classes.size() > 0); + } + + @Test + public void testGetBaseClassesAbstract() throws Exception { + List classes = ClassUtils.getBaseClasses(AbstractConcurrentInitializerTest.class, "org.apache.commons.lang3.concurrent"); + assertTrue(classes.size() > 0); + } + + @Test + public void testGetBaseClassesInterface() throws Exception { + List classes = ClassUtils.getBaseClasses(Foo.class, "org.apache.commons.lang3.reflect.testbed"); + assertTrue(classes.size() > 0); + } + + // Assumes org.apache.commons.lang3.ClassUtils derivatives will not be present underneath org.apache.commons.lang3.test + @Test + public void testGetBaseClassesNoneFound() throws Exception { + List classes = ClassUtils.getBaseClasses(ClassUtils.class, "org.apache.commons.lang3.test"); + assertEquals(0, classes.size()); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetBaseClassesNullDesiredClass() throws Exception { + ClassUtils.getBaseClasses(null, "org.apache.commons.lang3.test"); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetBaseClassesNullPackageName() throws Exception { + ClassUtils.getBaseClasses(String.class, null); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetBaseClassesIllegalPackageName() throws Exception { + ClassUtils.getBaseClasses(String.class, "com/test"); + } + + @Test(expected = URISyntaxException.class) + public void testGetBaseClassesInvalidPackage() throws Exception { + ClassUtils.getBaseClasses(String.class, "an.invalid.package"); + } + + @Test(expected = URISyntaxException.class) + public void testGetBaseClassesAnotherInvalidPackage() throws Exception { + ClassUtils.getBaseClasses(String.class, "bad formatted package"); + } + @Test public void testGetPublicMethod() throws Exception { // Tests with Collections$UnmodifiableSet From 9cbe3767a5ac64c0e6fe634dcde9a77652534c17 Mon Sep 17 00:00:00 2001 From: Zack Macomber Date: Mon, 1 Oct 2018 08:17:28 -0400 Subject: [PATCH 2/8] Removed redundant import of java.lang.IllegalArgumentException --- src/main/java/org/apache/commons/lang3/ClassUtils.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/apache/commons/lang3/ClassUtils.java b/src/main/java/org/apache/commons/lang3/ClassUtils.java index b8ad1850d5e..c856ed7ccf2 100644 --- a/src/main/java/org/apache/commons/lang3/ClassUtils.java +++ b/src/main/java/org/apache/commons/lang3/ClassUtils.java @@ -17,7 +17,6 @@ package org.apache.commons.lang3; import java.io.IOException; -import java.lang.IllegalArgumentException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URISyntaxException; From 4e0a3cf4b3429a11f2ab37266526600739a720c5 Mon Sep 17 00:00:00 2001 From: Zack Macomber Date: Mon, 1 Oct 2018 09:27:18 -0400 Subject: [PATCH 3/8] Fixed "Possible null pointer dereference" error --- src/main/java/org/apache/commons/lang3/ClassUtils.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/apache/commons/lang3/ClassUtils.java b/src/main/java/org/apache/commons/lang3/ClassUtils.java index c856ed7ccf2..28fd0dfd4c5 100644 --- a/src/main/java/org/apache/commons/lang3/ClassUtils.java +++ b/src/main/java/org/apache/commons/lang3/ClassUtils.java @@ -1108,9 +1108,10 @@ public static List getBaseClasses(final Class desiredBase, final Strin try (DirectoryStream stream = Files.newDirectoryStream(classesPath)) { for (Path file: stream) { - if ( ! Files.isDirectory(file)) { + Path pathFileName = file.getFileName(); + if (( ! Files.isDirectory(file)) && (pathFileName != null)) { String fullClassName = packageName + "." + - file.getFileName().toString().replace(".class", ""); + pathFileName.toString().replace(".class", ""); // Only add classes that can be instantiated via newInstance() try { From faac578c4d712d603c7f83ae1d61b7ad5025a001 Mon Sep 17 00:00:00 2001 From: Zack Macomber Date: Tue, 16 Oct 2018 08:51:36 -0400 Subject: [PATCH 4/8] Took out unnecessary "packageName.contains('/')" check in ClassUtils.getBaseClasses() --- src/main/java/org/apache/commons/lang3/ClassUtils.java | 4 ---- src/test/java/org/apache/commons/lang3/ClassUtilsTest.java | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/apache/commons/lang3/ClassUtils.java b/src/main/java/org/apache/commons/lang3/ClassUtils.java index 28fd0dfd4c5..0be5590c50c 100644 --- a/src/main/java/org/apache/commons/lang3/ClassUtils.java +++ b/src/main/java/org/apache/commons/lang3/ClassUtils.java @@ -1092,10 +1092,6 @@ public static List getBaseClasses(final Class desiredBase, final Strin throw new IllegalArgumentException("packageName must not be blank"); } - if (packageName.contains("/")) { - throw new IllegalArgumentException("packageName is not properly formatted (i.e. 'java.lang.String')"); - } - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); URL url = classLoader.getResource(packageName.replaceAll("[.]", "/")); if (url == null) { diff --git a/src/test/java/org/apache/commons/lang3/ClassUtilsTest.java b/src/test/java/org/apache/commons/lang3/ClassUtilsTest.java index ce486e6df27..89523bb8cb0 100644 --- a/src/test/java/org/apache/commons/lang3/ClassUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/ClassUtilsTest.java @@ -1233,8 +1233,8 @@ public void testGetBaseClassesNullPackageName() throws Exception { } @Test(expected = IllegalArgumentException.class) - public void testGetBaseClassesIllegalPackageName() throws Exception { - ClassUtils.getBaseClasses(String.class, "com/test"); + public void testGetBaseClassesEmptyPackageName() throws Exception { + ClassUtils.getBaseClasses(String.class, " "); } @Test(expected = URISyntaxException.class) From 15a594c4cd484930aa27c4443011bbcce3b22d25 Mon Sep 17 00:00:00 2001 From: Zack Macomber Date: Tue, 16 Oct 2018 10:10:16 -0400 Subject: [PATCH 5/8] Updated to use Objects.requireNonNull in ClassUtils.getBaseClasses(). Sorted names and updated tests. --- .../org/apache/commons/lang3/ClassUtils.java | 16 +++++++--------- .../org/apache/commons/lang3/ClassUtilsTest.java | 6 +++--- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/apache/commons/lang3/ClassUtils.java b/src/main/java/org/apache/commons/lang3/ClassUtils.java index 0be5590c50c..ceb418d0221 100644 --- a/src/main/java/org/apache/commons/lang3/ClassUtils.java +++ b/src/main/java/org/apache/commons/lang3/ClassUtils.java @@ -32,6 +32,7 @@ import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; +import java.util.Objects; import java.util.Map; import java.util.Set; @@ -1077,16 +1078,15 @@ public static Class getClass(final String className, final boolean initialize * @param packageName the package name in the standard import format (i.e. "java.lang.String") * @param The desired base class or interface type to retrieve * @return a list of base classes/interfaces that match the supplied type underneath the supplied package - * @throws URISyntaxException if the packageName is not found in the class loader - * @throws IOException if an I/O error occurs in getting a new directory stream * @throws IllegalArgumentException if the desiredBase or packageName are invalid + * @throws IOException if an I/O error occurs in getting a new directory stream + * @throws NullPointerException if desiredBase or url are null + * @throws URISyntaxException if the generated url can't be converted to a URI */ public static List getBaseClasses(final Class desiredBase, final String packageName) - throws URISyntaxException, IOException, IllegalArgumentException { + throws IllegalArgumentException, IOException, NullPointerException, URISyntaxException { - if (desiredBase == null) { - throw new IllegalArgumentException("desiredBase must not be null"); - } + Objects.requireNonNull(desiredBase, "desiredBase must not be null"); if (StringUtils.isBlank(packageName)) { throw new IllegalArgumentException("packageName must not be blank"); @@ -1094,9 +1094,7 @@ public static List getBaseClasses(final Class desiredBase, final Strin ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); URL url = classLoader.getResource(packageName.replaceAll("[.]", "/")); - if (url == null) { - throw new URISyntaxException(packageName, "Supplied package not found"); - } + Objects.requireNonNull(url, "supplied package not found"); Path classesPath = Paths.get(url.toURI()); diff --git a/src/test/java/org/apache/commons/lang3/ClassUtilsTest.java b/src/test/java/org/apache/commons/lang3/ClassUtilsTest.java index 89523bb8cb0..8fe46c19938 100644 --- a/src/test/java/org/apache/commons/lang3/ClassUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/ClassUtilsTest.java @@ -1222,7 +1222,7 @@ public void testGetBaseClassesNoneFound() throws Exception { assertEquals(0, classes.size()); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = NullPointerException.class) public void testGetBaseClassesNullDesiredClass() throws Exception { ClassUtils.getBaseClasses(null, "org.apache.commons.lang3.test"); } @@ -1237,12 +1237,12 @@ public void testGetBaseClassesEmptyPackageName() throws Exception { ClassUtils.getBaseClasses(String.class, " "); } - @Test(expected = URISyntaxException.class) + @Test(expected = NullPointerException.class) public void testGetBaseClassesInvalidPackage() throws Exception { ClassUtils.getBaseClasses(String.class, "an.invalid.package"); } - @Test(expected = URISyntaxException.class) + @Test(expected = NullPointerException.class) public void testGetBaseClassesAnotherInvalidPackage() throws Exception { ClassUtils.getBaseClasses(String.class, "bad formatted package"); } From 62c6115726c7da55169cda0408dbb9d7a3c8a987 Mon Sep 17 00:00:00 2001 From: Zack Macomber Date: Fri, 19 Oct 2018 07:40:30 -0400 Subject: [PATCH 6/8] Replaced "@Test(expected...)" with try/catch blocks in GetBaseClasses tests as that code was causing compile errors --- .../apache/commons/lang3/ClassUtilsTest.java | 51 +++++++++++++------ 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/src/test/java/org/apache/commons/lang3/ClassUtilsTest.java b/src/test/java/org/apache/commons/lang3/ClassUtilsTest.java index 8fe46c19938..ea47821d87b 100644 --- a/src/test/java/org/apache/commons/lang3/ClassUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/ClassUtilsTest.java @@ -29,7 +29,6 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -1222,29 +1221,49 @@ public void testGetBaseClassesNoneFound() throws Exception { assertEquals(0, classes.size()); } - @Test(expected = NullPointerException.class) - public void testGetBaseClassesNullDesiredClass() throws Exception { - ClassUtils.getBaseClasses(null, "org.apache.commons.lang3.test"); + @Test + public void testGetBaseClassesNullDesiredClass() { + try { + ClassUtils.getBaseClasses(null, "org.apache.commons.lang3.test"); + } catch (Exception e) { + assertTrue(e instanceof NullPointerException); + } } - @Test(expected = IllegalArgumentException.class) - public void testGetBaseClassesNullPackageName() throws Exception { - ClassUtils.getBaseClasses(String.class, null); + @Test + public void testGetBaseClassesNullPackageName() { + try { + ClassUtils.getBaseClasses(String.class, null); + } catch (Exception e) { + assertTrue(e instanceof IllegalArgumentException); + } } - @Test(expected = IllegalArgumentException.class) - public void testGetBaseClassesEmptyPackageName() throws Exception { - ClassUtils.getBaseClasses(String.class, " "); + @Test + public void testGetBaseClassesEmptyPackageName() { + try { + ClassUtils.getBaseClasses(String.class, " "); + } catch (Exception e) { + assertTrue(e instanceof IllegalArgumentException); + } } - @Test(expected = NullPointerException.class) - public void testGetBaseClassesInvalidPackage() throws Exception { - ClassUtils.getBaseClasses(String.class, "an.invalid.package"); + @Test + public void testGetBaseClassesInvalidPackage() { + try { + ClassUtils.getBaseClasses(String.class, "an.invalid.package"); + } catch (Exception e) { + assertTrue(e instanceof NullPointerException); + } } - @Test(expected = NullPointerException.class) - public void testGetBaseClassesAnotherInvalidPackage() throws Exception { - ClassUtils.getBaseClasses(String.class, "bad formatted package"); + @Test + public void testGetBaseClassesAnotherInvalidPackage() { + try { + ClassUtils.getBaseClasses(String.class, "bad formatted package"); + } catch (Exception e) { + assertTrue(e instanceof NullPointerException); + } } @Test From c1b44e72103fde0771f5c1937af24b2667b282cd Mon Sep 17 00:00:00 2001 From: Zack Macomber Date: Thu, 25 Oct 2018 08:22:30 -0400 Subject: [PATCH 7/8] Improved grammar and provided overloaded getBaseClasses method --- .../org/apache/commons/lang3/ClassUtils.java | 32 +++++++++++++------ .../apache/commons/lang3/ClassUtilsTest.java | 9 ++++++ 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/apache/commons/lang3/ClassUtils.java b/src/main/java/org/apache/commons/lang3/ClassUtils.java index ceb418d0221..25a8ee93b96 100644 --- a/src/main/java/org/apache/commons/lang3/ClassUtils.java +++ b/src/main/java/org/apache/commons/lang3/ClassUtils.java @@ -1068,22 +1068,22 @@ public static Class getClass(final String className, final boolean initialize } /** - * Returns a list of base classes/interfaces underneath the supplied package - * This method only retrieves base classes/interfaces that have children that can be instantiated - * via a no-args constructor - * The class loader is retrieved via Thread.currentThread().getContextClassLoader() - * This only retrieves base classes/interfaces directly underneath the supplied package + * Returns a list of base classes/interfaces underneath the supplied package. + * This method only retrieves base classes/interfaces that have child classes that can be instantiated + * via a no-args constructor. + * This only retrieves base classes/interfaces directly underneath the supplied package. * * @param desiredBase the desired base class/interface to retrieve * @param packageName the package name in the standard import format (i.e. "java.lang.String") + * @param classLoader the class loader to use for retrieving classes * @param The desired base class or interface type to retrieve * @return a list of base classes/interfaces that match the supplied type underneath the supplied package - * @throws IllegalArgumentException if the desiredBase or packageName are invalid + * @throws IllegalArgumentException if the packageName is invalid * @throws IOException if an I/O error occurs in getting a new directory stream - * @throws NullPointerException if desiredBase or url are null + * @throws NullPointerException if desiredBase, classLoader or url are null * @throws URISyntaxException if the generated url can't be converted to a URI */ - public static List getBaseClasses(final Class desiredBase, final String packageName) + public static List getBaseClasses(final Class desiredBase, final String packageName, ClassLoader classLoader) throws IllegalArgumentException, IOException, NullPointerException, URISyntaxException { Objects.requireNonNull(desiredBase, "desiredBase must not be null"); @@ -1092,7 +1092,8 @@ public static List getBaseClasses(final Class desiredBase, final Strin throw new IllegalArgumentException("packageName must not be blank"); } - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + Objects.requireNonNull(classLoader, "classLoader must not be null"); + URL url = classLoader.getResource(packageName.replaceAll("[.]", "/")); Objects.requireNonNull(url, "supplied package not found"); @@ -1123,6 +1124,19 @@ public static List getBaseClasses(final Class desiredBase, final Strin return classes; } + /** + * Invokes {@link #getBaseClasses(Class, String, ClassLoader)} with + * {@code Thread.currentThread().getContextClassLoader()} class loader. + * + * @see #getBaseClasses(Class, String, ClassLoader) for complete details. + */ + public static List getBaseClasses(final Class desiredBase, final String packageName) + throws IllegalArgumentException, IOException, NullPointerException, URISyntaxException { + + return getBaseClasses(desiredBase, packageName, Thread.currentThread().getContextClassLoader()); + + } + // Public method // ---------------------------------------------------------------------- /** diff --git a/src/test/java/org/apache/commons/lang3/ClassUtilsTest.java b/src/test/java/org/apache/commons/lang3/ClassUtilsTest.java index ea47821d87b..2d4c7db7b2f 100644 --- a/src/test/java/org/apache/commons/lang3/ClassUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/ClassUtilsTest.java @@ -1230,6 +1230,15 @@ public void testGetBaseClassesNullDesiredClass() { } } + @Test + public void testGetBaseClassesNullClassLoader() { + try { + ClassUtils.getBaseClasses(String.class, "org.apache.common.lang3.test", null); + } catch (Exception e) { + assertTrue(e instanceof NullPointerException); + } + } + @Test public void testGetBaseClassesNullPackageName() { try { From a0bc206bb2618e87c7351eaa8d903e972dc27ede Mon Sep 17 00:00:00 2001 From: Zack Macomber Date: Thu, 25 Oct 2018 09:35:37 -0400 Subject: [PATCH 8/8] Added Javadoc parameters to getBaseClasses(Class, String) as flagged by checkstyle --- src/main/java/org/apache/commons/lang3/ClassUtils.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/org/apache/commons/lang3/ClassUtils.java b/src/main/java/org/apache/commons/lang3/ClassUtils.java index 25a8ee93b96..f3360b3fe69 100644 --- a/src/main/java/org/apache/commons/lang3/ClassUtils.java +++ b/src/main/java/org/apache/commons/lang3/ClassUtils.java @@ -1129,6 +1129,15 @@ public static List getBaseClasses(final Class desiredBase, final Strin * {@code Thread.currentThread().getContextClassLoader()} class loader. * * @see #getBaseClasses(Class, String, ClassLoader) for complete details. + * + * @param desiredBase the desired base class/interface to retrieve + * @param packageName the package name in the standard import format (i.e. "java.lang.String") + * @param The desired base class or interface type to retrieve + * @return a list of base classes/interfaces that match the supplied type underneath the supplied package + * @throws IllegalArgumentException if the packageName is invalid + * @throws IOException if an I/O error occurs in getting a new directory stream + * @throws NullPointerException if desiredBase, classLoader or url are null + * @throws URISyntaxException if the generated url can't be converted to a URI */ public static List getBaseClasses(final Class desiredBase, final String packageName) throws IllegalArgumentException, IOException, NullPointerException, URISyntaxException {