JAX-RS отправляет методы, помеченные @Produces, через заголовок Accept. Итак, если вы хотите, чтобы JAX-RS осуществлял диспетчеризацию, вам нужно использовать этот механизм. Без дополнительной работы вам придется создать метод (и поставщика) для каждого типа носителя, который вы хотите поддерживать.
Ничто не мешает вам иметь несколько методов, основанных на типе носителя, которые все вызывают общий метод для выполнения этой работы, но вам придется обновлять его и добавлять код каждый раз, когда вы добавляете новый тип носителя.
Одна из идей - добавить фильтр, который «нормализует» заголовок Accept специально для отправки. То есть, возможно, вы берете:
Accept: application/vnd.COMPANY.systeminfo-v1+json
И, преобразовав это, просто:
Accept: application/vnd.COMPANY.systeminfo+json
В то же время вы извлекаете информацию о версии для последующего использования (возможно, в запросе или каком-либо другом специальном механизме).
Затем JAX-RS отправит один метод, который обрабатывает "application / vnd.COMPANY.systeminfo + json".
Затем этот метод получает информацию о версиях «out-of-band» для обработки деталей при обработке (например, выбор подходящего класса для загрузки через 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 правильно отправляет ваши классы. Единственная другая проблема заключается в том, что ваши классы, если они посмотрят, увидят измененный путь, а не исходный путь (но ваш фильтр может добавить это в запрос в качестве ссылки, если хотите).
Это не идеально, но это (в основном) бесплатно.
Этот - это существующий фильтр, который может делать то, что вы хотите сделать, если нет, то он может послужить вам вдохновением, чтобы сделать это самостоятельно.