diff --git a/.gitignore b/.gitignore index 8f3056e..0566805 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ /.metadata/ /.recommenders/ .classpath +.project +/.settings/ # OS .DS_Store diff --git a/.project b/.project deleted file mode 100644 index d7a464d..0000000 --- a/.project +++ /dev/null @@ -1,23 +0,0 @@ - - - plurl - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.eclipse.jdt.core.javanature - org.eclipse.m2e.core.maven2Nature - - - diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index f9fe345..0000000 --- a/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,4 +0,0 @@ -eclipse.preferences.version=1 -encoding//src/main/java=UTF-8 -encoding//src/test/java=UTF-8 -encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 98e4b3f..0000000 --- a/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,15 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.8 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore -org.eclipse.jdt.core.compiler.release=enabled -org.eclipse.jdt.core.compiler.source=1.8 diff --git a/src/main/java/org/eclipse/osgitech/plurl/impl/PlurlImpl.java b/src/main/java/org/eclipse/osgitech/plurl/impl/PlurlImpl.java index 8f924be..d8d0888 100644 --- a/src/main/java/org/eclipse/osgitech/plurl/impl/PlurlImpl.java +++ b/src/main/java/org/eclipse/osgitech/plurl/impl/PlurlImpl.java @@ -1071,14 +1071,34 @@ protected void remove(URLStreamHandlerFactory f) { PlurlStreamHandler newProxyPlurlStreamHandler(URLStreamHandler handler) { Class checkClass = handler.getClass(); while (checkClass != null) { - for (Class i : checkClass.getInterfaces()) { - if (PLURL_STREAM_HANDLER_CLASS_NAME.equals(i.getName())) { - for (Method m : i.getMethods()) { - if (m.getName().equals("parseURL")) { //$NON-NLS-1$ - Class plurlStreamHandlerClass = i; - Class plurlSetterClass = m.getParameterTypes()[0]; - return new PlurlStreamHandlerProxy(handler, plurlStreamHandlerClass, plurlSetterClass); + for (Class handlerInterfaces : checkClass.getInterfaces()) { + // To determine if we can proxy the handler we look for an interface that defines a method + // public void parseURL(PlurlSetter plurlSetter, URL u, String spec, int start, int limit); + // But we cannot search for it the conventional way because the PlurlSetter may be a different + // copy from ours. + for (Method m : handlerInterfaces.getMethods()) { + if (m.getName().equals("parseURL")) { //$NON-NLS-1$ + Class[] params = m.getParameterTypes(); + if (params.length == 5) { + // check the first param to see if it is a PlurlSetter candidate + Class plurlSetterCandidate = params[0]; + if (plurlSetterCandidate.isInterface()) { + try { + // try finding the appropriate setURL method + plurlSetterCandidate.getMethod("setURL", URL.class, String.class, String.class, Integer.TYPE, String.class, String.class, + String.class, String.class, String.class); + } catch (Exception e) { + // move on to the next interface + continue; + } + } + } else { + // Wrong number of arguments for parseURL; move on to next interface + continue; } + Class plurlStreamHandlerClass = handlerInterfaces; + Class plurlSetterClass = m.getParameterTypes()[0]; + return new PlurlStreamHandlerProxy(handler, plurlStreamHandlerClass, plurlSetterClass); } } } diff --git a/src/test/java/org/eclipse/osgitech/plurl/test/MultiplePlurlInstallWithParentsTests.java b/src/test/java/org/eclipse/osgitech/plurl/test/MultiplePlurlInstallWithParentsTests.java index 80c36a8..d1ffcc7 100644 --- a/src/test/java/org/eclipse/osgitech/plurl/test/MultiplePlurlInstallWithParentsTests.java +++ b/src/test/java/org/eclipse/osgitech/plurl/test/MultiplePlurlInstallWithParentsTests.java @@ -94,6 +94,11 @@ public void testAddRemoveProxyFactory() throws IOException { doTestMultiplePlurlsAddRemoveFactory(TestFactoryType.PLURL_PROXY_FACTORY); } + @Test + public void testAddRemovePlurlCopyFactory() throws IOException { + doTestMultiplePlurlsAddRemoveFactory(TestFactoryType.PLURL_COPY_FACTORY); + } + private static void doTestMultiplePlurlsAddRemoveFactory(TestFactoryType type) throws IOException { doAddRemoveFactory(type, // listOfPlurlTestHandlers.get(listOfPlurlTestHandlers.size() - 1), // @@ -120,6 +125,11 @@ public void testURLContextProxyFactory() throws IOException { doTestMultiplePlurlsTestURLContext(TestFactoryType.PLURL_PROXY_FACTORY); } + @Test + public void testURLContextPlurlCopyFactory() throws IOException { + doTestMultiplePlurlsTestURLContext(TestFactoryType.PLURL_COPY_FACTORY); + } + private static void doTestMultiplePlurlsTestURLContext(TestFactoryType type) throws IOException { doTestURLContext(type, // listOfPlurlTestHandlers.get(listOfPlurlTestHandlers.size() - 1), // @@ -146,6 +156,11 @@ public void testContentProxyFactory() throws IOException { doTestMultiplePlurlsContent(TestFactoryType.PLURL_PROXY_FACTORY); } + @Test + public void testContentPlurlCopyFactory() throws IOException { + doTestMultiplePlurlsContent(TestFactoryType.PLURL_COPY_FACTORY); + } + private static void doTestMultiplePlurlsContent(TestFactoryType type) throws IOException { doTestContentContext(type, // listOfPlurlTestHandlers.get(listOfPlurlTestHandlers.size() - 1), // diff --git a/src/test/java/org/eclipse/osgitech/plurl/test/PlurlContentHandlerFactoryTest.java b/src/test/java/org/eclipse/osgitech/plurl/test/PlurlContentHandlerFactoryTest.java index 502d502..3c98037 100644 --- a/src/test/java/org/eclipse/osgitech/plurl/test/PlurlContentHandlerFactoryTest.java +++ b/src/test/java/org/eclipse/osgitech/plurl/test/PlurlContentHandlerFactoryTest.java @@ -106,6 +106,11 @@ public void testAddRemoveProxyFactory() throws IOException { doAddRemoveFactory(TestFactoryType.PLURL_PROXY_FACTORY); } + @Test + public void testAddRemovePlurlCopyFactory() throws IOException { + doAddRemoveFactory(TestFactoryType.PLURL_COPY_FACTORY); + } + private void doAddRemoveFactory(TestFactoryType type) throws IOException { assumeThat(canReflect(type), is(String.valueOf(true))); @@ -180,6 +185,11 @@ public void testGCProxyFactory() throws IOException { doTestGCURLFactory(TestFactoryType.PLURL_PROXY_FACTORY); } + @Test + public void testGCPlurlCopyFactory() throws IOException { + doTestGCURLFactory(TestFactoryType.PLURL_COPY_FACTORY); + } + private void doTestGCURLFactory(TestFactoryType type) throws IOException { assumeThat(canReflect(type), is(String.valueOf(true))); @@ -226,6 +236,11 @@ public void testContentProxyFactory() throws IOException { doTestContentContext(TestFactoryType.PLURL_PROXY_FACTORY, plurlTestHandlers, null); } + @Test + public void testContentPlurlCopyFactory() throws IOException { + doTestContentContext(TestFactoryType.PLURL_COPY_FACTORY, plurlTestHandlers, null); + } + static void doTestContentContext(TestFactoryType type, PlurlTestHandlers handlersToUse, PlurlTestHandlers handlersToUninstall) throws IOException { assumeThat(canReflect(type), is(String.valueOf(true))); diff --git a/src/test/java/org/eclipse/osgitech/plurl/test/PlurlStreamHandlerFactoryTest.java b/src/test/java/org/eclipse/osgitech/plurl/test/PlurlStreamHandlerFactoryTest.java index d805450..296937d 100644 --- a/src/test/java/org/eclipse/osgitech/plurl/test/PlurlStreamHandlerFactoryTest.java +++ b/src/test/java/org/eclipse/osgitech/plurl/test/PlurlStreamHandlerFactoryTest.java @@ -73,6 +73,11 @@ public void testAddRemoveProxyFactory() throws IOException { doAddRemoveFactory(TestFactoryType.PLURL_PROXY_FACTORY, plurlTestHandlers, null); } + @Test + public void testAddRemovePlurlCopyFactory() throws IOException { + doAddRemoveFactory(TestFactoryType.PLURL_COPY_FACTORY, plurlTestHandlers, null); + } + static void doAddRemoveFactory(TestFactoryType type, PlurlTestHandlers handlersToUse, PlurlTestHandlers handlersToUninstall) throws IOException { assumeThat(canReflect(type), is(String.valueOf(true))); @@ -151,6 +156,11 @@ public void testURLContextProxyFactory() throws IOException { doTestURLContext(TestFactoryType.PLURL_PROXY_FACTORY, plurlTestHandlers, null); } + @Test + public void testURLContextPlurlCopyFactory() throws IOException { + doTestURLContext(TestFactoryType.PLURL_COPY_FACTORY, plurlTestHandlers, null); + } + static void doTestURLContext(TestFactoryType type, PlurlTestHandlers handlersToUse, PlurlTestHandlers handlersToUninstall) throws IOException { assumeThat(canReflect(type), is(String.valueOf(true))); @@ -246,6 +256,11 @@ public void testGCProxyFactory() throws IOException { doTestGCURLFactory(TestFactoryType.PLURL_PROXY_FACTORY); } + @Test + public void testGCPlurlCopyFactory() throws IOException { + doTestGCURLFactory(TestFactoryType.PLURL_COPY_FACTORY); + } + private void doTestGCURLFactory(TestFactoryType type) throws IOException { assumeThat(canReflect(type), is(String.valueOf(true))); diff --git a/src/test/java/org/eclipse/osgitech/plurl/test/PlurlTestHandlers.java b/src/test/java/org/eclipse/osgitech/plurl/test/PlurlTestHandlers.java index c245a72..db8d996 100644 --- a/src/test/java/org/eclipse/osgitech/plurl/test/PlurlTestHandlers.java +++ b/src/test/java/org/eclipse/osgitech/plurl/test/PlurlTestHandlers.java @@ -123,6 +123,24 @@ public boolean shouldHandle(Class clazz) { } } + public static class TestPlurlCopyContentHandlerFactory extends TestContentHandlerFactory + implements org.eclipse.osgitech.plurl.test.copy.PlurlContentHandlerFactory { + + public TestPlurlCopyContentHandlerFactory(List mimetypes, Class... shouldHandleClasses) { + super(mimetypes, shouldHandleClasses); + } + + @Override + protected ContentHandler createContentHandlerImpl(String mimetype) { + return new TestContentHandler(mimetype); + } + + @Override + public boolean shouldHandle(Class clazz) { + return shouldHandleImpl(clazz); + } + } + public static class TestContentHandler extends ContentHandler { private final String mimetype; @@ -184,6 +202,21 @@ public boolean shouldHandle(Class clazz) { } } + public static class TestPlurlCopyStreamHandlerFactory extends TestURLStreamHandlerFactory implements org.eclipse.osgitech.plurl.test.copy.PlurlStreamHandlerFactory { + public TestPlurlCopyStreamHandlerFactory(List protocols, Class... shouldHandleClasses) { + super(protocols, shouldHandleClasses); + } + @Override + protected URLStreamHandler createURLStreamHandlerImpl(String protocol) { + return new TestPlurlCopyStreamHandler(false); + } + + @Override + public boolean shouldHandle(Class clazz) { + return shouldHandleImpl(clazz); + } + } + static class CatchAllPlurlFactory extends TestURLStreamHandlerFactory implements PlurlStreamHandlerFactory { CatchAllPlurlFactory(String... protos) { super(Arrays.asList(protos)); @@ -281,8 +314,58 @@ public String toString() { } } + static class TestPlurlCopyStreamHandler extends org.eclipse.osgitech.plurl.test.copy.PlurlStreamHandlerBase { + private final boolean unsupported; + + public TestPlurlCopyStreamHandler() { + this(false); + } + + public TestPlurlCopyStreamHandler(boolean unsupported) { + this.unsupported = unsupported; + } + + @Override + public URLConnection openConnection(URL u) throws IOException { + if (unsupported) { + throw new UnsupportedOperationException(); + } + return new URLConnection(u) { + @Override + public String getContentType() { + // for testing purposes just use the test protocol name + return u.getProtocol(); + } + + @Override + public void connect() throws IOException { + // do nothing + } + + @Override + public InputStream getInputStream() throws IOException { + // just testing + return new ByteArrayInputStream(u.getProtocol().getBytes()); + } + }; + } + + @Override + public void parseURL(PlurlSetter setter, URL u, String spec, int start, int limit) { + if (unsupported) { + throw new UnsupportedOperationException(); + } + super.parseURL(setter, u, spec, start, limit); + } + + @Override + public String toString() { + return getClass().getSimpleName() + '@' + System.identityHashCode(this); + } + } + enum TestFactoryType { - PLURL_FACTORY, PLURL_PROXY_FACTORY, NOT_PLURL_FACTORY, LEGACY_FACTORY + PLURL_FACTORY, PLURL_PROXY_FACTORY, PLURL_COPY_FACTORY, NOT_PLURL_FACTORY, LEGACY_FACTORY } static final boolean CAN_REFLECT_SET_URL_HANDLER; static final String CAN_REFLECT_ON_URL_STREAM_HANDLER; @@ -375,6 +458,8 @@ static TestURLStreamHandlerFactory createTestURLStreamHandlerFactory(TestFactory return new TestNotPlurlStreamHandlerFactory(protocols, shouldHandleClasses); case PLURL_PROXY_FACTORY: return createProxyURLHandlerFactory(protocols, shouldHandleClasses); + case PLURL_COPY_FACTORY: + return new TestPlurlCopyStreamHandlerFactory(protocols, shouldHandleClasses); default: throw new UnsupportedOperationException("Unknown type: " + type); } @@ -407,6 +492,8 @@ static TestContentHandlerFactory createTestContentHandlerFactory(TestFactoryType return new TestNotPlurlContentHandlerFactory(mimetypes, shouldHandleClasses); case PLURL_PROXY_FACTORY: return createProxyContentFactory(mimetypes, shouldHandleClasses); + case PLURL_COPY_FACTORY: + return new TestPlurlCopyContentHandlerFactory(mimetypes, shouldHandleClasses); default: throw new UnsupportedOperationException("Unknown type: " + type); } @@ -680,7 +767,7 @@ static Field getField(Class clazz, Class type, boolean instance) { } static String canReflect(TestFactoryType type) { - if (type == TestFactoryType.PLURL_FACTORY || type == TestFactoryType.PLURL_PROXY_FACTORY) { + if (type == TestFactoryType.PLURL_FACTORY || type == TestFactoryType.PLURL_PROXY_FACTORY || type == TestFactoryType.PLURL_COPY_FACTORY) { return String.valueOf(true); } return PlurlTestHandlers.CAN_REFLECT_ON_URL_STREAM_HANDLER; diff --git a/src/test/java/org/eclipse/osgitech/plurl/test/copy/PlurlContentHandlerFactory.java b/src/test/java/org/eclipse/osgitech/plurl/test/copy/PlurlContentHandlerFactory.java new file mode 100644 index 0000000..5e3a431 --- /dev/null +++ b/src/test/java/org/eclipse/osgitech/plurl/test/copy/PlurlContentHandlerFactory.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2025 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.osgitech.plurl.test.copy; + +import java.net.ContentHandlerFactory; + +/** + * A {@link ContentHandlerFactory} that also implements {@link PlurlFactory} + */ +public interface PlurlContentHandlerFactory extends ContentHandlerFactory, PlurlFactory { + // a marker interface for a ContentHandlerFactory that implements PlurlFactory +} diff --git a/src/test/java/org/eclipse/osgitech/plurl/test/copy/PlurlFactory.java b/src/test/java/org/eclipse/osgitech/plurl/test/copy/PlurlFactory.java new file mode 100644 index 0000000..e7d2813 --- /dev/null +++ b/src/test/java/org/eclipse/osgitech/plurl/test/copy/PlurlFactory.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2025 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.osgitech.plurl.test.copy; + + +public interface PlurlFactory { + + boolean shouldHandle(Class clazz); +} diff --git a/src/test/java/org/eclipse/osgitech/plurl/test/copy/PlurlStreamHandler.java b/src/test/java/org/eclipse/osgitech/plurl/test/copy/PlurlStreamHandler.java new file mode 100644 index 0000000..c7f8d33 --- /dev/null +++ b/src/test/java/org/eclipse/osgitech/plurl/test/copy/PlurlStreamHandler.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2025 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.osgitech.plurl.test.copy; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; + + +public interface PlurlStreamHandler { + + public interface PlurlSetter { + + public void setURL(URL u, String protocol, String host, int port, String authority, String userInfo, + String path, String query, String ref); + } + + public boolean equals(URL u1, URL u2); + + public int hashCode(URL u); + + public boolean hostsEqual(URL u1, URL u2); + + public int getDefaultPort(); + + public InetAddress getHostAddress(URL u); + + public URLConnection openConnection(URL u) throws IOException; + + public URLConnection openConnection(URL u, Proxy p) throws IOException; + + public boolean sameFile(URL u1, URL u2); + + public String toExternalForm(URL u); + + public void parseURL(PlurlSetter plurlSetter, URL u, String spec, int start, int limit); + + public void setURL(URL u, String proto, String host, int port, String file, String ref); + + public void setURL(URL u, String proto, String host, int port, String auth, String user, String path, + String query, String ref); +} diff --git a/src/test/java/org/eclipse/osgitech/plurl/test/copy/PlurlStreamHandlerBase.java b/src/test/java/org/eclipse/osgitech/plurl/test/copy/PlurlStreamHandlerBase.java new file mode 100644 index 0000000..b98b8e9 --- /dev/null +++ b/src/test/java/org/eclipse/osgitech/plurl/test/copy/PlurlStreamHandlerBase.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright (c) 2025 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.osgitech.plurl.test.copy; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +public abstract class PlurlStreamHandlerBase extends URLStreamHandler implements PlurlStreamHandler { + private volatile PlurlSetter plurlSetter; + + @Override + public abstract URLConnection openConnection(URL u) throws IOException; + + @Override + public void parseURL(PlurlSetter setter, URL u, String spec, int start, int limit) { + this.plurlSetter = setter; + parseURL(u, spec, start, limit); + } + + @Override + public URLConnection openConnection(URL u, Proxy p) throws IOException { + return super.openConnection(u, p); + } + + @Override + public String toExternalForm(URL u) { + return super.toExternalForm(u); + } + + @Override + public boolean equals(URL u1, URL u2) { + return super.equals(u1, u2); + } + + @Override + public int getDefaultPort() { + return super.getDefaultPort(); + } + + @Override + public InetAddress getHostAddress(URL u) { + return super.getHostAddress(u); + } + + @Override + public int hashCode(URL u) { + return super.hashCode(u); + } + + @Override + public boolean hostsEqual(URL u1, URL u2) { + return super.hostsEqual(u1, u2); + } + + @Override + public boolean sameFile(URL u1, URL u2) { + return super.sameFile(u1, u2); + } + + @SuppressWarnings("deprecation") + @Override + public void setURL(URL u, String proto, String host, int port, String file, String ref) { + PlurlSetter current = plurlSetter; + if (current == null) { + // something is calling the handler directly, probably passed it to URL directly + super.setURL(u, proto, host, port, null, null, file, null, ref); + } else { + current.setURL(u, proto, host, port, null, null, file, null, ref); + } + } + + @Override + public void setURL(URL u, String proto, String host, int port, String auth, String user, String path, + String query, String ref) { + PlurlSetter current = plurlSetter; + if (current == null) { + // something is calling the handler directly, probably passed it to URL directly + super.setURL(u, proto, host, port, auth, user, path, query, ref); + } else { + current.setURL(u, proto, host, port, auth, user, path, query, ref); + } + } + +} diff --git a/src/test/java/org/eclipse/osgitech/plurl/test/copy/PlurlStreamHandlerFactory.java b/src/test/java/org/eclipse/osgitech/plurl/test/copy/PlurlStreamHandlerFactory.java new file mode 100644 index 0000000..52619ab --- /dev/null +++ b/src/test/java/org/eclipse/osgitech/plurl/test/copy/PlurlStreamHandlerFactory.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2025 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.osgitech.plurl.test.copy; + +import java.net.URLStreamHandler; +import java.net.URLStreamHandlerFactory; + +/** + * A {@link URLStreamHandlerFactory} that also implements {@link PlurlFactory} + */ +public interface PlurlStreamHandlerFactory extends URLStreamHandlerFactory, PlurlFactory { + + /** + * A factory is expected to return {@link URLStreamHandler} instances that also + * implement {@link PlurlStreamHandler}. If the returned handler does not + * implement {@link PlurlStreamHandler} then deep reflection is required and the + * JVM may require the "--add-opens" option in order to open the "java.net" + * package for reflection. For example: + * + *
+	 * --add-opens java.base/java.net=ALL-UNNAMED
+	 * 
+ * + * @see URLStreamHandlerFactory#createURLStreamHandler(String) + */ + @Override + URLStreamHandler createURLStreamHandler(String protocol); +}