protocol mismo example diferencia java url uri protocols

mismo - Registro y uso de un protocolo personalizado java.net.URL



uri y url es lo mismo (3)

Intenté invocar una custom url de mi programa java, por lo tanto, utilicé algo como esto:

URL myURL; try { myURL = new URL("CustomURI:"); URLConnection myURLConnection = myURL.openConnection(); myURLConnection.connect(); } catch (Exception e) { e.printStackTrace(); }

Obtuve la siguiente excepción:

java.net.MalformedURLException: protocolo desconocido: CustomURI en java.net.URL. (Fuente desconocida) en java.net.URL. (Fuente desconocida) en java.net.URL. (Fuente desconocida) en com.demo.TestDemo. main (TestDemo.java:14)

Si desencadenar el URI desde un navegador, funciona como se esperaba, pero si intento invocarlo desde el Java Program recibo la excepción anterior.

EDITAR:

A continuación se detallan los pasos que probé (me falta algo seguro, por favor avísenme al respecto):

Paso 1: Agregar el URI personalizado en java.protocol.handler.pkgs

Paso 2: Activación del URI personalizado desde la URL

Código:

public class CustomURI { public static void main(String[] args) { try { add("CustomURI:"); URL uri = new URL("CustomURI:"); URLConnection uc = uri.openConnection(); uc.connect(); } catch (Exception e) { e.printStackTrace(); } } public static void add( String handlerPackage ){ final String key = "java.protocol.handler.pkgs"; String newValue = handlerPackage; if ( System.getProperty( key ) != null ) { final String previousValue = System.getProperty( key ); newValue += "|" + previousValue; } System.setProperty( key, newValue ); System.out.println(System.getProperty("java.protocol.handler.pkgs")); } }

Cuando ejecuto este código, CustomURI: el CustomURI: impreso en mi consola (desde el método add) pero luego recibo esta excepción cuando la URL se inicializa con CustomURI: como un constructor:

Exception in thread "main" java.lang.StackOverflowError at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Unknown Source) at java.net.URL.getURLStreamHandler(Unknown Source) at java.net.URL.<init>(Unknown Source) at java.net.URL.<init>(Unknown Source) at sun.misc.URLClassPath$FileLoader.getResource(Unknown Source) at sun.misc.URLClassPath.getResource(Unknown Source) at java.net.URLClassLoader$1.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) at java.lang.ClassLoader.loadClass(Unknown Source) at java.net.URL.getURLStreamHandler(Unknown Source) at java.net.URL.<init>(Unknown Source) at java.net.URL.<init>(Unknown Source)

Por favor, consejos sobre cómo hacer que esto funcione.


  1. Cree una implementación URLConnection personalizada que realice el trabajo en el método connect() .

    public class CustomURLConnection extends URLConnection { protected CustomURLConnection(URL url) { super(url); } @Override public void connect() throws IOException { // Do your job here. As of now it merely prints "Connected!". System.out.println("Connected!"); } }

    No olvides anular e implementar otros métodos como getInputStream() consecuencia. No se pueden dar más detalles al respecto porque esta información falta en la pregunta.

  2. Cree una implementación de URLStreamHandler personalizada que la devuelva en openConnection() .

    public class CustomURLStreamHandler extends URLStreamHandler { @Override protected URLConnection openConnection(URL url) throws IOException { return new CustomURLConnection(url); } }

    No olvide anular e implementar otros métodos si es necesario.

  3. Cree una URLStreamHandlerFactory personalizada que la cree y la devuelva en función del protocolo.

    public class CustomURLStreamHandlerFactory implements URLStreamHandlerFactory { @Override public URLStreamHandler createURLStreamHandler(String protocol) { if ("customuri".equals(protocol)) { return new CustomURLStreamHandler(); } return null; } }

    Tenga en cuenta que los protocolos always son minúsculos.

  4. Finalmente regístrelo durante el inicio de la aplicación a través del URL#setURLStreamHandlerFactory()

    URL.setURLStreamHandlerFactory(new CustomURLStreamHandlerFactory());

    Tenga en cuenta que el URL#setURLStreamHandlerFactory() dice explícitamente que puede establecerlo como máximo una vez. Por lo tanto, si tiene la intención de admitir varios protocolos personalizados en la misma aplicación, deberá generar la implementación personalizada de URLStreamHandlerFactory para cubrirlos dentro del método createURLStreamHandler() .

    Alternativamente, si no te gusta la Ley de Demeter, ponlo todo junto en clases anónimas para la minificación del código:

    URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() { public URLStreamHandler createURLStreamHandler(String protocol) { return "customuri".equals(protocol) ? new URLStreamHandler() { protected URLConnection openConnection(URL url) throws IOException { return new URLConnection(url) { public void connect() throws IOException { System.out.println("Connected!"); } }; } } : null; } });

    Si ya está en Java 8, reemplace la interfaz funcional URLStreamHandlerFactory por una lambda para una mayor minificación:

    URL.setURLStreamHandlerFactory(protocol -> "customuri".equals(protocol) ? new URLStreamHandler() { protected URLConnection openConnection(URL url) throws IOException { return new URLConnection(url) { public void connect() throws IOException { System.out.println("Connected!"); } }; } } : null);

Ahora puedes usarlo de la siguiente manera:

URLConnection connection = new URL("CustomURI:blabla").openConnection(); connection.connect(); // ...

O con protocolo en minúsculas según la especificación:

URLConnection connection = new URL("customuri:blabla").openConnection(); connection.connect(); // ...


Hiciste una recursión / bucle infinito.

El Classloader busca la clase de diferentes maneras.

El stacktrace (URLClassPath) es así:

  1. Cargar un recurso
  2. ¿Cargué todos los protocolos? ¡No!
  3. Cargue todos los manejadores de protocolo, no puedo encontrar el archivo «your java.protocol.handler.pkgs-package».CustomURI.Handler .
  4. La clase es un recurso! ¿Cargué todos los protocolos? ¡No!
  5. Cargue todos los manejadores de protocolo, no puedo encontrar el archivo «your java.protocol.handler.pkgs-package».CustomURI.Handler .
  6. La clase es un recurso! ¿Cargué todos los protocolos? ¡No!
  7. Cargue todos los manejadores de protocolo, no puedo encontrar el archivo «your java.protocol.handler.pkgs-package».CustomURI.Handler .
  8. La clase es un recurso! ¿Cargué todos los protocolos? ¡No!
  9. Cargue todos los manejadores de protocolo, no puedo encontrar el archivo «your java.protocol.handler.pkgs-package».CustomURI.Handler .
  10. La clase es un recurso! ¿Cargué todos los protocolos? ¡No!
  11. Cargue todos los manejadores de protocolo, no puedo encontrar el archivo «your java.protocol.handler.pkgs-package».CustomURI.Handler .

    ...... Exception !!!


Si no desea hacerse cargo de la URLStreamHandlerFactory única y única, puede utilizar una convención de nomenclatura horrible, pero efectiva para entrar en la implementación predeterminada.

Debe nombrar su URLStreamHandler clase URLStreamHandler , y el protocolo al que se asigna es el último segmento del paquete de esa clase.

Por lo tanto, com.foo.myproto.Handler -> myproto:urls , siempre que agregue su paquete com.foo a la lista de "paquetes de origen de la secuencia de url" para buscar en un protocolo desconocido. Esto se hace a través de la propiedad del sistema "java.protocol.handler.pkgs" (que es una lista delimitada de nombres de paquetes para buscar).

Aquí hay una clase abstracta que realiza lo que necesita: (no importa la falta de StringTo<Out1<String>> o StringURLConnection , estos hacen lo que sugieren sus nombres y puede usar las abstracciones que prefiera)

public abstract class AbstractURLStreamHandler extends URLStreamHandler { protected abstract StringTo<Out1<String>> dynamicFiles(); protected static void addMyPackage(Class<? extends URLStreamHandler> handlerClass) { // Ensure that we are registered as a url protocol handler for JavaFxCss:/path css files. String was = System.getProperty("java.protocol.handler.pkgs", ""); String pkg = handlerClass.getPackage().getName(); int ind = pkg.lastIndexOf(''.''); assert ind != -1 : "You can''t add url handlers in the base package"; assert "Handler".equals(handlerClass.getSimpleName()) : "A URLStreamHandler must be in a class named Handler; not " + handlerClass.getSimpleName(); System.setProperty("java.protocol.handler.pkgs", handlerClass.getPackage().getName().substring(0, ind) + (was.isEmpty() ? "" : "|" + was )); } @Override protected URLConnection openConnection(URL u) throws IOException { final String path = u.getPath(); final Out1<String> file = dynamicFiles().get(path); return new StringURLConnection(u, file); } }

Entonces, aquí está la clase real implementando el controlador abstracto (para dynamic: urls:

package xapi.dev.api.dynamic; // imports elided for brevity public class Handler extends AbstractURLStreamHandler { private static final StringTo<Out1<String>> dynamicFiles = X_Collect.newStringMap(Out1.class, CollectionOptions.asConcurrent(true) .mutable(true) .insertionOrdered(false) .build()); static { addMyPackage(Handler.class); } @Override protected StringTo<Out1<String>> dynamicFiles() { return dynamicFiles; } public static String registerDynamicUrl(String path, Out1<String> contents) { dynamicFiles.put(path, contents); return path; } public static void clearDynamicUrl(String path) { dynamicFiles.remove(path); } }