我试图从我的java程序中调用custom url
,因此我使用了这样的东西:
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.main(TestDemo.java:14)
如果我从浏览器触发URI
,那么它按预期工作,但如果我尝试从Java Program
调用它,那么我得到上述异常。
修改
以下是我尝试的步骤(我肯定错过了一些内容,请告诉我):
第1步:在java.protocol.handler.pkgs
第2步:从网址触发自定义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方法),但是当URL
初始化为CustomURI:
时,我收到此异常作为构造函数:
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)
请告知如何使这项工作。
答案 0 :(得分:59)
创建一个自定义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()
。由于问题中缺少此信息,因此无法提供更多详细信息。
创建一个自定义URLStreamHandler
实现,并在openConnection()
中返回它。
public class CustomURLStreamHandler extends URLStreamHandler {
@Override
protected URLConnection openConnection(URL url) throws IOException {
return new CustomURLConnection(url);
}
}
如果有必要,请不要忘记覆盖并实施其他方法。
创建一个自定义URLStreamHandlerFactory
,根据协议创建并返回它。
public class CustomURLStreamHandlerFactory implements URLStreamHandlerFactory {
@Override
public URLStreamHandler createURLStreamHandler(String protocol) {
if ("customuri".equals(protocol)) {
return new CustomURLStreamHandler();
}
return null;
}
}
请注意,协议为always小写。
最后通过URL#setURLStreamHandlerFactory()
URL.setURLStreamHandlerFactory(new CustomURLStreamHandlerFactory());
请注意,Javadoc明确表示您最多可以设置一次。因此,如果您打算在同一个应用程序中支持多个自定义协议,则需要对自定义URLStreamHandlerFactory
实现进行通用化,以便在createURLStreamHandler()
方法中覆盖所有这些协议。
或者,如果您不喜欢Demeter法则,请将它们全部放在匿名类中以进行代码缩小:
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
功能接口替换为lambda以进一步缩小:
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();
// ...
答案 1 :(得分:3)
如果您不想接管唯一的URLStreamHandlerFactory,您实际上可以使用一种可怕但有效的命名约定来获取默认实现。
您必须为您的URLStreamHandler
班级Handler
命名,其所映射的协议是该班级的最后一段&#39;封装
所以,com.foo.myproto.Handler
- &gt; myproto:urls
,
如果您将包com.foo
添加到&#34; url流源包列表中,并且#34;用于查找未知协议。您可以通过系统属性"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);
}
}
答案 2 :(得分:1)
你做了一个递归/无限循环。
Classloader以不同方式搜索类。
stacktrace(URLClassPath)是这样的:
«your java.protocol.handler.pkgs-package».CustomURI.Handler
。 «your java.protocol.handler.pkgs-package».CustomURI.Handler
。 «your java.protocol.handler.pkgs-package».CustomURI.Handler
。 «your java.protocol.handler.pkgs-package».CustomURI.Handler
。 加载所有protocoll-Handler,我找不到文件«your java.protocol.handler.pkgs-package».CustomURI.Handler
。
...... StackOverflowException !!!