web-dev-qa-db-ja.com

カスタムJava.net.URLプロトコルの登録と使用

Javaプログラムからcustom urlを呼び出そうとしていたので、次のようなものを使用しました。

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

私は以下の例外を受け取りました:

Java.net.MalformedURLException:不明なプロトコル:com.demo.TestDemoのJava.net.URL。(Unknown Source)のJava.net.URL。(Unknown Source)のJava.net.URL。(Unknown Source)のCustomURI main(TestDemo.Java:14)

ブラウザからURIをトリガーすると期待どおりに動作しますが、Java Programから呼び出そうとすると上記の例外が発生します。

編集:

以下は私が試した手順です(確かに何かが欠けています。そのことを教えてください):

ステップ1:Java.protocol.handler.pkgsにカスタムURIを追加する

ステップ2:URLからカスタムURIをトリガーする

コード:

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メソッドから)表示されますが、URLCustomURI:で初期化されると、この例外が表示されます。コンストラクタ:

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)

この作業を行う方法をアドバイスしてください。

32
user182944
  1. connect()メソッドでジョブを実行するカスタム URLConnection 実装を作成します。

    _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. openConnection()で返すカスタム URLStreamHandler 実装を作成します。

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

    プロトコルは always 小文字であることに注意してください。


  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();
// ...
_
59
BalusC

唯一のURLStreamHandlerFactoryを引き継ぎたくない場合は、実際には恐ろしいが効果的な命名規則を使用して、デフォルトの実装を取得できます。

mustURLStreamHandler class Handlerに名前を付けます。マップするプロトコルは、そのクラスのパッケージの最後のセグメントです。

そう、 com.foo.myproto.Handler-> myproto:urls、パッケージを追加する場合com.fooを、不明なプロトコルの検索用の「url stream source packages」のリストに追加します。これは、システムプロパティ"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: URL:

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

}
4
Ajax

再帰/無限ループを作成しました。

さまざまな方法でクラスを検索するクラスローダー。

スタックトレース(URLClassPath)は次のようなものです。

  1. リソースをロードします。
  2. すべてのプロトコルをロードしましたか?いや!
  3. すべてのprotocol-Handlersをロードしますが、File «your Java.protocol.handler.pkgs-package».CustomURI.Handler
  4. クラスはリソースです!すべてのプロトコルをロードしましたか?いや!
  5. すべてのprotocol-Handlersをロードしますが、File «your Java.protocol.handler.pkgs-package».CustomURI.Handler
  6. クラスはリソースです!すべてのプロトコルをロードしましたか?いや!
  7. すべてのprotocol-Handlersをロードしますが、File «your Java.protocol.handler.pkgs-package».CustomURI.Handler
  8. クラスはリソースです!すべてのプロトコルをロードしましたか?いや!
  9. すべてのprotocol-Handlersをロードしますが、File «your Java.protocol.handler.pkgs-package».CustomURI.Handler
  10. クラスはリソースです!すべてのプロトコルをロードしましたか?いや!
  11. すべてのprotocol-Handlersをロードしますが、File «your Java.protocol.handler.pkgs-package».CustomURI.Handler

    ...... StackOverflowException !!!

1
Peter Rader