Ответ 1
Немного покопавшись, я быстро обнаружил, что есть два основных варианта:
Опция 1
Вы передаете "объект-обертку", содержащий все остальные параметры, службе. Возможно, вам потребуется аннотировать этот класс-оболочку аннотациями JAXB, такими как @XmlRootElement, чтобы он работал с провайдером на основе Jettison, но если вы используете Джексона вместо него, в этом нет необходимости. Просто установите тип контента на правильный тип, и будет вызван правильный читатель тела сообщения. Конечно, это будет работать только для услуг типа POST (AFAIK).
пример
Это всего лишь пример превращения службы, упомянутой в первоначальном вопросе, в службу, использующую объект-оболочку.
@Service("myService")
class RestService {
@POST
@Produces("application/json")
@Path("/fooBar")
public Result fooBar(
/**
* Using "" will inject all form params directly into a ParamsWrapper
* @see http://cxf.apache.org/docs/jax-rs-basics.html
*/
@FormParam("") FooBarParamsWrapper wrapper
) throws WebServiceException {
doSomething(wrapper.foo);
}
}
class ParamsWrapper {
double foo, bar;
MyComplexObject object;
}
Вариант 2
Вы можете предоставить некоторый специальный формат строки, в который вы упаковываете ваши объекты, а затем реализуете конструктор, принимающий строку, статический valueOf (String s) или статический fromString (String s) в классе, который будет принимать эту строку и создавать объект от него. Или совсем аналогично, создайте ParameterHandler, который делает то же самое.
AFAIK, только вторая версия позволит вам вызывать ваши сервисы из браузера, используя JSONP (поскольку JSONP - это трюк, ограниченный GET). Я выбрал этот маршрут, чтобы можно было передавать массивы сложных объектов в URI.
В качестве примера того, как это работает, возьмем следующий класс домена и службу
пример
@GET
@Path("myService")
public void myService(@QueryParam("a") MyClass [] myVals) {
//do something
}
class MyClass {
public int foo;
public int bar;
/** Deserializes an Object of class MyClass from its JSON representation */
public static MyClass fromString(String jsonRepresentation) {
ObjectMapper mapper = new ObjectMapper(); //Jackson JSON marshaller
MyClass o= null;
try {
o = mapper.readValue(jsonRepresentation, MyClass.class );
} catch (IOException e) {
throw new WebApplicationException()
}
return o;
}
}
URI http://my-server.com/myService?a={"foo":1, "bar":2}&a={"foo":100, "bar":200}
в этом случае будет десериализован в массив, состоящий из двух объектов MyClass.
Комментарий 2019 года. Видя, что в 2019 году этот ответ по-прежнему встречается, я чувствую, что должен это прокомментировать. Оглядываясь назад, я бы не рекомендовал вариант 2, поскольку выполнение этих шагов только для того, чтобы иметь возможность выполнять вызовы GET, добавляет сложности, которая, вероятно, того не стоит. Если ваш сервис принимает такие сложные входные данные, вы, вероятно, не сможете использовать кэширование на стороне клиента из-за количества перестановок вашего ввода. Я бы просто настроил правильные заголовки Cross-Origin-Sharing (CORS) на сервере и POST-ввод. Затем сконцентрируйтесь на кэшировании всего, что можете на сервере.