Search code examples
jax-rscxf

Using javax.ws.rs.client.ClientBuilder in CXF to create Client, any route to be able to use local transport?


I work on a codebase that uses the standard "javax.ws.rs.client.ClientBuilder" class, from the CXF distribution, to configure and create a "javax.ws.rs.client.Client".

This works well enough.

I'm now trying to write tests that use JAXRSServerFactoryBean to manage a fake server using a controller defined by an inline class. I can set my host:port to localhost:something, both in the test and in the client configuration, and this works well enough to allow me to test our MessageBodyReaders and Http exception handling.

However, I think this won't be "scalable", as each fake server will have to run on a "dedicated" port (while running the test, at least). I can try to use uncommon ports, and have different tests use different ports, or use random numbers, but that's all somewhat risky. I don't really want CI builds to fail because tests running in parallel ended up using the same port.

I read about the ability in CXF (not JAX-RS) to use "local transport" (https://cwiki.apache.org/confluence/display/CXF20DOC/JAXRS+Testing). It appears that might resolve my problem. I need to verify this, but it's possible that two tests running in parallel both using local transport will not conflict.

However, I can't even get this to work yet, because our client code is using the "standard" JAX-RS client class, not the CXF one. They appear to be different and incompatible.

At the point where I create the client, I tried to do this (just to see if it can work):

WebClient.getConfig(client).getRequestContext().put(LocalConduit.DIRECT_DISPATCH, Boolean.TRUE);

Unfortunately, this fails with "Not a valid Client" in "org.apache.cxf.jaxrs.client.WebClient.getConfig(Object)" because it needs to be an instance of "org.apache.cxf.jaxrs.client.Client", not javax.ws.rs.client.Client.

Is there any easy (or even possible) path forward here?


Solution

  • You can use ClientRequestFilters to unit test JAX-RS clients. Basically register a custom ClientRequestFilter to your Client object (or ClientBuilder) that mocks your response using the abortWith(Response) method on the ClientRequestContext object that is passed in to the filter method.

    Something like this should work:

    public MyMockRequestFilter implements ClientRequestFilter {
      @Override
      public void filter(ClientRequestContext requestContext) {
        MyEntity entity = // get the entity you want to mock as returned from the server
        requestContext.abortWith(Request.ok(entity).build());
      }
    }
    ...
    ClientBuilder builder = ClientBuilder.newBuilder().register(MyMockRequestFilter .class)
    

    Hope this helps, Andy