Регистрация и использование собственного протокола java.net.URL

Я пытался вызвать custom url из моей программы Java, следовательно, я использовал что-то вроде этого:

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

Я получил следующее исключение:

java.net.MalformedURLException: неизвестный протокол: CustomURI на java.net.URL.(неизвестный источник) на java.net.URL.(неизвестный источник) на java.net.URL.(неизвестный источник) на com.demo.TestDemo. Основной (TestDemo.java:14)

Если я вызову URI из браузера, то он работает как положено, но если я пытаюсь вызвать его из Java Program тогда я получаю вышеуказанное исключение.

РЕДАКТИРОВАТЬ:

Ниже приведены шаги, которые я попробовал (я что-то упустил, пожалуйста, дайте мне знать об этом):

Шаг 1. Добавление пользовательского URI вjava.protocol.handler.pkgs

Шаг 2: Запуск пользовательского URI из URL

Код:

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"));

}

}

Когда я запускаю этот код, я получаю CustomURI: напечатано в моей консоли (из метода add), но затем я получаю это исключение, когда URL инициализируется с CustomURI: как конструктор:

Exception in thread "main" java.lang.StackruError
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)

Пожалуйста, совет, как сделать эту работу.

3 ответа

Решение
  1. Создать кастом URLConnection реализация, которая выполняет работу в 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!");
        }
    
    }
    

    Не забудьте переопределить и реализовать другие методы, такие как getInputStream() соответственно. Больше подробностей об этом не может быть дано, так как эта информация отсутствует в вопросе.


  2. Создать кастом URLStreamHandler реализация, которая возвращает его в openConnection(),

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

    Не забудьте переопределить и реализовать другие методы, если это необходимо.


  3. Создать кастом URLStreamHandlerFactory который создает и возвращает его на основе протокола.

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

    Обратите внимание, что протоколы всегда строчные.


  4. Наконец зарегистрируйте его во время запуска приложения через URL#setURLStreamHandlerFactory()

    URL.setURLStreamHandlerFactory(new CustomURLStreamHandlerFactory());
    

    Обратите внимание, что Javadoc явно говорит, что вы можете установить его не более одного раза. Поэтому, если вы намереваетесь поддерживать несколько пользовательских протоколов в одном приложении, вам необходимо создать URLStreamHandlerFactory реализация, чтобы покрыть их все внутри createURLStreamHandler() метод.


    В качестве альтернативы, если вам не нравится Закон Деметры, бросьте все это вместе в анонимные классы для минимизации кода:

    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;
        }
    });
    

    Если вы уже используете Java 8, замените URLStreamHandlerFactory Функциональный интерфейс лямбда для дальнейшей минимизации:

    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);
    

Теперь вы можете использовать его следующим образом:

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

Или с протоколом в нижнем регистре согласно спецификации:

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

Если вы не хотите брать на себя единственный-единственный URLStreamHandlerFactory, вы можете использовать отвратительное, но эффективное соглашение об именах, чтобы войти в реализацию по умолчанию.

Вы должны назвать свой URLStreamHandler учебный класс Handlerи протокол, к которому он привязан, является последним сегментом пакета этого класса.

Так, com.foo.myproto.Handler->myproto:urlsпри условии, что вы добавите свой пакет com.foo в список "пакетов источника потока url" для поиска по неизвестному протоколу. Вы делаете это через системное свойство "java.protocol.handler.pkgs" (который представляет собой разделенный | список имен пакетов для поиска).

Вот абстрактный класс, который выполняет то, что вам нужно: StringTo<Out1<String>> или же StringURLConnectionони делают то, что предлагают их имена, и вы можете использовать любые абстракции, которые вы предпочитаете)

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);
    }
}

Тогда вот фактический класс, реализующий абстрактный обработчик (для 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);
    }

}

Вы сделали рекурсию / бесконечный цикл.

Classloader ищет класс по-разному.

Трассировка стека (URLClassPath) выглядит следующим образом:

  1. Загрузите ресурс.
  2. Я загрузил каждый протокол? Нет!
  3. Загрузите все обработчики protocoll, я не могу найти файл «your java.protocol.handler.pkgs-package».CustomURI.Handler,
  4. Класс это ресурс! Я загрузил каждый протокол? Нет!
  5. Загрузите все обработчики protocoll, я не могу найти файл «your java.protocol.handler.pkgs-package».CustomURI.Handler,
  6. Класс это ресурс! Я загрузил каждый протокол? Нет!
  7. Загрузите все обработчики protocoll, я не могу найти файл «your java.protocol.handler.pkgs-package».CustomURI.Handler,
  8. Класс это ресурс! Я загрузил каждый протокол? Нет!
  9. Загрузите все обработчики protocoll, я не могу найти файл «your java.protocol.handler.pkgs-package».CustomURI.Handler,
  10. Класс это ресурс! Я загрузил каждый протокол? Нет!
  11. Загрузите все обработчики protocoll, я не могу найти файл «your java.protocol.handler.pkgs-package».CustomURI.Handler,

    ...... StackruException!!!

Другие вопросы по тегам