JarInputStream: getNextJarEntry всегда возвращает ноль - PullRequest
1 голос
/ 05 марта 2011

У меня есть вспомогательный класс I18n, который может узнать доступные Locale s, посмотрев на имена файлов внутри Jar приложения.

private static void addLocalesFromJar(List<Locale> locales) throws IOException {
    ProtectionDomain domain = I18n.class.getProtectionDomain();
    CodeSource src = domain.getCodeSource();
    URL url = src.getLocation();
    JarInputStream jar = new JarInputStream(url.openStream());
    while (true) {
        JarEntry entry = jar.getNextJarEntry();
        if (entry == null) {
            break;
        }
        String name = entry.getName();
        // ...
    }
}

В настоящее время это не работает - jar.getNextJarEntry(), кажется, всегда возвращает null. Я понятия не имею, почему это происходит, все, что я знаю, это то, что url установлено на rsrc:./. Я никогда не видел этот протокол и не мог найти в нем ничего.

Любопытно, что это работает:

class Main {
    public static void main(String[] args) {
        URL url = Main.class.getProtectionDomain().getCodeSource().getLocation();
        JarInputStream jar = new JarInputStream(url.openStream());
        while (true) {
            JarEntry entry = jar.getNextJarEntry();
            if (entry == null) {
                break;
            }
            System.out.println(entry.getName());
        }
    }
}

В этой версии, хотя между ними практически нет различий, url правильно задан путь к файлу Jar.

Почему не работает первая версия и что ее нарушает?

UPDATE

Рабочий пример действительно работает, только если я не использую Eclipse для его экспорта. В NetBeans все работало нормально, но в версии Eclipse URL-адрес также был установлен на rsrc:./.

Так как я экспортировал его с обработкой библиотеки Package required libraries into generated JAR, Eclipse поместил его jarinjarloader в мой Jar-файл, чтобы у меня были все зависимости внутри него. Он отлично работает с другими настройками, но есть ли способ сделать эту работу независимо от них?


Другой вопрос

В данный момент этот класс является частью моего приложения, но я планирую поместить его в отдельную библиотеку. В таком случае, как я могу убедиться, что он будет работать с отдельными банками?

Ответы [ 4 ]

2 голосов
/ 08 марта 2011

Проблема в jarinjarloader ClassLoader, который используется Eclipse.Очевидно, он использует собственную схему rsrc: URL для указания на файлы JAR, хранящиеся в основном файле JAR.Эта схема не понятна вашей фабрике обработчиков потока URL, поэтому метод openStream () возвращает значение null, которое вызывает возникшую проблему.

Это ответит на вторую часть вашего вопроса о отдельных jar-файлах, а не толькоБудет ли это работать, это единственный способ, которым это будет работать.Вам нужно изменить свое основное приложение, чтобы использовать отдельные банки вместо того, чтобы объединять их все в основном банке.Если вы создаете веб-приложение, скопируйте их в каталог WEB-INF / lib, и все в порядке.Если вы создаете настольное приложение, добавьте ссылку относительного пути в META-INF / MANIFEST.MF на другие файлы jar, и они будут автоматически включены как часть пути к классам при запуске основного файла jar.

1 голос
/ 12 марта 2011

Eclipse jarinjarloader загружает все, используя системный загрузчик классов, и никогда не знает, из какого jar-файла был загружен. Вот почему вы не можете получить URL банку для rsrc: URL.

Я предлагаю хранить список языковых стандартов в файле в каждой папке приложения, например, META-INF/locales. Затем вы можете использовать ClassLoader.getResources("META-INF/locales"), чтобы получить список всех файлов с этим именем в classpath и объединить их для получения полного списка локалей.

1 голос
/ 08 марта 2011

Код может или не может привести к файлу JAR, где находится I18n. Также getProtectionDomain может быть нулевым. Это зависит от того, как реализован загрузчик классов.

ProtectionDomain domain = I18n.class.getProtectionDomain();
CodeSource src = domain.getCodeSource();
URL url = src.getLocation();

о протоколе rsrc:./, загрузчик классов может свободно использовать любой URL, который пожелает (или назвать его в этом отношении)

попробуй, может повезет :) 1007 *

URL url = getClass().getResource(getClass().getSimpleName()+".class");
java.net.JarURLConnection conn = (java.net.JarURLConnection) url.openConnection();
Enumeration<JarEntry> e = conn.getJarFile().entries();
...

и удачи!

0 голосов
/ 05 марта 2011

Я использую System.getProperty ("java.class.path") для получения местоположения банки. Я не знаю, если это имеет значение. Я не исследовал путь ProtectDomain, поэтому не могу вам помочь, извините. Что касается нескольких jar-файлов, просто повторите и этот файл jar.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...