users@jersey.java.net

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

From: cowwoc <cowwoc_at_bbs.darktech.org>
Date: Tue, 29 Oct 2013 14:40:05 -0400

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