Quick sum-up of the problem:
I need to somehow configure a JAX-RS client implemented using CXF's
proxy-based client API, to automatically convert parameters annotated
with @FormParam to JSON. I cannot get this to work today.
I pasted the example code on PasteBin for better viewing:
http://www.pastebin.ca/2069097
I have created some services in Apache CXF JAX-RS that takes several
potentially complex objects as arguments. By implementing
valueOf(String s) for complex beans + using @FormParam, I can
pass several JSON encoded objects to the "method", not just one,
as would normally be the case.
This might not be the best way, or even a good way, to achieve the goal
of being able to have several arbitrarily complex objects as parameters in
a POST service, but it is the one I could think of ...
Feel free to suggest a better way ;)
An example implementation could be the following:
@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.
}
This works quite nicely. So far I have tested it by resorting to
low-level stuff; manually constructing query strings using Jackson's
ObjectMapper etc. Example:
//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=123&myComplex=" + new
ObjectMapper().writeValueAsString(myObjectToSend));
result = new ObjectMapper().readValue(new BufferedReader(new
InputStreamReader((InputStream) r.getEntity())).readLine(),
MyObject.class);
assertEquals(myObjectToSend, result);
}
What I would like to do, is to use the proxy based api, as
demonstrated in the CXF docs. This would be far cleaner and faster to
implement. The previous test would be something like
@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);
}
Today, this throws an WebApplicationException in
org.apache.cxf.jaxrs.provider.FormEncodingProvider.writeTo(..), as it
is probably just expecting primitives.
I am not quite sure how to deal with this. Any ideas? I tried
overriding toString() with { return new
ObjectMapper.writeValueAsString(this); }, which is ok, but
FormEncodingProvider.writeTo still fails when trying to convert
non-string objects,
like an Integer to String.
Regards
Carl-Erik