Sunday, October 14, 2012

JAXRS client on Android

Context


Not a while ago I realized that for many people on this planet including my parents, smart-phone application is the only way they understand to interact with Internet. Therefore with zero client side software development experience, I started learning Android app programming.

Only after several days of learning I found myself blocked for there doesn't seem to be a clear answer for a problem that is so essential -- how to create JAXRS client on Android application. After days of trying a working solution finally presented to me. This document talks about the solution that I found as well as, more importantly, the solutions that do not work.

It's really important to known what we are looking for before start coding. I found many discussions on internet where people provide irrelevant because they have no idea what they are looking for. A solution must satisfy all following criteria:

  1. A Java library that calls HTTP RESTful service, preferably support HTTPS, wth/without client certificate authentication. Must support interception to allow injection of additional code logic around calls.
  2. Compatible to JAXRS(JSR311). Library must provides API that returns Java proxy of JAXRS annotated interface, via which method invocation is interpreted as HTTP RESTful calls
  3. Runs on Android. To be specific, the library and all its dependencies' must fall into the subset of JavaSE API that Android platform supports.

Apache CXF


In my experience in past most RESTful applications are built on Apache CXF framework, which satisfies #1 and #2 nicely and requires minimal coding and configuration. Unfortunately it fails for #3 which is not very surprising.

Jersey based solution


This document is at the top of Google search result from keywords "JAXRS" and "Android" at the time I write this document. Steps in detail seem to imply that the author did have it work on an Android device. However this Jersey 1.x based solution does not satisfy #2. Jersey is the reference implementation of JSR311 for server side implementation, while the client side API is low-level and could be tedious for RESTful interfaces with large number of methods.

Jersey proxy client


It's kind of unbelievable that Jersey does not provide high-level client API that satisfies #2 while many of its competitors(like CXF) do. With a little research I found that there is an ongoing and young client proxy subproject under Jersey based on JAXRS 2.0(JSR-339). It's available in official Maven repository. I went ahead and added it into my Android app, which requires to upgrade all Jersey dependencies to 2.0 and JAXRS API to 2.0, at which point it started violating #3 and failed to run on Android. Worth a try though.

Finally something is working, RestEasy-mobile


This discussion might be the second item on the top of Google search result. A lot of things are covered, of which almost all are waste of time. It's amazing how much people want to jump in before they even understand the question.

You may see that the starter asked the same question, a JAXRS client that runs on Android, which is commented with "have you tried X, a simple enough JAXRS client?", "here's how to access JAXRS service in Java" and "What's API level 9?". The only thing that turns out to work after hours of trying is JBoss resteasy-mobile, someone mentioned it in discussion but no one seemed to follow up. A lesson learnt from here is, if a library does not explicitly claim it runs on Android, it usually doesn't.

Gotchas


Before the first HTTP call went through via resteasy-mobile I ran into a number of issues, which weren't problem when I built non-Android RESTful services in past.

  1. JAXB annotations are unsupported and must be removed. Even when I didn't plan to rely on them, having a useless JAXB annotation in POJO caused Andoid app to fail. This also implies that as long as interface is shared between client and server, server can not use jaxb or jackson-jaxb-json provider. I ended up using jackson-json provider.
  2. @Consumes must be defined in API. It's not required by CXF client, but required by resteasy-mobile as far as I can tell.
  3. @Produces must be defined in API probably for similar reason. In CXF when @Consumes and @Produces are undefined, library usually can intelligently match out the right data binding provider, while obviously, resteasy-mobile can not. (further confirmation needed)

Conclusion


After all the research, JBoss resteasy-mobile is the only solution I found working for me so far. I hope this document helps you avoid wasting efforts on dead ends like I did.

Solution HTTP client library JAXRS interface proxy Runs on Android
Apache CXF Yes Yes No
Jersey Client 1.x Yes No Yes
Jersey Client Proxy 2.x Yes Yes No
JBoss resteasy-mobile Yes Yes Yes
RESTlet edition for Android Yes No Yes
Resty Yes No No

Post a Comment