Introduzione e implementazione di base
Prima di tutto, avrai bisogno almeno di un URLStreamHandler. Questo aprirà effettivamente la connessione a un determinato URL. Si noti che questo è semplicemente chiamato Handler
; ciò consente di specificare java -Djava.protocol.handler.pkgs=org.my.protocols
e verrà automaticamente prelevato, utilizzando il nome del pacchetto "semplice" come protocollo supportato (in questo caso "percorso di classe").
uso
new URL("classpath:org/my/package/resource.extension").openConnection();
Codice
package org.my.protocols.classpath;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
/** A {@link URLStreamHandler} that handles resources on the classpath. */
public class Handler extends URLStreamHandler {
/** The classloader to find resources from. */
private final ClassLoader classLoader;
public Handler() {
this.classLoader = getClass().getClassLoader();
}
public Handler(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
protected URLConnection openConnection(URL u) throws IOException {
final URL resourceUrl = classLoader.getResource(u.getPath());
return resourceUrl.openConnection();
}
}
Problemi di lancio
Se sei qualcosa come me, non vuoi fare affidamento su una proprietà impostata nel lancio per portarti da qualche parte (nel mio caso, mi piace tenere aperte le mie opzioni come Java WebStart - motivo per cui
ho bisogno di tutto questo ).
Soluzioni temporanee / Miglioramenti
Codice manuale Specifiche del gestore
Se controlli il codice, puoi farlo
new URL(null, "classpath:some/package/resource.extension", new org.my.protocols.classpath.Handler(ClassLoader.getSystemClassLoader()))
e questo utilizzerà il gestore per aprire la connessione.
Ma ancora una volta, questo è meno che soddisfacente, poiché non hai bisogno di un URL per farlo - vuoi farlo perché un po 'di lib che non puoi (o non vuoi) controllare vogliono gli URL ...
Registrazione gestore JVM
L'ultima opzione è quella di registrare un URLStreamHandlerFactory
che gestirà tutti gli URL in jvm:
package my.org.url;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.util.HashMap;
import java.util.Map;
class ConfigurableStreamHandlerFactory implements URLStreamHandlerFactory {
private final Map<String, URLStreamHandler> protocolHandlers;
public ConfigurableStreamHandlerFactory(String protocol, URLStreamHandler urlHandler) {
protocolHandlers = new HashMap<String, URLStreamHandler>();
addHandler(protocol, urlHandler);
}
public void addHandler(String protocol, URLStreamHandler urlHandler) {
protocolHandlers.put(protocol, urlHandler);
}
public URLStreamHandler createURLStreamHandler(String protocol) {
return protocolHandlers.get(protocol);
}
}
Per registrare il gestore, chiamare URL.setURLStreamHandlerFactory()
con il produttore configurato. Quindi fai new URL("classpath:org/my/package/resource.extension")
come il primo esempio e via.
Problema di registrazione del gestore JVM
Si noti che questo metodo può essere chiamato solo una volta per JVM e si noti che Tomcat utilizzerà questo metodo per registrare un gestore JNDI (AFAIK). Prova Jetty (lo sarò); nel peggiore dei casi, è possibile utilizzare prima il metodo e poi deve aggirare intorno a te!
Licenza
Lo pubblico di pubblico dominio e chiedo che, se si desidera modificare, si avvia un progetto OSS da qualche parte e si commenta qui con i dettagli. Un'implementazione migliore sarebbe URLStreamHandlerFactory
quella di utilizzare una ThreadLocal
s per memorizzare URLStreamHandler
s per ciascuna Thread.currentThread().getContextClassLoader()
. Ti darò anche le mie modifiche e le lezioni di prova.
com.github.fommil.common-utils
pacchetto che prevedo di aggiornare e rilasciare presto tramite Sonatype.