REST Client

At this version of WebSphere, JAX-RS 1.1 is supported, but that doesn’t include any REST Client support. JAX-RS 2.0 apparently does, but that’s not yet available here on WAS 8.5.5 Full Profile. It is on Liberty Profile, but that’s not what we’re using.

However, WebSphere’s JAX-RS Server support uses Apache Wink, which does include REST Client capability. And, in fact, is the REST Client mechanism recommended by WebSphere’s official documentation:

Implementing clients that use the Apache Wink REST client

Those steps are actually pretty clear and comprehensive. I’ll give quick examples of the mostly-default code I used. (Showing full class packages inline, just once, for simplicity.)

    org.apache.wink.client.RestClient client = new RestClient();  
    org.apache.wink.client.Resource resource = client.resource(resourceURL);  
    try {  
        MyJsonResponseDataTypeBean responseBean =  
            resource.accept(javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE)  
                    .get(MyJsonResponseDataTypeBean.class);  

       // work with or return responseBean  
    }  

    // HTTP error response codes. Unchecked Exception. Subclass of ClientRuntimeException  
    catch (org.apache.wink.client.ClientWebException e) {  
        org.apache.wink.client.ClientResponse response = e.getResponse();  
        // however you want to handle HTTP error response codes  
    }  

    // Other call errors. Also Unchecked Exception  
    catch (org.apache.wink.client.ClientRuntimeException e) {  
        // however you want to handle other exeptions  
    }

The Wink Javadoc shows those unchecked Exceptions for one form of the operations, like post().

Another form of each operation does not throw that Exception, but allows you to manually check the ClientResponse yourself. This is how the example in the above WAS documentation does things. (Note that even those methods do seem to throw ClientRuntimeException for things like communication errors, despite the javadoc not indicating that.)

POST

Speaking of POST, here’s what that looks like. With a JSON payload as well.

    MyJsonResponseDataTypeBean responseBean =  
        resource.contentType(MediaType.APPLICATION_JSON_TYPE)  
                .accept(MediaType.APPLICATION_JSON_TYPE)  
                .post(MyJsonResponseDataTypeBean.class, MyJsonRequestDataTypeBean);

Adding HTTP Basic Authentication

From another WebSphere Knowledge Center article, Securing JAX-RS applications within the web container, which largely describes securing your JAX-RS services, we also find the technique for passing HTTP Basic Authentication in your Wink client requests:

    org.apache.wink.client.ClientConfig config = new ClientConfig();  
    org.apache.wink.client.handlers.BasicAuthSecurityHandler handler = 
        new BasicAuthSecurityHandler(username, password);  
    config.handlers(handler);  
    RestClient client = new RestClient(config); // instead of just new RestClient()

JSON Beans and Serializing/Deserializing

So what allows automatically serializing a request POJO into JSON or deserializing a response JSON into a POJO? I had some naive hope that perhaps just being a JavaBean would be sufficient. But alas, it is not.

Would I have to manually parse the JSON, using something like com.ibm.json.java.JSONObject?

Thankfully, no. Also in the original WebSphere Rest Client article linked above, we find this statement:

Instead of calling the response.getEntity(String.class) object with String.class file, you can use any other class that has a valid javax.ws.rs.ext.MessageBodyReader object, such as a JAXB annotated class, a byte[], or a custom class that has a custom entity provider.

JAXB annotated class, that’s super simple. (Still feels a bit weird that JAXB annotations are used for JSON serialization in WAS. Don’t know if other servers do this as well. But easy.) If I do this in a base class, the subclasses don’t have to also add the annotation:

import javax.xml.bind.annotation.XmlType;

@XmlType  
public class JsonBase {}

Unwanted Fields

Hmmm… do I have to declare in the POJO every field and sub-object the JSON could have? That would be really frustrating and difficult to maintain. Maybe I’d rather just parse the fields I care about after all.

Yeah, look. If I don’t declare every field, I get errors like this on deserialization:

org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "start" (Class MyJsonDataType), not marked as ignorable

Jackson, eh? So WebSphere uses Jackson for its JSON serialization.

And, as usual, StackOverflow to the rescue. @JsonIgnoreProperties will do the trick. So change the base class to:

import javax.xml.bind.annotation.XmlType;  
import org.codehaus.jackson.annotate.JsonIgnoreProperties;

@XmlType  
@JsonIgnoreProperties(ignoreUnknown = true)  
public class JsonBase {}

Now all subclasses only have to declare whatever fields they want parsed or sent.

Some additional notes

  • For reference, if/when moving from JAX-RS 1.1, based on Wink, to 2.0, based on CXF: https://www.ibm.com/support/knowledgecenter/was_beta_liberty/com.ibm.websphere.wlp.nd.multiplatform.doc/ae/cwlp_jaxrs_behavior.html (Oct 2 2017)
  • FWIW, appears JAX-RS 2.0 under WebSphere no longer exposes the Jackson classes, so that will necessitate a change to this approach: https://www.ibm.com/support/knowledgecenter/en/SSEQTP_liberty/com.ibm.websphere.wlp.doc/ae/cwlp_jaxrs_behavior.html (Feb 15 2017)