1С 8.3 и Java: COM-подключение через Jacob (Connect, Query, выборка)
Jава-приложение на Windows подключается к информационной базе 1С:Предприятие 8.3 через COM: Jacob создаёт ActiveXComponent, Connect принимает строку подключения, данные читают встроенным Запросом платформы. Ниже - справочные сниппеты для разработчика Java или интегратора 1С, которому нужен сеанс 8.3 и обход выборки без промежуточной публикации на стороне конфигурации.
1. Когда уместно Java + COM к 1С 8.3
СОМ-мост между JVM и платформой 1С работает только там, где зарегистрированы классы V83.*, то есть на Windows с клиентом или сервером нужной версии. Если нужен лишь обмен по API, чаще хватает НТТР-сервиса или OData; COM имеет смысл, когда из Java нужен сеанс платформы, NewObject и объект запроса с обходом результата на стороне 1С.
1.1. Сеанс платформы и границы интеграции
COM поднимает сеанс rphost; публикация HTTP или OData отдаёт только то, что описали в контракте, без произвольного доступа к объектной модели конфигурации. Через Jacob вызывают методы аутоматион-интерфейса так же, как внешний код через COMConnector на языке 1С. Такой путь уместен, когда логика уже живёт в Java на Windows и нужны запросы и свойства ссылок без отдельного модуля в базе. Для Линух-сервера приложений тот же приём без машины с Windows и зарегистрированным comcntr не применим - в этой справке кроссплатформенные обходы не разбираем.
1.2. Когда COM не нужен
В 8.3 для РЕСТ-подобного обмена обычно публикуют НТТР-сервис, OData или веб-сервис из конфигурации. Этот путь не требует совпадения битности JVM с comcntr, зато не даёт выполнить произвольный фрагмент языка 1С в сеансе. COM оставляют там, где в Java нужны Query и цикл по выборке на платформе, а не готовый JSON из публикации.
| Механизм | Что получаем | Ограничение |
|---|---|---|
| COM (Jacob) | Сеанс 8.3, NewObject, запросы | Только Windows, разрядность |
| НТТР-сервис | Контракт API конфигурации | Нужна разработка на стороне 1С |
| OData | Чтение опубликованных сущностей | Не вся объектная модель |
| Веб-сервис (SOAP) | Удалённые операции по WSDL | Версионирование контракта |
2. Зависимости Jacob и регистрация COM платформы
После выбора COM собирают минимальный classpath: JAR Jacob и нативе-библиотеку jacob-*.dll, согласованную с разрядностью JVM. JVM должна видеть DLL: указывают -Djava.library.path= каталог с нужной jacob-1.xx-x64.dll (или x86) либо свойство jacob.dll.path из документации Jacob. Параллельно проверяют регистрацию коннектора 8.3 - без неё ActiveXComponent не создаст ProgID V83.Application или V83.ComConnector.
2.1. Jacob: ActiveXComponent, Dispatch, Variant
Jacob оборачивает вызовы IDispatch: ActiveXComponent создаёт СОМ-объект по ProgID, Dispatch.call и Dispatch.get вызывают методы и свойства, Variant хранит скаляры и ссылки. Сбой на стороне COM приходит как ComFailException; в интеграционном коде его не проглатывают: сохраняют полный текст getMessage() и stack trace в лог, иначе отказ Connect выглядит как «ничего не произошло».
2.2. Регистрация comcntr и разрядность
Регистрацию выполняет установщик платформы или вручную для comcntr.dll из каталога bin нужной разрядности. 32-разрядная JVM видит 32-разрядные классы; 64-разрядная JVM не подключится к 32-разрядному COM без отдельной цепочки. Сверяют вывод java -version, разрядность процесса 1cv8 при том же ProgID и какой comcntr зарегистрирован (оснастка COM, при необходимости reg query). Смешение 64-bit Java с 32-bit V83 даёт «класс не зарегистрирован» или ошибку при создании ActiveXComponent ещё до Connect.
На одном хосте часто стоят несколько релизов платформы; ProgID V83.ComConnector относится к линейке 8.3, для другой мажорной версии будет иной идентификатор. Перед сборкой интеграции фиксируют номер клиента 1С, с которым пойдут в production.
3. Инициализация СОМ-объекта и Connect
Когда среда готова, создают СОМ-объект коннектора или приложения и передают строку в Connect. Сначала ComConnector и успешный Connect - иначе NewObject вызовут не в контексте информационной базы. В Jава-классе ниже везде сценарий V83.ComConnector: Connect возвращает Variant, из него берут Dispatch сеанса (app), и уже от него зовут NewObject.
3.1. V83.Application и V83.ComConnector
ProgID V83.Application поднимает аутоматион-приложение 1С, нередко с UI; для фоновой интеграции чаще берут V83.ComConnector, создают экземпляр и вызывают Connect для программного сеанса без лишнего окна клиента. Строка подключения одна и та же; отличаются процесс на рабочей станции и наличие интерфейса. С Application порядок шагов в типовых схемах другой: сначала создание приложения, затем подключение к базе - здесь не смешиваем его с цепочкой ComConnector.Connect в листинге.
3.2. Строка Connect для файловой и клиент-серверной базы
Файловая база: File=каталог;Usr=…;Pwd=…. Клиент-сервер: Srvr=имя_сервера;Ref=имя_базы;Usr=…;Pwd=…. Параметры чувствительны к синтаксису и кавычкам в путях; лишний пробел или неверное имя Ref даёт отказ Connect с текстом платформы в ComFailException. Успешный Connect у ComConnector возвращает Variant сеанса; дальнейшие Dispatch.call выполняют относительно полученного Dispatch, а не относительно самого ActiveXComponent коннектора.
Я обычно проверяю строку Connect из списка баз 1С: если тонкий клиент открывает базу с теми же параметрами, Jава-вызов с тем же текстом сужает круг причин при ComFailException до Jacob, разрядности и прав на каталог или кластер.
4. Запрос через NewObject("Query") и обход выборки
После подключения сеанса получают объект запроса через NewObject("Query"), задают Text и проходят цепочку Execute, Choose, Next. На русскоязычной установке аутоматион-имена часто совпадают с языком 1С: при ошибке на NewObject пробуют "Запрос", методы - Execute/Выполнить, Choose/Выбрать, Next/Следующий в зависимости от локали COM. Вызовы в листинге даны в английских именах, как в типовых примерах Jacob к 8.3.
4.1. Текст запроса и выполнение
Текст на языке запросов 1С задают свойством Text; надёжнее передать строку через new Variant(queryText) в Dispatch.put. Имена объектов метаданных берут из вашей конфигурации - в примере типовой справочник номенклатуры.
ВЫБРАТЬ
Номенклатура.Ссылка КАК Ссылка,
Номенклатура.Наименование КАК Наименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
НЕ Номенклатура.ПометкаУдаления
После установки Text вызывают Execute, затем Choose для построения выборки. Execute возвращает результат запроса на стороне платформы; обход строк - через Choose и цикл Next, а не через таблицу значений в Java.
4.2. Цикл Next и чтение полей
Пока Next возвращает true, поля читают через Dispatch.get по псевдониму колонки. Для ссылки - getDispatch(), для строки - getString() у Variant. Полный каркас с try/finally, логированием ComFailException и чтением UUID ссылки - в фрагменте ниже; текст запроса совпадает с блоком выше.
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.ComFailException;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;
public final class V83ComQuerySample {
private ActiveXComponent comConnector;
private Dispatch app;
public void openSession(String connectString) {
comConnector = new ActiveXComponent("V83.ComConnector");
Variant session = Dispatch.call(comConnector, "Connect", connectString);
app = session.toDispatch();
}
public void readNomenclature() {
// На RU-клиенте при ошибке NewObject("Query") попробуйте "Запрос"
Dispatch query = Dispatch.call(app, "NewObject", "Query").getDispatch();
String queryText =
"ВЫБРАТЬ\n"
+ " Номенклатура.Ссылка КАК Ссылка,\n"
+ " Номенклатура.Наименование КАК Наименование\n"
+ "ИЗ\n"
+ " Справочник.Номенклатура КАК Номенклатура\n"
+ "ГДЕ\n"
+ " НЕ Номенклатура.ПометкаУдаления";
Dispatch.put(query, "Text", new Variant(queryText));
// Dispatch.call(query, "УстановитьПараметр", "Дата", new Variant(...));
Dispatch result = Dispatch.call(query, "Execute").getDispatch();
Dispatch selection = Dispatch.call(result, "Choose").getDispatch();
while (Dispatch.call(selection, "Next").getBoolean()) {
Dispatch itemRef = Dispatch.get(selection, "Ссылка").getDispatch();
String name = Dispatch.get(selection, "Наименование").getString();
Variant uuid = Dispatch.call(itemRef, "УникальныйИдентификатор");
System.out.println(uuid.getString() + " " + name);
}
}
public void closeSession() {
if (app!= null) {
try {
Dispatch.call(app, "Disconnect");
} catch (ComFailException e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
app = null;
}
if (comConnector!= null) {
comConnector.safeRelease();
comConnector = null;
}
}
public static void main(String[] args) {
// -Djava.library.path=каталог с jacob-*.dll той же разрядности, что и JVM
V83ComQuerySample sample = new V83ComQuerySample();
try {
sample.openSession("File=...;Usr=...;Pwd=...");
sample.readNomenclature();
} catch (ComFailException e) {
System.err.println(e.getMessage());
e.printStackTrace();
} finally {
sample.closeSession();
}
}
}
Псевдонимы в Dispatch.get должны совпадать с запросом (Ссылка, Наименование). Параметры с &Имя в тексте задают до Execute, например: Dispatch.call(query, "УстановитьПараметр", "Дата", new Variant(...)); - на ЕН-клиенте имя метода может быть SetParameter. Без параметров отбор остаётся только в тексте запроса.
5. Типы Variant/Dispatch и ссылочные значения
Здесь чаще всего сыпятся ошибки приведения на JVM: колонка «ссылка» в COM приходит как Dispatch, а не как UUID Java.
5.1. getDispatch для ссылок
Для колонки Ссылка берут getDispatch() у Variant из выборки. Стабильный ключ для внешней системы удобно получить вызовом automation ссылки, например Dispatch.call(itemRef, "УникальныйИдентификатор") (на РУ-клиенте то же имя, что в языке 1С). Представление для лога - через Dispatch.get(itemRef, "Представление") или поле ПРЕДСТАВЛЕНИЕ(Ссылка) в запросе, если на границе COM достаточно строки.
5.2. Псевдокод цепочки типов
Ниже - цепочка типов на границе COM (псевдокод), без подмены ссылок на Jава-типы.
// псевдокод: типы на границе COM
ActiveXComponent(ProgID V83.ComConnector)
Connect(строка) -> Dispatch app
NewObject("Query") -> Dispatch query
Text = язык запросов 1С
Execute() -> Dispatch result
Choose() -> Dispatch selection
while Next()
get("Ссылка") -> Variant -> getDispatch() -> Dispatch ref
call(ref, "УникальныйИдентификатор") -> Variant
get("Наименование") -> Variant -> getString()
Если нужна только строка без удержания СОМ-ссылки, проще добавить в запрос ПРЕДСТАВЛЕНИЕ(Ссылка) и читать её getString() - так реже путают Variant и «сырой» UUID.
6. Завершение сеанса и сообщения COM об ошибках
Незакрытый СОМ-сеанс оставляет rphost или 1cv8 в диспетчере задач; в коде закладывают finally с Disconnect и safeRelease для ActiveXComponent.
6.1. Disconnect и Release
Для сеанса после ComConnector.Connect вызывают Disconnect у объекта сеанса (app в листинге), затем обнуляют ссылки Dispatch и safeRelease() у коннектора. Jacob держит нативе-счётчики COM; без Release JVM может завершиться, а процесс 1С ещё некоторое время останется активным. Если сеанс поднимали через V83.Application, на практике дополнительно смотрят завершение аутоматион-приложения (Terminate и т.п.) по документации вашей версии - в примере только ComConnector.
6.2. Симптомы ComFailException и что проверить
«Класс не зарегистрирован» при new ActiveXComponent: переустановка или regsvr32 comcntr нужной разрядности, проверка ProgID в оснастке COM. Ошибка на Connect: сверить File или Srvr/Ref, учётную запись, права на каталог файловой базы, доступность кластера. Сбой сразу после Execute: синтаксис запроса и имена метаданных в конфигурации. HRESULT 0x80040154 часто указывает на несовпадение разрядности или отсутствие регистрации; 0x80070005 (E_ACCESSDENIED) - права, политики, иногда неверные учётные данные в строке, не только пароль.
Имеет смысл также проверить антивирус и политики, блокирующие запуск rphost из сервиса Java: картина может напоминать «зависший» Connect при верной строке.
7. Ограничения и смежные механизмы платформы
COM из Java не масштабируется как пул stateless НТТР-запросов: каждый сеанс тяжёлый, его число ограничено лицензией и ресурсами сервера 1С. Долгие циклы Next без сужения выборки в тексте запроса нагружают тот же rphost, что и интерактивный пользователь.
7.1. Границы подхода
Jacob COM работает только там, где зарегистрирован V83.*, - practically Wиндоwс-хост с клиентом 1С; macOS и Linux без такого хоста не рассматриваем. Штатная публикация сервисов остаётся основным путём для мобильных и веб-клиентов. После смены мажорной версии платформы перепроверяют Connect и ProgID. Один Dispatch сеанса не рассчитан на параллельные вызовы из разных потоков Java: COM 1С живёт в арартмент-модели, синхронизацию делают снаружи.
7.2. Когда брать COM из Java
| Ситуация | Решение | Риск |
|---|---|---|
| Нужен Query и обход выборки из Java на Windows | V83.ComConnector, Jacob, Connect, NewObject("Query") | Зависшие rphost при отсутствии Disconnect |
| ActiveXComponent падает при создании | Согласовать разрядность JVM и comcntr, перерегистрация V83.* | Отказ в production без логирования HRESULT |
| Поле ссылка в Java не строка | getDispatch(), свойства ссылки или ПРЕДСТАВЛЕНИЕ в запросе | Неверный ключ во внешней БД |
| Интеграция с Линух-сервера приложений | НТТР-сервис или OData вместо COM | Дублирование логики при последующем запросе COM |
| Фоновое чтение без UI | ComConnector вместо V83.Application | Лишние окна клиента при неверном ProgID |
Перед prod проверьте строку в тонком клиенте 1С и одним JВМ-тестом той же разрядности выполните Connect и короткий запрос на одну строку выборки. Оба шага прошли - разбор полей, параметры и Release в finally можно переносить в основной модуль интеграции.
Вступайте в нашу телеграмм-группу Инфостарт
Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.