eclipse-ee4j / jersey

Eclipse Jersey Project - Read our Wiki:
https://github.com/eclipse-ee4j/jersey/wiki
Other
690 stars 351 forks source link

Enable Jersey/Guice integration via HK2 Guice Bridge #2222

Open jerseyrobot opened 11 years ago

jerseyrobot commented 11 years ago

The HK2 Guice Bridge is available, but there may be more work needed in Jersey in order to enable it.

Affected Versions

[2.0]

jerseyrobot commented 6 years ago
jerseyrobot commented 11 years ago

@glassfishrobot Commented Reported by @jwells131313

jerseyrobot commented 11 years ago

@glassfishrobot Commented cowwoc said: This issue is related to https://java.net/jira/browse/HK2-39 and https://java.net/jira/browse/HK2-121

To reiterate, here is what we had in Jersey 1.0:

Container
\-> GuiceFilter (Guice: initialize request scope)
  \-> GuiceServletContextListener (Guice: initialize the Guice injector)
    \-> JerseyServletModule (Jersey: bind Jersey types to Guice module)
      \-> GuiceContainer (Jersey: redirect incoming requests to resource classes)

In other words, we created a Guice injector first and initialized Jersey second.

In Jersey 2.0 we have a circular reference. We need to initialize Injector before ServletContainer (otherwise @RequestScoped isn't initialized), but we need to initialize ServletContainer before Injector (otherwise we can't get a reference to ServiceLocator).

jerseyrobot commented 11 years ago

@glassfishrobot Commented vokiel said: I've been reading the various issues on Guice with Jersey 2.0 & HK2 and I have to say I'm a bit confused as to what the bridge allows currently and what it doesn't allow. I'm trying to get Guice-Persist to work with Jersey, but yes it just won't inject what the module defines (factories and such).

If I just use the bridge as is and install a JpaPersistModule into the HK2 bridge, shouldn't it be able to inject an EntityManager from the Guice definition in my resources afterward? All that without having to use GuiceFilter & the Servlet plumbing of Guice? Isn't this just adaptation?

What sm I missing or what's the status?

jerseyrobot commented 11 years ago

@glassfishrobot Commented cowwoc said: Jersey 2.0 doesn't support Guice, period.

Development is being held up on the Jersey end of things, not HK2.

Anyone wishing to help should take a look at how Spring integration was added in #2229 and try to replicate the technique for Guice.

jerseyrobot commented 10 years ago

@glassfishrobot Commented cowwoc said: I finally figured out how to wedge Guice support into Jersey 2 (mostly through trial and error). Can someone from the Jersey team please review and publish the following documentation as part of the official user guide?


1. Add GuiceFilter and ServletContainer to web.xml:

<filter>
        <filter-name>GuiceFilter</filter-name>
        <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>GuiceFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>JerseyApplication</filter-name>
        <filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>com.mycompany.MyApplication</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>JerseyApplication</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

2. Note that GuiceFilter must show up before ServletContainer. 3. Define an application as follows:

public class MyApplication extends ResourceConfig {

    @Inject
    public MyApplication(ServiceLocator serviceLocator) {
        // Register root resources, then...

        // Instantiate Guice Bridge
        GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);

        GuiceIntoHK2Bridge guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
        Injector injector = Guice.createInjector(new MyModule());
        guiceBridge.bridgeGuiceInjector(injector);
    }
}

4. Define a Guice module as follows:

public class MyModule extends AbstractModule {

    @Override
    protected void configure() {
        // Configure Guice as you normally would, then... 
        install(new ServletModule());
    }
}

5. ServletModule defines the "request" scope. GuiceFilter creates/destroys the scope on each incoming request.


Let's begin by amending the documentation, and then we can follow up by adding a sample application and unit tests that mirror the Spring module.

jerseyrobot commented 10 years ago

@glassfishrobot Commented @jwells131313 said: That's a gr8 solution. I'd still like to see a more integrated solution though...

jerseyrobot commented 10 years ago

@glassfishrobot Commented reinert said: It is not possible to just substitute H2K to Guice?

I don't like the idea of two DI containers working together. I would rather prefer just using Guice for managing every DI issue in my application.

jerseyrobot commented 10 years ago

@glassfishrobot Commented cowwoc said: @jwells, what did you have in mind? @reinert, I don't think Jersey gives us an option. I believe it forces the use of HK2.

jerseyrobot commented 10 years ago

@glassfishrobot Commented cowwoc said: Bad news. The above solution won't work. It only initializes one direction of HK2's bi-directional bridge.

I am beyond frustrated with this, having spent days trying to get it to work.

@jwells, please contact me by email (cowwoc at bbs.darktech.org). I'd like to resolve this issue once and for all over chat. Playing tag over the issue tracker is not working out.

jerseyrobot commented 10 years ago

@glassfishrobot Commented cowwoc said: I found a way to beat the circular dependency for Injector. You can create the main Injector before the Application. Once you're inside Application, you create a child injector and pass in Hk2Module(serviceLocator) as follows: injector.createChildInjector(new Hk2Module(serviceLocator))

Now both Guice and HK2 are happy. This moves us in the right direction but it's still not a working solution:

1. There is no clean way to pass the root Injector into the Application class due to http://stackoverflow.com/q/19596592/14731. Currently I'm passing the variable using a public singleton, which is ugly. 2. There are problems mixing Guice and HK2 types. See HK2-139.

I will continue working to resolve this.

jerseyrobot commented 10 years ago

@glassfishrobot Commented jontro said: @cowwoc

Would you mind trying out the solution outlined in https://java.net/jira/browse/HK2-121 ?

jerseyrobot commented 10 years ago

@glassfishrobot Commented cowwoc said: @jontro

I replied to your solution, in HK2-121. Let's keep the discussion there to reduce noise for everyone else watching this issue.

jerseyrobot commented 10 years ago

@glassfishrobot Commented cowwoc said: Proposal:

  1. Isolate all HK2-specific bindings into reusable "factories".
  2. Extract all HK2-specific code into its own module. jersey-core would only use JSR 330 to @Inject but it wouldn't do the actual binding or construction of the ServiceLocator. Instead of Application creating ServiceLocator, ServiceLocator would create the Application (more on this below).
  3. The user add the HK2, Guice or Spring module to the classpath at built-time.
  4. At startup these implementation would bind against the factories from step 1, inject the Application class, answer all subsequent @Inject requests.

The beauty of this is that Jersey would depend on JSR 330 instead of HK2 directly, and wouldn't need to manage any DI frameworks (as it did in 1.0).

Jersey committers: what do you think of this proposal?

jerseyrobot commented 10 years ago

@glassfishrobot Commented cowwoc said: Can someone please change the title of this issue from "Enable Jersey/Guice integration via HK2 Guice Bridge" to "Guice support"? I don't think we'll be able to use the HK2 bridge for that.

jerseyrobot commented 10 years ago

@glassfishrobot Commented jontro said: I would just like to add that I support @cowwoc completely. After a couple of months now since switching to jersey 2.x from the 1.x version it really feels cumbersome developing with both hk2 and guice.

Is it possible to reach a consensus on how this should move forward?

jerseyrobot commented 10 years ago

@glassfishrobot Commented bowenwr said: I'm also voicing my support for moving forward on this issue.

jerseyrobot commented 10 years ago

@glassfishrobot Commented djxak said: I think Jersey need to be DI framework agnostic.

For example I have a maven module in my application with JPA persistence classes. Entities and DAOs. DAOs implemented with Guice. They receive request-scoped EntityManager by Guice DI, have methods with @Transactional annotation (by guice-persist) etc.

Now I want to use this DAOs in my new REST module. For this I need to inject them to appropriate Jersey Resources. I don't want to rewrite all my DAOs with HK2. They already used in another UI module of my application. And HK2 doesn't provide functionality similar to guice-persist (request scoped UnitOfWork, @Transactional interceptor).

jerseyrobot commented 10 years ago

@glassfishrobot Commented jitterted said: I've voted for this, but I also wanted to comment that because of this issue alone, I may be forced to switch to another JAX-RS provider (namely RESTEasy, which works quite well with Guice, thank you very much). Obviously I'd rather not do that, but HK2 is really getting in my way.

jerseyrobot commented 10 years ago

@glassfishrobot Commented aldenquimby said: @jitterted i was able to get things working by following this HK2 comment. It's not great, but should work until the Jersey guys finally get around to tackling this issue

jerseyrobot commented 10 years ago

@glassfishrobot Commented sugis said: I too, after many happy years of Jersey use, had to switch to RESTeasy over this issue

jerseyrobot commented 10 years ago

@glassfishrobot Commented natros said: I start to feel you pain over this issue. I have a large code base that dependes on jersey 1.x and can't simple switch to Resteasy.

jerseyrobot commented 9 years ago

@glassfishrobot Commented jkidd said: @cowwoc +1 As long as the support for Guice in Jersey 2.x is so cumbersome, I myself will not be willing to switch to Jersey 2. Using/handling one DI framework is enough, using two DI frameworks is pointing towards spaghetti.

jerseyrobot commented 9 years ago

@glassfishrobot Commented vshankri said: We wanted to use "asycn servlet" so want to upgrade to Jersey 2.x but this is such a huge draw back that GUICE is not supported. Currently we use GUICE and JERSEY 1.x; so it has been really tough so far. I hope Jersey starts supporting GUICE

jerseyrobot commented 9 years ago

@glassfishrobot Commented gmussi said: Hello,

Why is Jersey so dependent of HK2? Shouldnt DI and Rest be two different things? Do I miss something here? I use jersey 1.x and Guice heavily accross my applications, and would like to switch to 2.x, but like this, it is impossible at the moment.

My vote is for an official and well-maintained Guice support, as in the previous version

jerseyrobot commented 8 years ago

@glassfishrobot Commented superbull said: Hello, Is there any one in the jersey team care about this issue? It seems it is the most voted issue.

jerseyrobot commented 8 years ago

@glassfishrobot Commented @mpotociar said: Guice support is not the priority for the core Jersey team at the moment.

I can see two options how to get this feature in: 1. Get Guice owners to contribute a support module 2. Community contribution. Jersey is an open-source project and since the issue has 52 votes, chances are that there is someone out there in the community who cares enough about this feature to implement it and contribute it back to the project as a Jersey extension pull request.

jerseyrobot commented 8 years ago

@glassfishrobot Commented cowwoc said: Marek,

This issue cannot be solved without design-level changes in Jersey. Even if someone from the community were to contribute such a pull request, you wouldn't accept it (you implied as much in past mailing list discussion). There is no magical way to provide a Guice implementation that is completely abstracted away by HK2 without Jersey needing to be aware of it (the HK2 and Guice designs do not match and it causes the problems mentioned above). I already tried and gave up for this reason.

jerseyrobot commented 8 years ago

@glassfishrobot Commented sugis said: As a long-time voter on this issue, we also tried to contribute a fix to this issue. We used Jersey 1 + Guice with great success, but wanted JAX-RS 2.0. We ran into the same issues cowwoc mentioned (complex implementation, unclear path to contributing such a complex change upstream) and eventually decided that migrating to RESTEasy was a simpler task than fixing Jersey, and that is what we ended up doing. We were sad to leave as Jersey had served us well, but were really forced to because of this issue.

jerseyrobot commented 8 years ago

@glassfishrobot Commented aythus said: I remember that excitement. How much did we expect Jersey 2. We were so excited. but there was this nasty surprise when we tried to migrate over.

I can argue, that with HK2 it is not Jersey anymore. This is a different product, and it is altogether misleading to call it Jersey 2. It would better be called HKersey.

Marek, you need to admit to us and to yourself Jersey is dead, so that we can move one and you can continue developing HKersey.

It is easier to migrate from Jersey to RestEasy than to HKersey.

I am not being sarcastic, but your two points above are offensive to all the people on this thread.

Lot's of people tried to find a way to integrate Guice with HKersey, and all failed due to tight coupling of HK2. So rather than admitting, that the way HK2 was built into Jersey was shambles you are coming with inadequate excuses.

I don't even mention you suggesting Guice owners to contribute. Come on... Really, so it's Guice is guilty now. BTw, Is there any other DI framework HKersey can work with? Maybe Dagger or Spring?

jerseyrobot commented 8 years ago

@glassfishrobot Commented @jwells131313 said: I guess I'm not fully understanding what exactly does not work. Many people have used the guice/jersey bridge to interoperate as much as guice will allow. One good example is here:

http://stackoverflow.com/questions/32449706/guice-jersey-integration-injects-null-objects/32458999#32458999

Perhaps this is just a documentation issue? If there are specific features that do not work they should probably be broken out into separate bugs.

AlasdairYoung commented 6 years ago

BTw, Is there any other DI framework HKersey can work with? Maybe Dagger or Spring?

I found this thread because I have an application that uses Dagger and added Jersey 2 to it. Everything worked well until I hit a class that needs to use the @Injects annotation - then everything broke and there simply isn't a good solution. I wish I could tell Jersey 2 to use Dagger as the DI tool of choice instead of HK2...

leonardehrenfried commented 12 months ago

@AlasdairYoung Five years have passed and I'm also looking for a way to integrate Dagger with Jersey. Has the situation improved in the meantime. Or do you know of a JAX-RS server that works well with Dagger?

jansupol commented 12 months ago

The HK2 - Guice bridge should back Guice in Jersey, but I have not seen anyone trying it, yet.