{"id":16538781,"url":"https://github.com/sbabcoc/java-utils","last_synced_at":"2026-02-17T17:02:37.813Z","repository":{"id":38037756,"uuid":"111517559","full_name":"sbabcoc/Java-Utils","owner":"sbabcoc","description":"Nordstrom Java Utils is a small collection of general-purpose utility classes with wide applicability.","archived":false,"fork":false,"pushed_at":"2026-02-14T08:26:51.000Z","size":215,"stargazers_count":7,"open_issues_count":3,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2026-02-14T08:32:41.847Z","etag":null,"topics":["classpath","exception-handling","file-path","jar-files","java-utilities","jdbc-client","jdbc-utilities","stored-procedures"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sbabcoc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2017-11-21T08:00:12.000Z","updated_at":"2025-08-04T04:32:50.000Z","dependencies_parsed_at":"2024-05-31T20:27:48.736Z","dependency_job_id":"6e1d2e7e-42fc-490c-a2ee-f6311d42e071","html_url":"https://github.com/sbabcoc/Java-Utils","commit_stats":null,"previous_names":[],"tags_count":33,"template":false,"template_full_name":null,"purl":"pkg:github/sbabcoc/Java-Utils","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbabcoc%2FJava-Utils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbabcoc%2FJava-Utils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbabcoc%2FJava-Utils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbabcoc%2FJava-Utils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sbabcoc","download_url":"https://codeload.github.com/sbabcoc/Java-Utils/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbabcoc%2FJava-Utils/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29550828,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-17T14:33:00.708Z","status":"ssl_error","status_checked_at":"2026-02-17T14:32:58.657Z","response_time":100,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["classpath","exception-handling","file-path","jar-files","java-utilities","jdbc-client","jdbc-utilities","stored-procedures"],"created_at":"2024-10-11T18:46:47.804Z","updated_at":"2026-02-17T17:02:37.797Z","avatar_url":"https://github.com/sbabcoc.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Maven Central](https://img.shields.io/maven-central/v/com.nordstrom.tools/java-utils.svg)](https://central.sonatype.com/search?q=com.nordstrom.tools+java-utils\u0026core=gav)\r\n\r\n# NORDSTROM JAVA UTILS\r\n\r\n**Nordstrom Java Utils** is a small collection of general-purpose utility classes with wide applicability.\r\n\r\n## What You'll Find Here\r\n\r\n* [StackTrace](#stacktrace) provides a facility to capture the flow of execution that led to interesting system state transitions.\r\n* [ExceptionUnwrapper](#exceptionunwrapper) provides methods for extracting the contents of \"wrapped\" exceptions.\r\n* [UncheckedThrow](#uncheckedthrow) provides a method that uses type erasure to enable you to throw checked exception as unchecked.\r\n* [DatabaseUtils](#databaseutils) provides facilities that enable you to define collections of database queries and stored procedures in an easy-to-execute format.\r\n  * [Query Collections](#query-collections) are defined as Java enumerations that implement the `QueryAPI` interface\r\n  * [Stored Procedure Collections](#stored-procedure-collections) are defined as Java enumerations that implement the `SProcAPI` interface\r\n  * [Recommended Implementation Strategies](#recommended-implementation-strategies) to maximize usability and configurability\r\n    * [Query Collection Example](#query-collection-example)\r\n  * [Registering JDBC Providers](#registering-jdbc-providers) with the **ServiceLoader** facility of **DatabaseUtils**\r\n* [OSInfo](#osinfo) provides utility methods and abstractions for host operating system features.\r\n* [VolumeInfo](#volumeinfo) provides methods that parse the output of the 'mount' utility into a mapped collection of volume property records.\r\n* [PathUtils](#pathutils) provides a method to acquire the next file path in sequence for the specified base name and extension in the indicated target folder.\r\n* [Params Interface](#params-interface) defines concise methods for the creation of named parameters and parameter maps.\r\n* [JarUtils](#jarutils) provides methods related to Java JAR files:\r\n  * [Assembling a Classpath String](#assembling-a-classpath-string)\r\n  * [Finding a JAR File Path](#finding-a-jar-file-path)\r\n  * [Extracting the `Premain-Class` Attribute](#extracting-the-premain-class-attribute)\r\n* [UriUtils](#uriutils) provides convenience methods for assembling **URI** objects without having to deal with **URISyntaxException**.\r\n\r\n## StackTrace\r\n\r\nThe **StackTrace** class extends **Throwable** and it's intended to facilitate capture of the flow of execution that triggered system state changes that may lead to future operation errors. For example, an object that's no longer valid might get used subsequent to the event that caused it to become invalid, or a long-lived object may get discarded without corresponding resources being cleaned up.\r\n\r\nFor more details, check out the [blog post](https://blog.vanillajava.blog/2021/12/unusual-java-stacktrace-extends.html) that provided the implementation for **StackTrace**.\r\n\r\n## ExceptionUnwrapper\r\n\r\nThe **ExceptionUnwrapper** class provides methods for extracting the contents of \"wrapped\" exceptions.\r\n\r\n## UncheckedThrow\r\n\r\nThe **UncheckedThrow** class uses type erasure to enable client code to throw checked exceptions as unchecked. This allows methods to throw checked exceptions without requiring clients to handle or declare them. It should be used judiciously, as this exempts client code from handling or declaring exceptions created by their own actions. The target use case for this facility is to throw exceptions that were serialized in responses from a remote system. Although the compiler won't require clients of methods using this technique to handle or declare the suppressed exception, the JavaDoc for such methods should include a `@throws` declaration for implementers who might want to handle or declare it voluntarily.\r\n\r\n```java\r\n    ...\r\n    \r\n    String value;\r\n    try {\r\n        value = URLDecoder.decode(keyVal[1], \"UTF-8\");\r\n    } catch (UnsupportedEncodingException e) {\r\n        throw UncheckedThrow.throwUnchecked(e);\r\n    }\r\n    \r\n    ...\r\n```\r\n\r\n## DatabaseUtils\r\n\r\n**DatabaseUtils** provides facilities that enable you to define collections of database queries and stored procedures in an easy-to-execute format.\r\n\r\n### Query Collections\r\n\r\nQuery collections are defined as Java enumerations that implement the `QueryAPI` interface:\r\n* `getQueryStr` - Get the query string for this constant. This is the actual query that's sent to the database.\r\n* `getArgNames` - Get the names of the arguments for this query. This provides diagnostic information if the incorrect number of arguments is specified by the client.\r\n* `getConnection` - Get the connection string associated with this query. This eliminates the need for the client to provide this information.\r\n* `getEnum` - Get the enumeration to which this query belongs. This enables `executeQuery(Class, QueryAPI, Object[])` to retrieve the name of the query's enumerated constant for diagnostic messages.\r\n* ... see the _JavaDoc_ for the `QueryAPI` interface for additional information.\r\n\r\n### Stored Procedure Collections\r\n\r\nStore procedure collections are defined as Java enumerations that implement the `SProcAPI` interface: \r\n* `getSignature` - Get the signature for this stored procedure object. This defines the name of the stored procedure and the modes of its arguments. If the stored procedure accepts `varargs`, this will also be indicated (see _JavaDoc_ for details).\r\n* `getArgTypes` - Get the argument types for this stored procedure object.\r\n* `getConnection` - Get the connection string associated with this stored procedure. This eliminates the need for the client to provide this information.\r\n* `getEnum` - Get the enumeration to which this stored procedure belongs. This enables `executeStoredProcedure(Class, SProcAPI, Object[])` to retrieve the name of the stored procedured's enumerated constant for diagnostic messages.\r\n* ... see the _JavaDoc_ for the `SProcAPI` interface for additional information.\r\n\r\n### Recommended Implementation Strategy\r\n\r\nTo maximize usability and configurability, we recommend the following implementation strategy:\r\n* Define your collection as an enumeration:\r\n  * Query collections implement the `QueryAPI` interface.\r\n  * Stored procedure collections implement the `SProcAPI` interface.\r\n* Define each constant:\r\n  * (query) Specify a property name and a name for each argument (if any).\r\n  * (sproc) Declare the signature and the type for each argument (if any).\r\n* To assist users of your queries, preface their names with a type indicator (\u003cb\u003eGET\u003c/b\u003e or \u003cb\u003eUPDATE\u003c/b\u003e).\r\n* Back query collections with configurations that implement the **`Settings API`**:\r\n  * groupId: com.nordstrom.test-automation.tools\r\n  * artifactId: settings\r\n  * className: com.nordstrom.automation.settings.SettingsCore\r\n\r\n* To support execution on multiple endpoints, implement `QueryAPI.getConnection()` or `SProcAPI.getConnection()` with sub-configurations or other dynamic data sources (e.g. - web service).\r\n\r\n#### Query Collection Example\r\n\r\n```java\r\npublic class OpctConfig extends SettingsCore\u003cOpctConfig.OpctValues\u003e {\r\n\r\n    private static final String SETTINGS_FILE = \"OpctConfig.properties\";\r\n\r\n    private OpctConfig() throws ConfigurationException, IOException {\r\n        super(OpctValues.class);\r\n    }\r\n\r\n    public enum OpctValues implements SettingsCore.SettingsAPI, QueryAPI {\r\n        /** args: [  ] */\r\n        GET_RULE_HEAD_DETAILS(\"opct.query.getRuleHeadDetails\"),\r\n        /** args: [ name, zone_id, priority, rule_type ] */\r\n        GET_RULE_COUNT(\"opct.query.getRuleCount\", \"name\", \"zone_id\", \"priority\", \"rule_type\"),\r\n        /** args: [ role_id, user_id ] */\r\n        UPDATE_USER_ROLE(\"opct.query.updateRsmUserRole\", \"role_id\", \"user_id\"),\r\n        /** MST connection string */\r\n        MST_CONNECT(\"opct.connect.mst\"),\r\n        /** RMS connection string */\r\n        RMS_CONNECT(\"opct.connect.rms\");\r\n\r\n        private String key;\r\n        private String[] args;\r\n        private String query;\r\n\r\n        private static OpctConfig config;\r\n        private static String mstConnect;\r\n        private static String rmsConnect;\r\n\r\n        private static EnumSet\u003cOpctValues\u003e rmsQueries = EnumSet.of(UPDATE_USER_ROLE);\r\n\r\n        static {\r\n            try {\r\n                config = new OpctConfig();\r\n            } catch (ConfigurationException | IOException e) {\r\n                throw new RuntimeException(\"Unable to instantiate OPCT configuration object\", e);\r\n            }\r\n        }\r\n\r\n        OpctValues(String key, String... args) {\r\n            this.key = key;\r\n            this.args = args;\r\n        }\r\n\r\n        @Override\r\n        public String key() {\r\n            return key;\r\n        }\r\n\r\n        @Override\r\n        public String getQueryStr() {\r\n            if (query == null) {\r\n                query = config.getString(key);\r\n            }\r\n            return query;\r\n        }\r\n\r\n        @Override\r\n        public String[] getArgNames() {\r\n            return args;\r\n        }\r\n\r\n        @Override\r\n        public String getConnection() {\r\n            if (rmsQueries.contains(this)) {\r\n                return getRmsConnect();\r\n            } else {\r\n                return getMstConnect();\r\n            }\r\n        }\r\n\r\n        @Override\r\n        public Enum\u003cOpctValues\u003e getEnum() {\r\n            return this;\r\n        }\r\n\r\n        /**\r\n         * Get MST connection string.\r\n         * \r\n         * @return MST connection string\r\n         */\r\n        public static String getMstConnect() {\r\n            if (mstConnect == null) {\r\n                mstConnect = config.getString(OpctValues.MST_CONNECT.key());\r\n            }\r\n            return mstConnect;\r\n        }\r\n\r\n        /**\r\n         * Get RMS connection string.\r\n         * \r\n         * @return RMS connection string\r\n         */\r\n        public static String getRmsConnect() {\r\n            if (rmsConnect == null) {\r\n                rmsConnect = config.getString(OpctValues.RMS_CONNECT.key());\r\n            }\r\n            return rmsConnect;\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public String getSettingsPath() {\r\n        return SETTINGS_FILE;\r\n    }\r\n\r\n    /**\r\n     * Get OPCT configuration object.\r\n     *\r\n     * @return OPCT configuration object\r\n     */\r\n    public static OpctConfig getConfig() {\r\n        return OpctValues.config;\r\n    }\r\n\r\n    public enum SProcValues implements SProcAPI {\r\n        /** args: [  ] */\r\n        SHOW_SUPPLIERS(\"SHOW_SUPPLIERS()\"),\r\n        /** args: [ coffee_name, supplier_name ] */\r\n        GET_SUPPLIER_OF_COFFEE(\"GET_SUPPLIER_OF_COFFEE(\u003e, \u003c)\", Types.VARCHAR, Types.VARCHAR),\r\n        /** args: [ coffee_name, max_percent, new_price ] */\r\n        RAISE_PRICE(\"RAISE_PRICE(\u003e, \u003e, =)\", Types.VARCHAR, Types.REAL, Types.NUMERIC),\r\n        /** args: [ str, val... ] */\r\n        IN_VARARGS(\"IN_VARARGS(\u003c, \u003e:)\", Types.VARCHAR, Types.INTEGER),\r\n        /** args: [ val, str... ] */\r\n        OUT_VARARGS(\"OUT_VARARGS(\u003e, \u003c:)\", Types.INTEGER, Types.VARCHAR);\r\n\r\n        private int[] argTypes;\r\n        private String signature;\r\n\r\n        SProcValues(String signature, int... argTypes) {\r\n            this.signature = signature;\r\n            this.argTypes = argTypes;\r\n        }\r\n\r\n        @Override\r\n        public String getSignature() {\r\n            return signature;\r\n        }\r\n\r\n        @Override\r\n        public int[] getArgTypes () {\r\n            return argTypes;\r\n        }\r\n\r\n        @Override\r\n        public String getConnection() {\r\n            return OpctValues.getRmsConnect();\r\n        }\r\n\r\n        @Override\r\n        public Enum\u003cSProcValues\u003e getEnum() {\r\n            return this;\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n### Registering JDBC Drivers\r\n\r\nTo provide maximum flexibility, JDBC interacts with database instances through a defined interface (**java.sql.Driver**). Implementations of this interface translate its methods into their vendor-specific protocol, in classes called **drivers**. For example, [OracleDriver](https://download.oracle.com/otn_hosted_doc/jdeveloper/905/jdbc-javadoc/oracle/jdbc/OracleDriver.html) enables JDBC to interact with Oracle database products.\r\n\r\nIn JDBC connection URLs, the vendor and driver are specified as suffixes to the `jdbc` protocol. For the Oracle \"thin\" driver, this is `jdbc:oracle:thin`. This protocol/vendor/driver combination is handled by **OracleDriver**, and JDBC needs this class to be registered to handle this vendor-specific protocol.\r\n\r\nTo simplify the process of registering vendor-specific JDBC drivers, **DatabaseUtils** loads these for you through the Java **ServiceLoader** facility. Declare the driver(s) you need in a **ServiceLoader** provider configuration file at **_META-INF/services/java.sql.Driver_**:\r\n\r\n```\r\noracle.jdbc.OracleDriver\r\n```\r\n\r\nThis sample provider configuration file will cause **DatabaseUtils** to load the JDBC driver class for Oracle database products. The JAR that declares this class needs to be on the class path for this to work. For Maven projects, you just need to add the correct dependency:\r\n\r\n```xml\r\n[pom.xml]\r\n\u003cproject ...\u003e\r\n  [...]\r\n  \r\n  \u003cdependencies\u003e\r\n    [...]\r\n    \u003cdependency\u003e\r\n      \u003cgroupId\u003ecom.oracle.jdbc\u003c/groupId\u003e\r\n      \u003cartifactId\u003eojdbc6\u003c/artifactId\u003e\r\n      \u003cversion\u003e11.2.0.4.0\u003c/version\u003e\r\n    \u003c/dependency\u003e\r\n  \u003c/dependencies\u003e\r\n  \r\n  [...]\r\n\u003c/project\u003e\r\n```\r\n\r\n## OSInfo\r\n\r\nThe **OSInfo** class provides utility methods and abstractions for host operating system features.\r\n\r\n## VolumeInfo\r\n\r\nThe **VolumeInfo** class provides methods that parse the output of the 'mount' utility into a mapped collection of volume property records.\r\n\r\n## PathUtils\r\n\r\nThe **PathUtils** class provides a method to acquire the next file path in sequence for the specified base name and extension in the indicated target folder. If the target folder already contains at least one file that matches the specified base name and extension, the algorithm used to select the next path will always return a path whose index is one more than the highest index that currently exists. (If a single file with no index is found, its implied index is 0.)\r\n\r\n##### Example usage of `getNextPath`\r\n\r\n```java\r\n    ...\r\n    \r\n    /*\r\n     * This example gets the next path in sequence for base name `artifact`\r\n     * and extension `txt` in the TestNG output directory.\r\n     * \r\n     * For purposes of this example, the output directory already contains\r\n     * the following files: `artifact.txt`, `artifact-3.txt`\r\n     */\r\n\r\n    Path collectionPath = Paths.get(testContext.getOutputDirectory());\r\n    // =\u003e C:\\git\\my-project\\test-output\\Default suite\r\n\r\n    Path artifactPath;\r\n    try {\r\n        artifactPath = PathUtils.getNextPath(collectionPath, \"artifact\", \"txt\");\r\n        // =\u003e C:\\git\\my-project\\test-output\\Default suite\\artifact-4.txt\r\n    } catch (IOException e) {\r\n        provider.getLogger().info(\"Unable to get output path; no artifact was captured\", e);\r\n        return;\r\n    }\r\n    \r\n    ...\r\n```\r\n\r\n## Params Interface\r\n\r\nThe **Params** interface defines concise methods for the creation of named parameters and parameter maps. This facility can make your code much easier to read and maintain. The following example, which is extracted from the **Params** unit test class, demonstrates a few basic features.\r\n\r\n#### Params Example\r\n```\r\npackage com.nordstrom.example;\r\n\r\nimport static com.nordstrom.common.params.Params.param;\r\nimport static org.testng.Assert.assertEquals;\r\nimport static org.testng.Assert.assertFalse;\r\nimport static org.testng.Assert.assertTrue;\r\n\r\nimport java.util.Optional;\r\nimport org.testng.annotations.Test;\r\nimport com.nordstrom.common.params.Params;\r\n\r\npublic class ParamTest implements Params {\r\n    \r\n    @Test\r\n    public void testDefault() {\r\n        assertFalse(Params.super.getParameters().isPresent());\r\n    }\r\n    \r\n    @Test\r\n    public void testParam() {\r\n        Param param = param(\"boolean\", true);\r\n        assertEquals(param.getKey(), \"boolean\");\r\n        verifyBoolean(param.getVal());\r\n    }\r\n    \r\n    @Test\r\n    public void testParams() {\r\n        Optional\u003cMap\u003cString, Object\u003e\u003e optParameters = getParameters();\r\n        assertTrue(optParameters.isPresent());\r\n        Map\u003cString, Object\u003e parameters = optParameters.get();\r\n        assertFalse(parameters.isEmpty());\r\n        \r\n        assertTrue(parameters.containsKey(\"boolean\"));\r\n        verifyBoolean(parameters.get(\"boolean\"));\r\n    }\r\n    \r\n    private void verifyBoolean(Object value) {\r\n        assertTrue(value instanceof Boolean);\r\n        assertTrue((Boolean) value);\r\n    }\r\n    \r\n    @Override\r\n    public Optional\u003cMap\u003cString, Object\u003e\u003e getParameters() {\r\n        return Params.mapOf(param(\"boolean\", true), param(\"int\", 1), param(\"String\", \"one\"),\r\n                        param(\"Map\", Params.mapOf(param(\"key\", \"value\"))));\r\n    }\r\n}\r\n\r\n```\r\n\r\nThis code uses a static import to eliminate redundant references to the **Params** interface. It also shows the unrestricted data types of parameter values. The use of **Optional** objects enables you to provide an indication that no value was returned without the risks associated with `null`.\r\n\r\n## JarUtils\r\n\r\nThe **JarUtils** class provides methods related to Java JAR files. \r\n\r\n* `getClasspath` assembles a classpath string from the specified array of dependencies.\r\n* `findJarPathFor` finds the path to the JAR file from which the named class was loaded.\r\n* `getJarPremainClass` gets the 'Premain-Class' attribute from the indicated JAR file.\r\n\r\nThe methods of this class provide critical services for the `Local Grid` feature of [**Selenium Foundation**](https://github.com/sbabcoc/Selenium-Foundation), handling the task of locating the JAR files that declare the classes required by the Java-based servers it launches.\r\n\r\n### Assembling a Classpath String\r\n\r\nThe **`getClasspath`** method assembles a classpath string from the specified array of dependency contexts. This is useful for launching a Java sub-process, as it greatly simplifies the task of collecting the paths of JAR files that declare the classes required by your process. If any of the specified dependency contexts names the `premain` class of a Java agent, the string returned by this method will contain two records delimited by a `newline` character:\r\n\r\n* `0` - assembled classpath string\r\n* `1` - tab-delimited list of Java agent paths\r\n\r\n### Finding a JAR File Path\r\n\r\nThe **`findJarPathFor`** method will find the absolute path to the JAR file from which the named class was loaded, provided the class has been loaded from a JAR file on the local file system.\r\n\r\n### Extracting the `Premain-Class` Attribute\r\n\r\nThe **`getJarPremainClass`** method will extract the `Premain-Class` attribute from the manifest of the indicated JAR file. The value of this attribute specifies the name of a `Java agent` class declared by the JAR.\r\n\r\n## UriUtils\r\n\r\nAs of Java 20, all of the constructors of the **URL** class have been deprecated. The recommended replacement is the **`toURL()`** method of the **URI** class, but all of the constructors of _this_ class throw **URISyntaxException**. While this isn't a huge ordeal, having to handle this exception in contexts where the constructor arguments have already been validated can degrade code readability with no benefit to code safety. The **UriUtils** class provides two convenience methods that employ the same strategy used by the **`create()`** method of the **URI** class - wrapping the **URISyntaxException** in an **IllegalArgumentException**:\r\n\r\n* `makeBasicURI` assembles a basic URI from the specified components - scheme, host, port, and path.\r\n* `uriForPath` assembles a URI for the specified path under the provided context.\r\n\r\nNote that the **`toURL()`** method of the **URI** class throws the **MalformedURLException**, but this exception is a subclass of **IOException**, which affected code is almost certain to be handling already.\r\n\r\n\u003e Written with [StackEdit](https://stackedit.io/).\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsbabcoc%2Fjava-utils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsbabcoc%2Fjava-utils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsbabcoc%2Fjava-utils/lists"}