Другое

Как правильно подключить OkHttp и Okio в плагине Eclipse, чтобы okio.Buffer корректно загружался без ClassNotFoundException?

Я разрабатываю плагин Eclipse в среде OSGi и пытаюсь использовать OkHttp 4.11.0 для отправки HTTP-запросов. Однако я сталкиваюсь с ошибкой во время выполнения: java.lang.ClassNotFoundException: okio.Buffer не найден в eclipseai.plugin_1.0.0. Руководство по настройке bundle и устранению ошибок.

java.lang.ClassNotFoundException: okio.Buffer при использовании OkHttp внутри плагина Eclipse (OSGi)

Я разрабатываю плагин Eclipse в окружении OSGi и пытаюсь использовать OkHttp 4.11.0 для отправки HTTP‑запросов. Однако я сталкиваюсь с ошибкой во время выполнения:

java.lang.ClassNotFoundException: okio.Buffer cannot be found by eclipseai.plugin_1.0.0

Минимальный воспроизводимый пример (MRE)

java
package eclipseai.test;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;

public class OkHttpTest {

    public static void main(String[] args) throws IOException {
        OkHttpClient client = new OkHttpClient(); // ClassNotFoundException occurs here
        Request request = new Request.Builder()
                .url("https://www.google.com")
                .build();

        Response response = client.newCall(request).execute();
        System.out.println(response.body().string());
    }
}

Воспроизведение внутри плагина Eclipse (OSGi)

  1. Создайте новый проект плагина Eclipse (например, eclipseai.plugin).

  2. Добавьте следующие JAR‑файлы в папку library/ плагина:

    • okhttp-4.11.0.jar
    • okio-3.4.0.jar
    • kotlin-stdlib-2.2.21.jar
  3. Добавьте их в MANIFEST.MF в разделе Bundle-ClassPath:

    Bundle-ClassPath: .,
     library/okhttp-4.11.0.jar,
     library/okio-3.4.0.jar,
     library/kotlin-stdlib-2.2.21.jar
    
  4. Добавьте их в build.properties в разделе bin.includes:

    bin.includes = plugin.xml, META-INF/, .,
                 library/okhttp-4.11.0.jar,
                 library/okio-3.4.0.jar,
                 library/kotlin-stdlib-2.2.21.jar
    
  5. Запустите плагин → ClassNotFoundException возникает на okio.Buffer.

Вопрос

Как правильно включить OkHttp и Okio в плагин Eclipse, чтобы okio.Buffer корректно загружался без возникновения ClassNotFoundException?

Ошибка java.lang.ClassNotFoundException: okio.Buffer в вашем плагине Eclipse OSGi возникает из‑за того, что OSGi использует изолированные загрузчики классов, которые не позволяют пакетам видеть классы друг друга, если они не настроены правильно. OkHttp зависит от Okio, но среда OSGi автоматически не делает классы Okio доступными для вашего плагина.


Содержание


Понимание проблемы с загрузчиком классов OSGi

В OSGi каждый пакет имеет свой собственный загрузчик классов, который видит только:

  1. Классы, импортированные через Import-Package
  2. Классы, экспортированные другими пакетами
  3. Классы, включённые напрямую в classpath пакета

Как объясняет Stack Overflow, «Ваш IDE знает более или менее один classpath, содержащий все классы, тогда как OSGi использует множество classpath (по одному на пакет и несколько других), и поэтому «скрывает» классы друг от друга».

Когда ваш код пытается создать OkHttpClient, он внутренне загружает okio.Buffer, но изолированный загрузчик классов OSGi блокирует это, потому что классы Okio не экспортированы/импортированы должным образом.


Решение 1: Корректная конфигурация OSGi‑пакета

Самый распространённый способ — правильно настроить MANIFEST.MF с нужными заголовками OSGi:

Шаг 1: Обновите MANIFEST.MF

Добавьте эти записи в ваш MANIFEST.MF:

properties
Bundle-ClassPath: .,
 library/okhttp-4.11.0.jar,
 library/okio-3.4.0.jar,
 library/kotlin-stdlib-2.2.21.jar

Import-Package: 
 okio;version="[1.0.0,3.0.0)",
 org.jetbrains.annotations;version="9.0.0",
 kotlin;version="1.6.0",
 kotlinx.coroutines;version="1.6.0"

Require-Bundle: 
 org.eclipse.osgi;bundle-version="3.16.0"

Export-Package: 
 eclipseai.test

Шаг 2: Проверьте Bundle-ClassPath

Убедитесь, что Bundle-ClassPath включает все необходимые JAR‑файлы. Проблема часто возникает, когда classpath неполный или неверно отформатирован.

Шаг 3: Проверьте конфликтующие версии

Согласно исследованию на Stack Overflow, «Okio версии 3.0.0‑Alpha‑10 был рефакторирован для использования Kotlin вместо Java. Вам понадобится версия до Alpha‑9, чтобы работать с ним».


Решение 2: Использование OSGi‑дружелюбных версий библиотек

Некоторые библиотеки специально созданы для сред OSGi. Рассмотрите возможность использования OSGi‑готовых версий:

Рекомендуемые версии

  • OkHttp: используйте версии, совместимые с OSGi
  • Okio: используйте версию 2.x (до рефакторинга на Kotlin)
  • Kotlin: используйте стабильные, совместимые с OSGi версии

Пример конфигурации

properties
# В pom.xml, если используете Maven
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.9.3</version> <!-- Старый, более стабильный OSGi‑вариант -->
</dependency>
<dependency>
    <groupId>com.squareup.okio</groupId>
    <artifactId>okio</artifactId>
    <version>2.9.0</version> <!-- До рефакторинга на Kotlin -->
</dependency>

Как объясняет руководство IBM по OSGi, версия совместимости критична в средах OSGi.


Решение 3: Обёртывание библиотек как OSGi‑пакетов

Для лучшей интеграции OSGi оберните ваши библиотеки как полноценные OSGi‑пакеты, используя инструменты вроде Bnd или функциональность обёртывания в Eclipse PDE:

Использование Eclipse PDE для обёртывания JAR‑ов

  1. Щёлкните правой кнопкой по проекту → Configure → Convert to PDE Project
  2. Импортируйте JAR‑ы как внешние библиотеки
  3. Используйте мастер «Create Bundle Configuration»
  4. Сгенерируйте правильный MANIFEST.MF с метаданными OSGi

Использование Bnd Tool

bash
bnd wrap -b okhttp-4.11.0.jar
bnd wrap -b okio-3.4.0.jar

Как обсуждают на Stack Overflow, «обёртка (bnd) не учитывает транзитивные зависимости и использует информацию о зависимостях Maven (если она есть внутри jar: META‑INF/maven/…) только как подсказку для генерации версий».


Решение 4: Использование репозиториев Eclipse P2

Eclipse предоставляет предустановленные OSGi‑пакеты через репозитории P2. Рассмотрите возможность использования их вместо сырых JAR‑ов:

Шаги для использования P2‑пакетов

  1. Добавьте репозитории Eclipse в вашу целевую платформу
  2. Найдите OkHttp и Okio в репозитории P2
  3. Установите их как OSGi‑пакеты в целевую платформу

Пример конфигурации целевой платформы

xml
<!-- В вашем target definition -->
<unit id="com.squareup.okhttp3.feature.group" version="0.0.0"/>
<unit id="com.squareup.okio.feature.group" version="0.0.0"/>

Форумы Eclipse Foundation предлагают руководство по работе с OSGi‑пакетами в плагинах Eclipse.


Шаги по устранению неполадок

Если проблемы продолжаются, выполните следующие шаги:

1. Проверьте конфигурацию classpath

Убедитесь, что все необходимые JAR‑ы включены в:

  • Bundle-ClassPath в MANIFEST.MF
  • bin.includes в build.properties

2. Используйте команды консоли OSGi

В рантайме Eclipse используйте консоль OSGi для диагностики проблем с пакетами:

ss - показать статус всех пакетов
diag <bundle-id> - диагностировать конкретный пакет
headers <bundle-id> - показать заголовки пакета

3. Проверьте конфликтующие версии

Ищите конфликтующие версии в консоли OSGi:

fw - показать статус фреймворка
packages - показать использование пакетов

4. Включите логирование OSGi

Включите подробное логирование OSGi, чтобы увидеть ошибки загрузки классов:

-dosgi.debug=true

Как советует Liferay, «ClassNotFoundException и NoClassDefFoundError часто возникают в средах OSGi из‑за изоляции загрузчиков классов».


Лучшие практики управления библиотеками OSGi

1. Используйте OSGi‑готовые библиотеки

Всегда отдавайте предпочтение библиотекам, которые поставляются с метаданными OSGi (META‑INF/MANIFEST.MF с заголовками OSGi).

2. Управление версиями

Используйте строгие диапазоны версий в ваших Import-Package:

properties
Import-Package: okio;version="[2.0.0,3.0.0)"

3. Управление зависимостями

  • Избегайте смешивания разных версий одной и той же библиотеки
  • Используйте Require-Bundle для сложных зависимостей при необходимости
  • Рассмотрите возможность использования фрагментных пакетов для платформенно‑специфического кода

4. Тестирование

Тестируйте ваш плагин в чистой среде OSGi, а не только в IDE Eclipse, где загрузка классов более «прощена».

Как отмечает официальная документация Okio, «класс Buffer реализует как BufferedSource, так и BufferedSink, поэтому ваш тестовый код остаётся простым и понятным». Понимание внутренней работы Okio помогает быстро диагностировать проблемы с загрузкой классов.


Источники

  1. java.lang.ClassNotFoundException: okio.Buffer when using OkHttp inside Eclipse plugin (OSGi) - Stack Overflow
  2. Resolving ClassNotFoundException and NoClassDefFoundError in OSGi Bundles - Liferay
  3. Okio - Square GitHub
  4. Unraveling Java and OSGi class loader problems - IBM Developer
  5. java - Okhttp3 jar missing okio? - Stack Overflow
  6. OSGI : maven wrapped bundle throws java.lang.ClassNotFoundException - Stack Overflow
  7. ClassNotFoundException on resolved OSGI bundle - Stack Overflow

Заключение

Ошибка ClassNotFoundException: okio.Buffer в вашем плагине Eclipse OSGi обычно вызвана изоляцией загрузчиков классов. Ключевые решения:

  1. Правильно настройте MANIFEST.MF с корректными Bundle-ClassPath, Import-Package и Require-Bundle.
  2. Используйте совместимые версии библиотек – Okio 2.x до рефакторинга на Kotlin обеспечивает лучшую совместимость с OSGi.
  3. Обёрните библиотеки как OSGi‑пакеты с помощью Bnd или Eclipse PDE.
  4. Включите отладку OSGi для диагностики конфликтов и ошибок загрузки.
  5. Тестируйте в чистой среде OSGi, чтобы убедиться, что конфигурация работает вне IDE.

Для большинства случаев корректная настройка MANIFEST.MF решит проблему. Если проблемы сохраняются, рассмотрите использование репозиториев Eclipse P2 или обёртывание зависимостей как полноценные OSGi‑пакеты.

Авторы
Проверено модерацией
Модерация