?

Log in

Apache CXF, JAX-RS, and injecting dependencies into your resources without Spring - Nick [entries|archive|friends|userinfo]
Nick

[ website | gagravarr.org ]
[ userinfo | livejournal userinfo ]
[ archive | journal archive ]

Apache CXF, JAX-RS, and injecting dependencies into your resources without Spring [Apr. 11th, 2014|06:38 pm]
Nick
I find myself (for Apache Tika) wanting to do some work on an Apache CXF powered, RAX-RS RESTful API. For a few reasons, we're not using Spring, and we're not using a configuration XML file. It's all defined and run in code.

For this, we now need to pass in some dependencies to our Resource classes. Ask around, and everyone says "that's easy with Spring", but in this case we're not using Spring... After quite a bit of reading around, I've found the answer. What you need to do is use a SingletonResourceProvider to control what object gets returned when CXF wants your resource.

Using the code below, you can run a simple server, and then fetch http://localhost:8765/test from your web browser / curl etc. Because of the singleton, you get "I am a singleton!", and not "I was re-created, not a singleton" which you'd get if CXF created a new instance each time.

So, if you find yourself needing to inject some dependencies into your CXF resource classes, and you're not in spring, you can use this pattern to create the instance with the dependencies passed in, then have those used.

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.util.ArrayList;
import java.util.List;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.apache.cxf.binding.BindingFactoryManager;
import org.apache.cxf.jaxrs.JAXRSBindingFactory;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.lifecycle.ResourceProvider;
import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;

public class TestCLI {
  public static final int DEFAULT_PORT = 9998;
  public static final String DEFAULT_HOST = "localhost";
  
  @Path("/test")
  public static class TestResource {
      private String msg;
      public TestResource(String msg) {
          this.msg = msg;
      }
      public TestResource() {
          this("I was re-created, not a singleton");
      }
      @GET
      @Produces(MediaType.TEXT_PLAIN)
      public Response getStr() {
          return Response.ok(msg, MediaType.TEXT_PLAIN_TYPE).build();
      }
  }
  
  public static void main(String[] args) throws Exception {
      JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
      sf.setResourceClasses(TestResource.class);

      List rProviders = new ArrayList();
      rProviders.add(new SingletonResourceProvider(new TestResource("I am a singleton!")));
      sf.setResourceProviders(rProviders);
      
      sf.setAddress("http://localhost:8765/");
      BindingFactoryManager manager = sf.getBus().getExtension(BindingFactoryManager.class);
      JAXRSBindingFactory factory = new JAXRSBindingFactory();
      factory.setBus(sf.getBus());
      manager.registerBindingFactory(JAXRSBindingFactory.JAXRS_BINDING_ID, factory);
      sf.create();
  }
}


When run, we see what we hoped for!

$ wget -q -O - http://localhost:8765/test
I am a singleton!
$
linkReply