#java #client-side #cxf #jax-rs
#java #на стороне клиента #cxf #jax-rs
Вопрос:
Краткое изложение проблемы:
Мне нужно каким-то образом настроить клиент JAX-RS, реализованный с использованием клиентского API на основе прокси-сервера CXF, для автоматического преобразования параметров, аннотированных с помощью @FormParam, в JSON.
Я создал несколько сервисов в Apache CXF JAX-RS, которые принимают несколько потенциально сложных объектов в качестве аргументов. Реализуя valueOf(String s) для сложных компонентов, я могу передать в «метод» несколько объектов, закодированных в формате JSON, а не только один, как это обычно бывает.
Примером реализации может быть следующее:
@Service("receiverService")
@Path("/receiver")
public class ObjectReceiverService {
@POST
@Path("jsonTest")
@Produces("application/json")
public MyObject jsonTest(@FormParam("myPrimitive") int myPrimitive, @FormParam("myComplex") MyObject myComplex) {
return myComplex;
}
...//
}
//domain class with Mapper from Jackson
public class MyObject {
public String foo;
public String bar;
public String baz;
public static MyObject valueOf(String s) throws Exception {
return new ObjectMapper().readValue(s, MyObject.class);
}
...//implementation of equals() etc.
}
Это работает довольно хорошо. До сих пор я тестировал это, прибегая к низкоуровневым материалам; вручную создавая строки запроса с использованием ObjectMapper Джексона и т.д. Пример:
//test class with lots of manual setup using WebClient
public class ObjectReceiverServiceTest {
@Before
public void setup() {
ProviderFactory.getSharedInstance().registerUserProvider(new JacksonJsonProvider());
}
@org.junit.Test
public void jsonTest1_recievingSameObject() throws Exception {
String url = "http://localhost:8080/";
String path = "rest/receiver/jsonTest";
MyObject myObjectToSend = new MyObject();
MyObject result = new MyObject();
myObjectToSend.foo = "foo";
myObjectToSend.bar = "bar";
myObjectToSend.baz = "baz";
WebClient client = WebClient.create(url);
client.path(path);
client.accept("application/json").type(MediaType.APPLICATION_FORM_URLENCODED_TYPE);
Response r = client.post("myPrimitive=123amp;myComplex=" new ObjectMapper().writeValueAsString(myObjectToSend));
result = new ObjectMapper().readValue(new BufferedReader(new InputStreamReader((InputStream) r.getEntity())).readLine(), MyObject.class);
assertEquals(myObjectToSend, result);
}
Что я хотел бы сделать, так это использовать API на основе прокси, как продемонстрировано в документах CXF. Это было бы намного чище и быстрее в реализации. Предыдущий тест был бы чем-то вроде
@org.junit.Test
public void jsonTest2_recievingSameObject() throws Exception {
String url = "http://localhost:8080/rest";
ObjectReceiverService service = JAXRSClientFactory.create(url, ObjectReceiverService.class);
MyObject myObjectToSend = new MyObject();
myObjectToSend.foo = "foo2";
myObjectToSend.bar = "bar2";
myObjectToSend.baz = "baz2";
MyObject result = service.jsonTest(123,myObjectToSend);
assertEquals(myObjectToSend, result);
}
Сегодня это вызывает исключение WebApplicationException в org.apache.cxf.jaxrs.provider.FormEncodingProvider.writeTo(..), поскольку он, вероятно, просто ожидает примитивы.
Я не совсем уверен, как с этим бороться. Есть идеи? Возможно ли каким-либо образом создать аннотацию, скажем @JSONtoString , которая каким-то волшебным образом заменила бы метод objects toString на метод JSON? Как в String toString() { возвращает новый ObjectMapper.writeValueAsString(this); }
Комментарии:
1. Не ответ, а дополнительная информация из списка рассылки Sergey@CXF: (я): Я не совсем уверен, как с этим справиться. Есть идеи? Я попытался переопределить toString() с помощью { return new ObjectMapper.writeValueAsString(this); } , что нормально, но FormEncodingProvider.writeTo по-прежнему терпит неудачу при попытке преобразовать нестроковые объекты, такие как целое число в строку. — (Сергей:)Да, он ожидает только строки — я думаю, что исправление должно быть применено на стороне клиента до вызова FormEncodingProvider, потому что JAX-RS требует поддержки MultivaluedMap<Строка, String> —