From 2819b9bab4bf660a969954993d3ce5d2cb270c4c Mon Sep 17 00:00:00 2001 From: Michael Edgar Date: Tue, 21 Dec 2021 07:27:24 -0500 Subject: [PATCH] Allow loading included schemas on the class-path --- .../schema/ClasspathURLStreamHandler.java | 28 +++++++++++++ .../edi/internal/schema/SchemaReaderV4.java | 13 +++++- .../schema/ClasspathURLStreamHandlerTest.java | 40 +++++++++++++++++++ .../x12/005010X222/837_REF_impls.xml | 2 +- .../x12/005010X222/837_loop1000_only.xml | 2 +- 5 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 src/main/java/io/xlate/edi/internal/schema/ClasspathURLStreamHandler.java create mode 100644 src/test/java/io/xlate/edi/internal/schema/ClasspathURLStreamHandlerTest.java diff --git a/src/main/java/io/xlate/edi/internal/schema/ClasspathURLStreamHandler.java b/src/main/java/io/xlate/edi/internal/schema/ClasspathURLStreamHandler.java new file mode 100644 index 00000000..bb695212 --- /dev/null +++ b/src/main/java/io/xlate/edi/internal/schema/ClasspathURLStreamHandler.java @@ -0,0 +1,28 @@ +package io.xlate.edi.internal.schema; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +class ClasspathURLStreamHandler extends URLStreamHandler { + /** The classloader to find resources from. */ + private final ClassLoader classLoader; + + public ClasspathURLStreamHandler(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + @Override + protected URLConnection openConnection(URL u) throws IOException { + final String resourcePath = u.getPath(); + final URL resourceUrl = classLoader.getResource(resourcePath); + + if (resourceUrl == null) { + throw new FileNotFoundException("Class-path resource not found: " + resourcePath); + } + + return resourceUrl.openConnection(); + } +} diff --git a/src/main/java/io/xlate/edi/internal/schema/SchemaReaderV4.java b/src/main/java/io/xlate/edi/internal/schema/SchemaReaderV4.java index 5febfb48..aaf6f476 100644 --- a/src/main/java/io/xlate/edi/internal/schema/SchemaReaderV4.java +++ b/src/main/java/io/xlate/edi/internal/schema/SchemaReaderV4.java @@ -48,7 +48,18 @@ protected void readInclude(XMLStreamReader reader, Map types) t } } - URL schemaLocation = context != null ? new URL(context, location) : new URL(location); + URL schemaLocation; + + if (location.startsWith("classpath:")) { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + if (location.startsWith("classpath:/")) { + location = location.substring(0, "classpath:".length()) + location.substring("classpath:/".length()); + } + schemaLocation = new URL(null, location, new ClasspathURLStreamHandler(loader)); + } else { + schemaLocation = new URL(context, location); + } + types.putAll(StaEDISchemaFactory.readSchemaTypes(schemaLocation, super.properties)); reader.nextTag(); // End of include } catch (Exception e) { diff --git a/src/test/java/io/xlate/edi/internal/schema/ClasspathURLStreamHandlerTest.java b/src/test/java/io/xlate/edi/internal/schema/ClasspathURLStreamHandlerTest.java new file mode 100644 index 00000000..7d791257 --- /dev/null +++ b/src/test/java/io/xlate/edi/internal/schema/ClasspathURLStreamHandlerTest.java @@ -0,0 +1,40 @@ +package io.xlate.edi.internal.schema; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class ClasspathURLStreamHandlerTest { + + ClasspathURLStreamHandler cut; + + @BeforeEach + void setup() { + cut = new ClasspathURLStreamHandler(getClass().getClassLoader()); + } + + @Test + void testResourceUrlResolvesNull() throws MalformedURLException { + URL target = new URL(null, "classpath:does/not/exist.txt", cut); + @SuppressWarnings("unused") + FileNotFoundException ex = assertThrows(FileNotFoundException.class, () -> { + target.openConnection(); + }); + } + + @Test + void testResourceUrlFound() throws IOException { + URL target = new URL(null, "classpath:logging.properties", cut); + URLConnection connection = target.openConnection(); + assertNotNull(connection); + } + +} diff --git a/src/test/resources/x12/005010X222/837_REF_impls.xml b/src/test/resources/x12/005010X222/837_REF_impls.xml index d27d6579..4e71e66f 100644 --- a/src/test/resources/x12/005010X222/837_REF_impls.xml +++ b/src/test/resources/x12/005010X222/837_REF_impls.xml @@ -1,7 +1,7 @@ - + diff --git a/src/test/resources/x12/005010X222/837_loop1000_only.xml b/src/test/resources/x12/005010X222/837_loop1000_only.xml index a1355d67..8a284553 100644 --- a/src/test/resources/x12/005010X222/837_loop1000_only.xml +++ b/src/test/resources/x12/005010X222/837_loop1000_only.xml @@ -1,7 +1,7 @@ - +