Речь идет об использовании JAX-WS с EclipseLink MOXy и моей проблеме невозможности использования внешних картографических документов MOXy в этой комбинации. (То же самое, по-видимому, применимо и к JAX-RS, но я ограничиваю детали JAX-WS, чтобы это не стало еще длиннее, чем это уже есть).
Сначала я опишу (с некоторыми подробностями) контекст моих требований и тестовый код, который я написал, чтобы попытаться их решить. Актуальный вопрос следует в конце поста.
Контекст:
В некоторых унаследованных частях нашего проекта мы используем JAX-WS прямо поверх простой серверной модели POJO. Модель является частью API, который мы используем для прямых вызовов Java, но мы также предоставляем уровень SOAP, реализующий тот же интерфейс Java, что и наша прямая реализация, т.е. у нас есть интерфейс IManager, использующий нашу модель, и вызывающему абоненту все равно, его экземпляр IManager является локальной реализацией или клиентом SOAP, который вызывает оболочку сервера JAX-WS для локальной реализации.
Назад, когда мы начали реализовывать модель, мы не знали много о JAXB, поэтому модель не имеет аннотаций JAXB, и все автоматически выводится JAX-WS. Из аннотированных серверных классов JAX-WS мы создаем клиента с использованием wsgen и wsimport. Но поскольку модель является частью нашего API, а модель, сгенерированная wsimport, представляет собой отдельный набор классов (хотя и с одинаковыми сигнатурами), мы должны обернуть все клиентские вызовы методами, которые копируются между этими двумя моделями. Копирование из одной модели в другую осуществляется вручную и должно обновляться вручную для каждого незначительного изменения в модели API.
Поскольку сервер и клиент находятся под нашим контролем, мы хотели бы использовать один и тот же набор (рукописных) классов моделей в реализации сервера и клиента. Я провел последние несколько недель, играя с тестовым проектом, который работает, но еще не полностью удовлетворяет меня.
Я построил свой тестовый проект в три этапа:
Шаг 1. Реализация простого тестового API, состоящего из модели и интерфейса менеджера. Затем создайте простую реализацию.
В моем случае модель состоит в основном из IPerson и интерфейса IBook, а IModelManager имеет методы для получения, хранения / обновления и удаления людей и книг. Интерфейс также обеспечивает фабрику для создания новых людей и книг, поэтому клиентским проектам требуется только API во время компиляции (и реализация во время выполнения).
Шаг 2. Предоставление модулей для сериализации в и из XML и JSON.
Благодаря поддержке внешних картографических документов я поиграл с EclipseLink MOXy. Это позволило мне взять мою модель из шага 1 и добавить декларации привязки XML в мой отдельный проект сериализации. Я мог бы также написать свои служебные классы сериализации таким образом, чтобы вызывающий их клиентский код знал только об API, то есть все сигнатуры методов опираются только на интерфейсы модели, а не на классы реализации. Все это, не затрагивая классы из шага 1 - все элементы сериализации были аккуратно наложены поверх проекта реализации Java.
Шаг 3. Предоставление уровней SOAP и REST через JAX-WS и JAX-RS.
Теперь я написал серверные классы для SOAP и REST, используя аннотации JAX-WS и JAX-RS. Из классов JAX-WS я сгенерировал клиента с помощью wsgen и wsimport и включил его в реализацию IModelManager на стороне клиента, которая просто перенаправляет вызовы в класс клиента, сгенерированный wsimport. Для классов JAX-RS я использовал Jersey с аннотациями в своем классе сервера и написал реализацию IModelManager, которая использует клиентские классы Jersey для вызова службы REST.
Здесь я потерял некоторые приятные функциональные возможности с шага 2.
Используя плагин JAX-WS EclipseLink, весь код JAX-WS использует MOXy для сериализации и десериализации модели (или, по крайней мере, я так думаю). Но я не смог найти способ указать мои внешние файлы привязки. Мне пришлось добавить аннотации к моей фактической реализации модели с шага 1 (и даже к API, потому что модель также включает перечисление, на которое ссылаются интерфейсы, и перечисление также нуждается в аннотациях JAXB). Мне также пришлось изменить свой серверный класс JAX-WS, чтобы использовать классы реализации модели вместо интерфейсов (сейчас я просто использую приведение в случае необходимости, предполагая, что никогда не будет другой реализации модели).
Используя WSDL и схему, сгенерированную из обновленной модели wsgen, я могу вызвать wsimport с пользовательским XML-привязкой JAXB, чтобы сгенерировать клиент, который отображает все типы из сгенерированного XSD в мои существующие классы моделей вместо генерации новых. В результате получается клиентский интерфейс, который принимает и возвращает интерфейсы модели из моего API и всегда использует стандартную реализацию. Мне просто нужно написать простые оболочки и привести классы реализации моей модели к интерфейсам API в нескольких местах, что является огромным улучшением по сравнению с нашим унаследованным кодом с его дублирующимися (и тройными) моделями и множеством логики копирования.
Вопрос:
Меня не устраивает необходимость аннотировать все мои классы моделей напрямую (и даже перечисления в API), особенно учитывая, что у меня был рабочий конвейер сериализации / десериализации без аннотаций на шаге 2. Предположительно, если бы я мог предоставить wsimport и код, который запускает реализацию JAX-WS на стороне сервера с моими документами отображения MOXy, я мог бы обойтись без каких-либо аннотаций, как в шаге 2. Мне даже кажется, что если бы я мог предоставить wsgen файлы отображения, я мог бы использовать мои интерфейсы API (вместо классов реализации) в методах JAX-WS на стороне сервера и обходиться без всех приведений, и, возможно, даже без файла привязок JAXB, который вручную сопоставляет созданные XSD типы wsgen с моими существующими классами.
Но я не смог найти способ предоставить JAX-WS сопоставления MOXy, ни инструменты wsgen и wsimport, ни клиентский или серверный код. Есть ли что-то, чего я упускаю, или нет, действительно ли это пробел в мосте MOXy JAX-WS, и есть ли шанс заполнить его, чтобы получить полную функциональность MOXy в будущей версии? Или я совершил фундаментальную ошибку в своем мышлении, и решения либо не может быть, либо оно уже есть? (Отсюда и мое подробное описание моего тестового проекта)
Целевой платформой является обычная Java 8, либо как отдельное приложение (с Jetty, использующим javax.xml.ws.Endpoint для публикации службы SOAP и Jersey для службы REST), так и Tomcat с Jersey. Мои тесты выполняются непосредственно в JUnit с использованием Endpoints и JerseyTest, а также ручные тесты в Tomcat.