4

Given the following code in a Guice servlet module configureServlets():

serve("/a").with(new Decorator(new A()));
serve("/b").with(new Decorator(new B()));
...
serve("/z").with(new Decorator(new Z()));
...

What would be the best / easiest solution to properly inject all this? (i.e. injecting fields in the various decorated classes A, B, C...)

I was thinking using named providers, but I would prefer not having to define a new provider class for each A, B, C... The ideal solution would be thus generic.


ON MIXING HESSIAN WITH GUICE...

To help precise the question, the real code uses web-services with Hessian. After digging on the net there is currently no proper answer on this problem (I've seen many ugly hacks), and the solution given by Guillaume fits the bill on this precise case.

To summarize the original problem: to implement a web-service using Hessian, one must implement an HessianServlet, which is a GenericServlet; however Guice can only bind HttpServlet. The trick was thus to implement a thin wrapper HessianHttpServlet:

class HessianHttpServlet extends HttpServlet {
    public HessianHttpServlet(HessianServlet hessianServlet) {
        this.hessianServlet = hessianServlet;
    }
    @Override public void init(ServletConfig config) throws ServletException {
        hessianServlet.init(config);
    }
    @Override public void service(ServletRequest request, ServletResponse response) {                 
        hessianServlet.service(request, response);
    }
}

And calling:

serve("/a").with(new HessianHttpServlet(new WebServiceA()));

The complete solution is thus in that case to inject WebServiceX :

void configureServlet() {
    serve("/a").with(new HessianHttpServlet(inject(new WebServiceA())));
    serve("/b").with(new HessianHttpServlet(inject(new WebServiceB())));
    ...
    serve("/z").with(new HessianHttpServlet(inject(new WebServiceZ())));
}
private HessianServlet inject(HessianServlet hessianServlet) {
    requestInjection(hessianServlet);
    return hessianServlet;
}
Laurent Grégoire
  • 4,006
  • 29
  • 52
  • Forgive my ignorance, but what is this Decorator thing? Can't you just bind serve("/a").with(A.class)? Injection on A will then be automatically done. Same goes for B, C , Z. I feel like I am missing something. – Guillaume Polet Feb 13 '12 at 12:21
  • Well, the decorator is here to add a common functionality on top of all the decorated classes A,B,C... Adding directly this functionality to A, B, C would break the advantage of having this decorator. Furthermore, the decorator could be changed dynamically; here I've taken a simple example with only one decorator. – Laurent Grégoire Feb 13 '12 at 13:55

2 Answers2

3

You can use requestInjection(Object instance) on each of your decorators.

Guillaume Polet
  • 47,259
  • 4
  • 83
  • 117
  • In my case, I only need injecting decorated instances, so calling `serve("/a").with(new Decorator(injected(new A())))` would do it, with `injected()` an helper function just calling `requestInjection()` and returning the instance. But somehow I'm feeling bad writing this and I have the impression that this is misusing DI a bit. – Laurent Grégoire Feb 13 '12 at 15:17
  • I think I understand what you feel. You would like some way to say serve("/a*").with(Decorator.class).using(A.class); (syntax is not correct but it kinda express what you would want). Unfortunately my knowledge of Guice does not reach that extent. – Guillaume Polet Feb 13 '12 at 15:46
1

I created a little open source project which enables easy integration of hessian and guice. You can use annotation based configuration like this: WebService:

@HessianWebService
public class UserServiceImpl implements UserService {
    ...
}

Guice configuration:

public class WebServiceGuiceServletContextListener extends GuiceServletContextListener {
    @Override
    protected Injector getInjector() {
        return Guice.createInjector(
                /* your guice modules */
                new HessianWebServicesModule("your web service implementations package")
        );
    }
}

or the manual way using the EDSL:

public class WebServiceGuiceServletContextListener extends GuiceServletContextListener {
    @Override
    protected Injector getInjector() {
        return Guice.createInjector(
                /* your guice modules */
                new HessianWebServicesModule(){
                    @Override
                    protected void configureHessianWebServices() {
                        serveHessianWebService(UserService.class).usingUrl("/Users");
                    }
                }
        );
    }
}

More information, configuration options and complete examples are available here: https://bitbucket.org/richard_hauswald/hessian-guice/

Richard
  • 1,543
  • 1
  • 9
  • 13