users@jersey.java.net

[Jersey] Re: Why is JSR 330 not enough?

From: Joseph Mocker <jmocker_at_velti.com>
Date: Tue, 29 Oct 2013 21:31:27 +0000

Hi,

While I don't know if this is done, it appears that Autowired processing at least in Spring is handled by AutowiredAnnotationBeanPostProcessor. I'm guessing, if one so desired, they could augment or write a replacement to how this works to handle the guidelines required by section 3.1.2. Spring's constructor rules are already pretty close, but not exactly to the wording of 3.1.2

"The constructor with the greatest number of dependencies that can be satisfied by matching beans in the Spring container will be chosen. If none of the candidates can be satisfied, then a default constructor (if present) will be used."

Alas, my quick scan of the RESTEasy source, it doesn't appear there is any code to specifically deal with 3.1.2 rules.

  -joe


[Velti]<http://www.velti.com> Joseph Mocker | Senior Software Architect
t +1.415.315.4314 m +1.650.566.7033
e jmocker@velti.com @VeltiMobile<http://twitter.com/VeltiMobile>
[cid:sep11111ccae18]
The leading global technology provider of
mobile marketing and advertising solutions

<http://mwc.velti.com/meet-us>

On Oct 29, 2013, at 12:40 PM, cowwoc <cowwoc_at_bbs.darktech.org<mailto:cowwoc_at_bbs.darktech.org>> wrote:


    I just noticed that RESTEasy 3.0.4 support JAX-RS 2.0, Guice and Spring.

    Take a look at http://docs.jboss.org/resteasy/docs/3.0.4.Final/userguide/html_single/index.html#Guice1

    Section 46.1 shows them mixing @Inject with @RequestScoped. Section 46.2 shows them exposing JAX-RS types to Guice using "JaxrsModule".

    Any idea how they are able to do this? I fairly certain they ignore the rules you quoted in section 3.1.2 (choosing the constructor with the most parameters).

Gili

On 29/10/2013 2:40 PM, cowwoc wrote:
Cameron,

I would guess that for Jersey 1.0 which had a custom DI container, the intent was to integrate with any other DI, but for Jersey 2 as it defers responsibility to HK2 it would seem that it's HK2's responsibility to integrate with other DI containers.

    I understand why Jersey chose to delegate DI integration to HK2 (separation of concerns) but it turns out that was based on an incorrect assumption. It turns out that HK2 cannot share configuration/injection responsibility with 3rd-party DIs. Guice, in particular, does not support delegating injection for unknown types. This feature was requested 5 years ago but ultimately rejected due to insufficient demand and the extra complexity it would introduce: https://code.google.com/p/google-guice/issues/detail?id=49. I am trying to have it reintroduced, but I am fighting an uphill battle.

    At the same time, you bring up a good point:

Also, JAX-RS has some of it's own non-standard DI rules which wouldn't be definable without customizations to injection processing. This would also need to be defined per-container.

For example, for resource constructors (JAX-RS 3.1.2 Constructors):

"However, depending on the resource class lifecycle and concurrency, per-request information may not make sense in a constructor. If more than one public constructor is suitable then an implementation MUST use the one with the most parameters. Choosing amongst suitable constructors with the same number of parameters is implementation specific, implementations SHOULD generate a warning about such ambiguity."

This isn't defined in JSR-330 and in JSR-299 multiple constructors would throw an error at runtime.

    This is a hard requirement to meet. I am surprised that the JAX-RS spec mandates this (it seems out of scope to me). It virtually assures that no DI except HK2 would work for JAX-RS. Out of curiosity, does the Jersey-Spring plugin meet this requirement?


At what point does JAX-RS stop and the generic definition of DI containers begin?


    Jersey 1.0 did a pretty good job. We should pick up where it left off and take it to the next level. Depending on HK2 directly shifts the burden from a small number of Jersey committers to a large number of end-users. Guice/Spring weren't designed to for integration into 3rd-party DI frameworks. Their design (quite reasonably) assumes the use of one DI framework at a time. I have tried integrating Guice and HK2 for weeks now and it doesn't look like it's technically possible.

Heh, HK2 wasn't designed for integration with 3rd party DI frameworks either :)

    It gained that requirement the moment Jersey delegating DI integration to it. Guice/Spring are independent libraries that have nothing to do with JAX-RS. The close coupling of Jersey and HK2 might be nice for Jersey but it isn't reasonable to expect the same from general DI frameworks.

Are you asking more of HK2 than you expect of Guice/Spring?

    Not at all. I am expecting HK2 to be one of many implementations that may be used with Jersey. I expect only one DI implementation to be active at a time.

Isn't what you really want a (C)DI abstraction layer?

    I am not very familiar with CDI so I can't really comment. Last time I scanned through it it looked overly complex.

I'm guessing that mixing DI containers is probably a bad idea, hence the technical difficulties. I've not resolved this either.

    I agree. Which is why I'm saying we should only be using one DI implementation at a time, but allow users to decide which implementation they chose to use.


The problem is that JSR-330 doesn't define enough. It is a set of reusable annotations, with no specification of how any system using them should be implemented:

http://atinject.googlecode.com/svn/trunk/javadoc/javax/inject/package-summary.html

"This package provides dependency injection annotations that enable portable classes, but it leaves external dependency configuration up to the injector implementation."

"Injector implementations can take many forms. An injector could configure itself using XML, annotations, a DSL (domain-specific language), or even plain Java code. An injector could rely on reflection or code generation. An injector that uses compile-time code generation may not even have its own run time representation. Other injectors may not be able to generate code at all, neither at compile nor run time. A "container", for some definition, can be an injector, but this package specification aims to minimize restrictions on injector implementations."

I can see that it's feasible to do multiple Jersey modules with one for each DI container, much the same as a lot of other extension modules work.

Either that or a new DI abstraction which had the features Jersey requires without the bloat of CDI. I would guess that a new abstraction which fulfills an implementation's requirements is harder to achieve and those interested in more DI abstraction have probably already invested in the CDI specification.

    I can't speak for others, but I'm simply interested in getting the same functionality I had in Jersey 1.0. I want to be able to use either: only HK2, only Guice or only Spring at a time. I also need to be able to do this outside a JavaEE container. I am running Jetty inside a simple JavaSE application and I really appreciate how light this solution feels.

    Another difference I wanted to point out:

  * I expect Jersey to speak to the DI implementation through the abstraction layer, but...
  * Users should speak to the DI implementation directly.

    The point I want to make is that users don't have to learn yet another DI framework. The only thing that's new is having to register a DI framework once at startup. Past that point they should be able to use the native HK2, Guice and Spring constructs they are used to.

Gili






logo1111129d340
(image/gif attachment: logo1111129d340)

sep11111ccae18
(image/gif attachment: sep11111ccae18)