Введение и базовая реализация
Во-первых, вам понадобится хотя бы URLStreamHandler. Это фактически откроет соединение с данным URL. Обратите внимание, что это просто называется Handler
; это позволяет вам указать, java -Djava.protocol.handler.pkgs=org.my.protocols
и он будет автоматически выбран, используя «простое» имя пакета в качестве поддерживаемого протокола (в данном случае «classpath»).
использование
new URL("classpath:org/my/package/resource.extension").openConnection();
Код
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();
}
}
Проблемы с запуском
Если вы чем-то похожи на меня, вы не хотите полагаться на свойство, установленное при запуске, чтобы получить вас куда-то (в моем случае мне нравится держать свои параметры открытыми, как Java WebStart - вот почему
мне все это нужно ).
Обходные пути / Улучшения
Спецификация обработчика кода вручную
Если вы контролируете код, вы можете сделать
new URL(null, "classpath:some/package/resource.extension", new org.my.protocols.classpath.Handler(ClassLoader.getSystemClassLoader()))
и это будет использовать ваш обработчик, чтобы открыть соединение.
Но опять же, это менее чем удовлетворительно, так как вам не нужен URL для этого - вы хотите сделать это, потому что какая-то библиотека, которую вы не можете (или не хотите) контролировать, требует URL ...
Регистрация обработчика JVM
Окончательный вариант - зарегистрировать, URLStreamHandlerFactory
который будет обрабатывать все URL через 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);
}
}
Чтобы зарегистрировать обработчик, позвоните URL.setURLStreamHandlerFactory()
на настроенную фабрику. Затем сделайте new URL("classpath:org/my/package/resource.extension")
первый пример, и вы отправитесь в путь.
Проблема регистрации обработчика JVM
Обратите внимание, что этот метод может вызываться только один раз для JVM, и обратите внимание, что Tomcat будет использовать этот метод для регистрации обработчика JNDI (AFAIK). Попробуйте Jetty (я буду); в худшем случае, вы можете сначала использовать метод, а затем он должен работать вокруг вас!
Лицензия
Я передаю это в общественное достояние и спрашиваю, что если вы хотите изменить это, вы запускаете проект OSS где-то и комментируете здесь с деталями. Лучше реализация будет иметь , URLStreamHandlerFactory
что использует ThreadLocal
s для хранения URLStreamHandler
s для каждого Thread.currentThread().getContextClassLoader()
. Я даже дам вам свои модификации и тестовые классы.
com.github.fommil.common-utils
пакет, который я планирую вскоре обновить и выпустить через Sonatype.