129129 * the protocol, host name, or port number is missing, the value is
130130 * inherited from the fully specified URL. The file component must be
131131 * specified. The optional fragment is not inherited.
132+ *
133+ * <h2><a id="constructor-deprecation"></a>Constructing instances of {@code URL}</h2>
134+ *
135+ * The {@code java.net.URL} constructors are deprecated.
136+ * Developers are encouraged to use {@link URI java.net.URI} to parse
137+ * or construct a {@code URL}. In cases where an instance of {@code
138+ * java.net.URL} is needed to open a connection, {@link URI} can be used
139+ * to construct or parse the URL string, possibly calling {@link
140+ * URI#parseServerAuthority()} to validate that the authority component
141+ * can be parsed as a server-based authority, and then calling
142+ * {@link URI#toURL()} to create the {@code URL} instance.
143+ * <p>
144+ * The URL constructors are specified to throw
145+ * {@link MalformedURLException} but the actual parsing/validation
146+ * that is performed is implementation dependent. Some parsing/validation
147+ * may be delayed until later, when the underlying {@linkplain
148+ * URLStreamHandler stream handler's implementation} is called.
149+ * Being able to construct an instance of {@code URL} doesn't
150+ * provide any guarantee about its conformance to the URL
151+ * syntax specification.
132152 * <p>
133153 * The URL class does not itself encode or decode any URL components
134154 * according to the escaping mechanism defined in RFC2396. It is the
152172 *
153173 * @apiNote
154174 *
175+ * <a id="integrity"></a>
155176 * Applications working with file paths and file URIs should take great
156177 * care to use the appropriate methods to convert between the two.
157178 * The {@link Path#of(URI)} factory method and the {@link File#File(URI)}
164185 * from the direct string representation of a {@code File} or {@code Path}
165186 * instance.
166187 * <p>
188+ * Before constructing a {@code URL} from a {@code URI}, and depending
189+ * on the protocol involved, applications should consider validating
190+ * whether the URI authority {@linkplain URI#parseServerAuthority()
191+ * can be parsed as server-based}.
192+ * <p>
167193 * Some components of a URL or URI, such as <i>userinfo</i>, may
168194 * be abused to construct misleading URLs or URIs. Applications
169195 * that deal with URLs or URIs should take into account
@@ -373,7 +399,11 @@ public final class URL implements java.io.Serializable {
373399 * @see java.net.URLStreamHandler
374400 * @see java.net.URLStreamHandlerFactory#createURLStreamHandler(
375401 * java.lang.String)
402+ * @deprecated Use {@link URI#toURL()} to construct an instance of URL. See the note on
403+ * <a href="#constructor-deprecation">constructor deprecation</a> for more
404+ * details.
376405 */
406+ @ Deprecated (since = "20" )
377407 public URL (String protocol , String host , int port , String file )
378408 throws MalformedURLException
379409 {
@@ -399,7 +429,11 @@ public URL(String protocol, String host, int port, String file)
399429 * rejects, or is known to reject, the {@code URL}
400430 * @see java.net.URL#URL(java.lang.String, java.lang.String,
401431 * int, java.lang.String)
432+ * @deprecated Use {@link URI#toURL()} to construct an instance of URL. See the note on
433+ * <a href="#constructor-deprecation">constructor deprecation</a> for more
434+ * details.
402435 */
436+ @ Deprecated (since = "20" )
403437 public URL (String protocol , String host , String file )
404438 throws MalformedURLException {
405439 this (protocol , host , -1 , file );
@@ -446,7 +480,13 @@ public URL(String protocol, String host, String file)
446480 * java.lang.String)
447481 * @see SecurityManager#checkPermission
448482 * @see java.net.NetPermission
483+ * @deprecated
484+ * Use {@link #of(URI, URLStreamHandler)} to construct an instance of URL
485+ * associated with a custom protocol handler.
486+ * See the note on <a href="#constructor-deprecation">constructor deprecation</a>
487+ * for more details.
449488 */
489+ @ Deprecated (since = "20" )
450490 public URL (String protocol , String host , int port , String file ,
451491 URLStreamHandler handler ) throws MalformedURLException {
452492 if (handler != null ) {
@@ -533,7 +573,11 @@ public URL(String protocol, String host, int port, String file,
533573 * URLStreamHandler#parseURL parseURL method} throws
534574 * {@code IllegalArgumentException}
535575 * @see java.net.URL#URL(java.net.URL, java.lang.String)
576+ * @deprecated Use {@link URI#toURL()} to construct an instance of URL. See the note on
577+ * <a href="#constructor-deprecation">constructor deprecation</a> for more
578+ * details.
536579 */
580+ @ Deprecated (since = "20" )
537581 public URL (String spec ) throws MalformedURLException {
538582 this (null , spec );
539583 }
@@ -593,7 +637,11 @@ public URL(String spec) throws MalformedURLException {
593637 * @see java.net.URLStreamHandler
594638 * @see java.net.URLStreamHandler#parseURL(java.net.URL,
595639 * java.lang.String, int, int)
640+ * @deprecated Use {@link URI#toURL()} to construct an instance of URL. See the note on
641+ * <a href="#constructor-deprecation">constructor deprecation</a> for more
642+ * details.
596643 */
644+ @ Deprecated (since = "20" )
597645 public URL (URL context , String spec ) throws MalformedURLException {
598646 this (context , spec , null );
599647 }
@@ -626,7 +674,13 @@ public URL(URL context, String spec) throws MalformedURLException {
626674 * @see java.net.URLStreamHandler
627675 * @see java.net.URLStreamHandler#parseURL(java.net.URL,
628676 * java.lang.String, int, int)
677+ * @deprecated
678+ * Use {@link #of(URI, URLStreamHandler)} to construct an instance of URL
679+ * associated with a custom protocol handler.
680+ * See the note on <a href="#constructor-deprecation">constructor deprecation</a>
681+ * for more details.
629682 */
683+ @ Deprecated (since = "20" )
630684 public URL (URL context , String spec , URLStreamHandler handler )
631685 throws MalformedURLException
632686 {
@@ -748,23 +802,70 @@ public URL(URL context, String spec, URLStreamHandler handler)
748802 }
749803
750804 /**
751- * Creates a URL from a URI, as if by invoking {@code uri.toURL()}.
805+ * Creates a URL from a URI, as if by invoking {@code uri.toURL()}, but
806+ * associating it with the given {@code URLStreamHandler}, if allowed.
807+ *
808+ * @apiNote
809+ * Applications should consider performing additional integrity
810+ * checks before constructing a {@code URL} and opening a connection.
811+ * See the <a href=#integrity>API note</a> in the class level API
812+ * documentation.
813+ *
814+ * @implSpec The implementation of this method includes calling the {@link
815+ * URLStreamHandler#parseURL(URL, String, int, int) parseURL} method on the
816+ * selected handler.
817+ *
818+ * @param uri the {@code URI} from which the returned {@code URL} should
819+ * be built
820+ * @param handler a custom protocol stream handler for
821+ * the returned {@code URL}. Can be {@code null},
822+ * in which case the default stream handler for
823+ * the protocol if any, will be used.
824+ *
825+ * @return a new {@code URL} instance created from the given {@code URI}
826+ * and associated with the given {@code URLStreamHandler}, if any
827+ *
828+ * @throws NullPointerException if {@code uri} is {@code null}
829+ *
830+ * @throws IllegalArgumentException if no protocol is specified
831+ * (the {@linkplain URI#getScheme() uri scheme} is {@code null}), or
832+ * if the {@code URLStreamHandler} is not {@code null} and can not be
833+ * set for the given protocol
834+ *
835+ * @throws MalformedURLException if an unknown protocol is found,
836+ * or the given URI fails to comply with the specific
837+ * syntax of the associated protocol, or the
838+ * underlying stream handler's {@linkplain
839+ * URLStreamHandler#parseURL(URL, String, int, int)
840+ * parseURL method} throws {@code IllegalArgumentException}
841+ *
842+ * @throws SecurityException
843+ * if a security manager exists and its
844+ * {@code checkPermission} method doesn't allow
845+ * specifying a stream handler
752846 *
753847 * @see java.net.URI#toURL()
848+ *
849+ * @since 20
754850 */
755- static URL fromURI (URI uri ) throws MalformedURLException {
851+ public static URL of (URI uri , URLStreamHandler handler )
852+ throws MalformedURLException {
756853 if (!uri .isAbsolute ()) {
757854 throw new IllegalArgumentException ("URI is not absolute" );
758855 }
856+
759857 String protocol = uri .getScheme ();
760858
859+ // fast path for canonical jrt:/... URLs
860+ //
761861 // In general we need to go via Handler.parseURL, but for the jrt
762862 // protocol we enforce that the Handler is not overridable and can
763863 // optimize URI to URL conversion.
764864 //
765865 // Case-sensitive comparison for performance; malformed protocols will
766866 // be handled correctly by the slow path.
767- if (protocol .equals ("jrt" ) && !uri .isOpaque ()
867+ if (handler == null && protocol .equals ("jrt" ) && !uri .isOpaque ()
868+ && uri .getRawAuthority () == null
768869 && uri .getRawFragment () == null ) {
769870
770871 String query = uri .getRawQuery ();
@@ -780,9 +881,28 @@ static URL fromURI(URI uri) throws MalformedURLException {
780881 int port = uri .getPort ();
781882
782883 return new URL ("jrt" , host , port , file , null );
783- } else {
784- return new URL ((URL )null , uri .toString (), null );
785884 }
885+
886+ // slow path (will work for non-canonical forms of jrt: too)
887+
888+ if ("url" .equalsIgnoreCase (protocol )) {;
889+ String uristr = uri .toString ();
890+ try {
891+ URI inner = new URI (uristr .substring (4 ));
892+ if (inner .isAbsolute ()) {
893+ protocol = inner .getScheme ();
894+ }
895+ } catch (URISyntaxException use ) {
896+ throw new MalformedURLException (use .getMessage ());
897+ }
898+ }
899+
900+ if (handler != null && !isOverrideable (protocol )) {
901+ throw new IllegalArgumentException ("Can't override URLStreamHandler for protocol "
902+ + protocol );
903+ }
904+
905+ return new URL ((URL )null , uri .toString (), handler );
786906 }
787907
788908 /*
0 commit comments