Registrering og brug af en brugerdefineret java.net.URL-protokol
-
Opret en tilpasset
URLConnection
implementering, som udfører jobbet iconnect()
metode.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!"); } }
Glem ikke at tilsidesætte og implementere andre metoder såsom
getInputStream()
derfor. Flere detaljer om det kan ikke gives, da disse oplysninger mangler i spørgsmålet. -
Opret en tilpasset
URLStreamHandler
implementering, som returnerer den iopenConnection()
.public class CustomURLStreamHandler extends URLStreamHandler { @Override protected URLConnection openConnection(URL url) throws IOException { return new CustomURLConnection(url); } }
Glem ikke at tilsidesætte og implementere andre metoder, hvis det er nødvendigt.
-
Opret en tilpasset
URLStreamHandlerFactory
som opretter og returnerer det baseret på protokollen.public class CustomURLStreamHandlerFactory implements URLStreamHandlerFactory { @Override public URLStreamHandler createURLStreamHandler(String protocol) { if ("customuri".equals(protocol)) { return new CustomURLStreamHandler(); } return null; } }
Bemærk, at protokoller altid er små bogstaver.
-
Til sidst registrer det under applikationens opstart via
URL#setURLStreamHandlerFactory()
URL.setURLStreamHandlerFactory(new CustomURLStreamHandlerFactory());
Bemærk, at Javadoc udtrykkeligt siger, at du højst kan indstille det én gang. Så hvis du har til hensigt at understøtte flere brugerdefinerede protokoller i samme applikation, skal du generere den tilpassede
URLStreamHandlerFactory
implementering for at dække dem alle inde icreateURLStreamHandler()
metode.Alternativt, hvis du ikke kan lide Demeterloven, så smid det hele sammen i anonyme klasser til kodeminificering:
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; } });
Hvis du allerede er på Java 8, skal du erstatte
URLStreamHandlerFactory
funktionel grænseflade med en lambda for yderligere minifikation: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);
Nu kan du bruge det som følger:
URLConnection connection = new URL("CustomURI:blabla").openConnection();
connection.connect();
// ...
Eller med små bogstaver i overensstemmelse med specifikationerne:
URLConnection connection = new URL("customuri:blabla").openConnection();
connection.connect();
// ...
Hvis du ikke ønsker at overtage den ene-og-kun URLStreamHandlerFactory, kan du faktisk bruge en hæslig, men effektiv navnekonvention til at komme ind på standardimplementeringen.
Du skal navngiv din URLStreamHandler
klasse Handler
, og den protokol, den er knyttet til, er det sidste segment af den klasses pakke.
Så com.foo.myproto.Handler
->myproto:urls
, forudsat at du tilføjer din pakke com.foo
til listen over "url stream source-pakker" til opslag på ukendt protokol. Du gør dette via systemegenskaben "java.protocol.handler.pkgs"
(som er en | separeret liste over pakkenavne, der skal søges i).
Her er en abstrakt klasse, der udfører det, du har brug for:(ikke noget imod den manglende StringTo<Out1<String>>
eller StringURLConnection
, disse gør, hvad deres navne antyder, og du kan bruge de abstraktioner, du foretrækker)
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);
}
}
Så her er den faktiske klasse, der implementerer abstraktbehandleren (for dynamic:
webadresser:
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);
}
}