Ответ 1
JAX-RS отправляет методы, аннотированные с помощью @Produces через заголовок Accept. Итак, если вы хотите, чтобы JAX-RS выполнял вашу диспетчеризацию, вам необходимо использовать этот механизм. Без какой-либо дополнительной работы вам нужно будет создать метод (и провайдер) для каждого типа носителя, который вы хотите поддерживать.
Ничего не мешает вам иметь несколько методов на основе типа мультимедиа, которые вызывают общий метод для выполнения этой работы, но вам придется обновлять их и добавлять код каждый раз, когда вы добавляете новый тип носителя.
Одна идея - добавить фильтр, который "нормализует" ваш заголовок Accept специально для отправки. То есть, возможно, принимая ваши:
Accept: application/vnd.COMPANY.systeminfo-v1+json
И преобразуя это, просто:
Accept: application/vnd.COMPANY.systeminfo+json
В то же время вы извлекаете информацию о версии для последующего использования (возможно, в запросе или какой-либо другой механизм ad hoc).
Затем JAX-RS отправит единственный метод, который обрабатывает "application/vnd.COMPANY.systeminfo + json".
Затем метод THAT берет "внеполосную" информацию о версии для обработки деталей при обработке (например, для выбора подходящего класса для загрузки через OSGi).
Затем вы создаете Провайдера с соответствующим MessageBodyWriter. Поставщик будет выбран JAX-RS для типа application/vnd.COMPANY.systeminfo + json. Это будет до вашего MBW, чтобы выяснить фактический тип носителя (основанный снова на этой информации о версии) и создать правильный формат вывода (опять же, возможно, отправив правильный класс OSGi).
Я не знаю, может ли MBW перезаписать заголовок Content-Type или нет. Если нет, то вы можете делегировать более ранний фильтр, чтобы переписать эту часть для вас на выходе.
Это немного запутанно, но если вы хотите использовать JAX-RS-рассылку и не создавать методы для каждой версии вашего типа медиа, то это возможный путь для этого.
Изменить в ответ на комментарий:
Да, по сути, вы хотите, чтобы JAX-RS отправлялся в соответствующий класс на основе типа Path и Accept. Маловероятно, что JAX-RS сделает это из коробки, так как это немного кромка. Я не смотрел ни на одну из реализаций JAX-RS, но вы можете сделать то, что хотите, путем настройки одного из уровней инфраструктуры.
Возможно, еще один менее инвазивный вариант - использовать старый мир из мира Apache и просто создать фильтр, который переписывает ваш путь на основе заголовка Accept.
Итак, когда система получает:
GET /resource
Accept: application/vnd.COMPANY.systeminfo-v1+json
Вы переписываете его на:
GET /resource-v1
Accept: application/vnd.COMPANY.systeminfo-v1+json
Затем в вашем классе JAX-RS:
@Path("resource-v1")
@Produces("application/vnd.COMPANY.systeminfo-v1+json")
public class ResourceV1 {
...
}
Итак, ваши клиенты получают правильный вид, но ваши классы правильно отправляются JAX-RS. Единственная другая проблема заключается в том, что ваши классы, если они будут выглядеть, будут видеть измененный Путь, а не исходный путь (но ваш фильтр может заполнить это в запросе в качестве ссылки, если хотите).
Он не идеален, но он (в основном) свободен.
Этот - это существующий фильтр, который может делать то, что вы хотите сделать, если он не может стать для вас вдохновением сами.