Thursday, November 6, 2008

Google Guice and JAX-WS RI revisited

I've been coding a bit more with the guice-extension for jax-ws, and the result is actually quite nice, see below for how your web service endpoint would look when it is handled by guice:
@GuiceManaged(module = WebServiceModule.class)
@WebService
public class AddNumbersImpl implements AddNumbers {

    private Calculator calculator;

    @Inject
    public void setCalculator(Calculator calc)
    {
        this.calculator=calc;
    }
    @WebMethod
    public int addNumbers(int num1, int num2)
    {
        return this.calculator.calc(num1,num2);
    }
}
And WebServiceModule looks like this:
public class WebServiceModule extends AbstractModule {
    protected void configure() {
        bind(Calculator.class).to(CalculatorImpl.class).in(Singleton.class);
    }
}

It can handle endpoints in any scope you want, if you want just one instance of the endpoint, you either annotate the class with @Singleton or bind it in Singleton scope in your module.

Head over to the jax-ws commons project on dev.java.net to get the code, binaries and some information on how to use it.


Tuesday, November 4, 2008

Google Guice and jax-ws

To integrate google guice with jax-ws, you need to use the InstanceResolver extension point. this way your endpoints will look like this;

@GuiceManaged
@WebService(targetNamespace = "http://marcus", name="AddNumbers")
public class AddNumbersImpl {
  @Inject
  public void setCalculator(Calculator calc)
  {
      this.calculator=calc;
  }
...

To achieve this you need to create the annotation GuiceManaged;
@Retention(RUNTIME)
@Target(TYPE)
@Documented
@WebServiceFeatureAnnotation(id=GuiceManagedFeature.ID, bean=GuiceManagedFeature.class)
@InstanceResolverAnnotation(GuiceManagedInstanceResolver.class)
public @interface GuiceManaged {
}

Then you need to implement the GuiceManagedFeature:
public class GuiceManagedFeature extends WebServiceFeature {
    public static final String ID="some_nice_id";

    @FeatureConstructor
    public GuiceManagedFeature()
    {
        this.enabled=true;
    }
    
    public String getID() {
        return ID;
    }
}
And finally the actual InstanceResolver:
public class GuiceManagedInstanceResolver extends AbstractMultiInstanceResolver {
    private T instance=null;
    public GuiceManagedInstanceResolver(@NotNull Class clazz)
    {
        super(clazz);
    }
    public T resolve(@NotNull Packet packet) {
        if(instance==null)
        {
            instance=create();
            Injector injector= Guice.createInjector(new WebServiceModule());
            injector.injectMembers(instance);
        }
        return instance;
    }
}

That should do it, I'll update this post soon with a URL to the actual code (with documentation on how to use it. My plan is to make it more extensible (i.e. no hard dependency on the WebServiceModule) and possible to use in a non-singleton scope soon.