Repository: networknt/json-schema-validator (java)

Issue:
Maps of URLs can have performance impacts
While incorporating the feature of URL mappings into an app, [Spotbugs](https://spotbugs.readthedocs.io/en/stable/) flagged the [inefficient use of URL in maps](https://spotbugs.readthedocs.io/en/stable/bugDescriptions.html#dm-maps-and-sets-of-urls-can-be-performance-hogs-dmi-collection-of-urls).

While this is an easy fix, it does make a breaking change in the API since 1.0.5.

Pull request description:
fix: avoid performance penalty of using URL in map or set
See https://spotbugs.readthedocs.io/en/stable/bugDescriptions.html#dm-maps-and-sets-of-urls-can-be-performance-hogs-dmi-collection-of-urls

Fixes #136 by introducing breaking change to the URL mapping feature of versions 1.0.5 thru 1.0.7

Patch:
diff --git a/src/main/java/com/networknt/schema/JsonSchemaFactory.java b/src/main/java/com/networknt/schema/JsonSchemaFactory.java
index 01dadf3..dcda5bd 100644
--- a/src/main/java/com/networknt/schema/JsonSchemaFactory.java
+++ b/src/main/java/com/networknt/schema/JsonSchemaFactory.java
@@ -29,6 +29,7 @@ import org.slf4j.LoggerFactory;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.networknt.schema.url.StandardURLFetcher;
+import com.networknt.schema.url.URLFactory;
 import com.networknt.schema.url.URLFetcher;
 
 public class JsonSchemaFactory {
@@ -41,7 +42,7 @@ public class JsonSchemaFactory {
         private URLFetcher urlFetcher;
         private String defaultMetaSchemaURI;
         private Map<String, JsonMetaSchema> jsonMetaSchemas = new HashMap<String, JsonMetaSchema>();
-        private Map<URL, URL> urlMap = new HashMap<URL, URL>();
+        private Map<String, String> urlMap = new HashMap<String, String>();
         
         public Builder objectMapper(ObjectMapper objectMapper) {
             this.objectMapper = objectMapper;
@@ -70,7 +71,7 @@ public class JsonSchemaFactory {
             return this;
         }
         
-        public Builder addUrlMappings(Map<URL, URL> map) {
+        public Builder addUrlMappings(Map<String, String> map) {
             this.urlMap.putAll(map);
             return this;
         }
@@ -91,9 +92,9 @@ public class JsonSchemaFactory {
     private final URLFetcher urlFetcher;
     private final String defaultMetaSchemaURI;
     private final Map<String, JsonMetaSchema> jsonMetaSchemas;
-    private final Map<URL, URL> urlMap;
+    private final Map<String, String> urlMap;
 
-    private JsonSchemaFactory(ObjectMapper mapper, URLFetcher urlFetcher, String defaultMetaSchemaURI, Map<String, JsonMetaSchema> jsonMetaSchemas, Map<URL, URL> urlMap) {
+    private JsonSchemaFactory(ObjectMapper mapper, URLFetcher urlFetcher, String defaultMetaSchemaURI, Map<String, JsonMetaSchema> jsonMetaSchemas, Map<String, String> urlMap) {
         if (mapper == null) {
             throw new IllegalArgumentException("ObjectMapper must not be null");
         }
@@ -204,9 +205,9 @@ public class JsonSchemaFactory {
     public JsonSchema getSchema(URL schemaURL, SchemaValidatorsConfig config) {
         try {
             InputStream inputStream = null;
-            Map<URL, URL> map = (config != null) ? config.getUrlMappings() : new HashMap<URL, URL>(urlMap);
+            Map<String, String> map = (config != null) ? config.getUrlMappings() : new HashMap<String, String>(urlMap);
             map.putAll(urlMap);
-            URL mappedURL = map.getOrDefault(schemaURL, schemaURL);
+            URL mappedURL = URLFactory.toURL(map.getOrDefault(schemaURL.toString(), schemaURL.toString()));
             try {
                 inputStream = urlFetcher.fetch(mappedURL);
                 JsonNode schemaNode = mapper.readTree(inputStream);
diff --git a/src/main/java/com/networknt/schema/SchemaValidatorsConfig.java b/src/main/java/com/networknt/schema/SchemaValidatorsConfig.java
index bdb16ba..3aad2a1 100644
--- a/src/main/java/com/networknt/schema/SchemaValidatorsConfig.java
+++ b/src/main/java/com/networknt/schema/SchemaValidatorsConfig.java
@@ -18,7 +18,6 @@ package com.networknt.schema;
 
 import java.util.HashMap;
 import java.util.Map;
-import java.net.URL;
 
 public class SchemaValidatorsConfig {
     /**
@@ -43,7 +42,7 @@ public class SchemaValidatorsConfig {
      * validation of schemas that refer to public URLs. This is merged with any mappings the {@link JsonSchemaFactory} 
      * may have been built with.
      */
-    private Map<URL, URL> urlMappings = new HashMap<URL, URL>();
+    private Map<String, String> urlMappings = new HashMap<String, String>();
 
     public boolean isTypeLoose() {
         return typeLoose;
@@ -53,11 +52,12 @@ public class SchemaValidatorsConfig {
         this.typeLoose = typeLoose;
     }
 
-    public Map<URL, URL> getUrlMappings() {
-        return new HashMap<URL, URL>(urlMappings);
+    public Map<String, String> getUrlMappings() {
+        // return a copy of the mappings
+        return new HashMap<String, String>(urlMappings);
     }
 
-    public void setUrlMappings(Map<URL, URL> urlMappings) {
+    public void setUrlMappings(Map<String, String> urlMappings) {
         this.urlMappings = urlMappings;
     }
 
@@ -83,6 +83,6 @@ public class SchemaValidatorsConfig {
 
     private void loadDefaultConfig() {
         this.typeLoose = true;
-        this.urlMappings = new HashMap<URL, URL>();
+        this.urlMappings = new HashMap<String, String>();
     }
 }


Test patch:
diff --git a/src/test/java/com/networknt/schema/UrlMappingTest.java b/src/test/java/com/networknt/schema/UrlMappingTest.java
index c362e5c..72bf01b 100644
--- a/src/test/java/com/networknt/schema/UrlMappingTest.java
+++ b/src/test/java/com/networknt/schema/UrlMappingTest.java
@@ -141,11 +141,11 @@ public class UrlMappingTest {
         assertEquals(0, schema.validate(mapper.readTree("[]")).size());
     }
 
-    private Map<URL, URL> getUrlMappingsFromUrl(URL url) throws MalformedURLException, IOException {
-        HashMap<URL, URL> map = new HashMap<URL, URL>();
+    private Map<String, String> getUrlMappingsFromUrl(URL url) throws MalformedURLException, IOException {
+        HashMap<String, String> map = new HashMap<String, String>();
         for (JsonNode mapping : mapper.readTree(url)) {
-            map.put(URLFactory.toURL(mapping.get("publicURL").asText()),
-                    URLFactory.toURL(mapping.get("localURL").asText()));
+            map.put(mapping.get("publicURL").asText(),
+                    mapping.get("localURL").asText());
         }
         return map;
     }