How are these two independent specifications specified to interact in MicroProfile?
Is the apparent lack of a MicroProfile specification or specification section governing the interaction of these two independent specifications deliberate?
"CDI provides the base for a growing number of APIs included in MicroProfile 2.0."
"JAX-RS provides both standard client and server APIs for RESTful communication by MicroProfile 2.0 applications."
"Since the MicroProfile repo is an "umbrella" project, there will be no individual API or TCK generated for this component. Only this Specification will be generated and maintained to document the contents of each release."
"The [JAX-RS 2.1] specification defines a set of optional container-managed facilities and resources that are intended to be available in a Java EE container — all such features and resources must be made available."
MicroProfile does not specify any extra behaviour difference over and above what Java EE7/8 defined for JAX-RS and CDI.
In MicroProfile 2.0, JAX-RS 2.1 and CDI 2.0 are certified against Java EE8 corresponding TCKs. The interaction between JAX-RS and CDI are defined in EE7/8 spec under the table EE 6-3.
Eclipse MicroProfile does not include any Java EE umbrella spec, so the integration of how CDI and JAX-RS works in Java EE does not apply.
At a previous Architecture meeting we discussed this: https://github.com/eclipse/microprofile/issues/49
The agreement was that it made sense for MicroProfile to define the integration and require JAX-RS Resources to be @RequestScoped, in the absence of any other scope.
However, currently MicroProfile does not have any type of umbrella specification. It's something that's needed so that we can define these types of integrations and in addition a TCK to test for it as well. It's on the list, but we haven't done it yet.
My hope is we can have something for MP 2.2 in February.
JAX-RS does mention CDI on section 10.2.3 for JAX-RS 2.0 and 11.2.3
for JAX-RS 2.1
"In a product that supports CDI, implementations MUST support the use
of CDI-style Beans as root resource classes, providers and Application
subclasses. Providers and Application subclasses MUST be singletons or
use application scope."
IMO, problem is more on the CDI side and bean discovery mode. Without
umbrella spec, some impl assume "all" as bean discovery and others
"annotated".
* From a JAX-RS perspective, subclassing Application is the only way to guarantee portability
* As Laird indicated, the JAX-RS spec recommends class scanning in Servlet environments. For that purpose, it uses annotations such as @Path (resources) and @Provider (providers). Class scanning is (loosely) enabled by not providing an Application subclass or by providing one that returns nothing.
I don’t believe MP says anything about Application subclasses being optional (does it?), so let’s assume that they are not as in vanilla JAX-RS. Then,
(1) When an Application subclass is (somehow) discovered, should it be automatically be annotated with @ApplicationScoped if not already? What if it has a different scope?
(2) Application.getClasses() can return resources and providers. In the absence of scope annotations, resources should be @RequestScoped (as proposed elsewhere) and providers should be @ApplicationScoped.
(3) Application.getSingletons() may return instances that are not CDI beans.
In MP environments, the use of this method should be (highly) discouraged in favor of @ApplicationScoped classes in (2).
So how can (2) be implemented?
RuntimeDelegate.createEndpoint(new Unmanaged<Application>().newInstance().produce().inject().postConstruct().get(), someEndpointClass);
If in a CDI extension (discovery mode all?), it will need to annotate all resources and providers as it doesn’t know which ones will be returned by Application.getClasses(). Unless the @Provider annotation is mandated (see Servlet discussion above), detecting providers will require inspection of base types.
In any case, an Application subclass should be the source of truth regardless of what CDI happens to discover during its scanning phase.
If MP wants to support JAX-RS applications relying exclusively on scanning, without an Application subclass,
On Thursday, November 8, 2018 at 7:36:29 AM UTC-8, Santiago Pericas-Geertsen wrote:* From a JAX-RS perspective, subclassing Application is the only way to guarantee portabilityYes, but as Antoine pointed out section 11.2.3 in JAX-RS 2.1 expands (and/or confuses!) these portability rules for all MicroProfile implementations (a MicroProfile implementation is by definition a "product that supports CDI").
* As Laird indicated, the JAX-RS spec recommends class scanning in Servlet environments. For that purpose, it uses annotations such as @Path (resources) and @Provider (providers). Class scanning is (loosely) enabled by not providing an Application subclass or by providing one that returns nothing.Not just Servlet. Because MicroProfile implementations fall under the category of "a product that supports CDI", it means that regardless of whether I have an Application subclass or not, CDI bean discovery must be in play, according to section 11.2.3 of the JAX-RS specification. (The JAX-RS specification itself in isolation has many issues here IMHO: should an instance returned by Application#getSingletons() trump a discovered bean of the same class? But normally Application#getClasses() trumps Application#getSingletons()….)(Playing devil's advocate, there might be some quibbling over the mysterious and ill-defined "CDI-style Beans" moniker. Does this mean an honest-to-goodness CDI bean (a source of contextual instances) (at the time the specification was written CDI was new so maybe the terminology was a little off here), or an unmanaged instance that supports injection?)I don’t believe MP says anything about Application subclasses being optional (does it?), so let’s assume that they are not as in vanilla JAX-RS. Then,For the sake of discussion, sure, but bear in mind that if in a "product that supports CDI" such as a MicroProfile implementation JAX-RS "implementations MUST support the use of CDI-style Beans as root resource classes", then an Application subclass would be optional, assuming "CDI-style Beans" means "CDI beans".
(1) When an Application subclass is (somehow) discovered, should it be automatically be annotated with @ApplicationScoped if not already? What if it has a different scope?
The only muddy area here is, IMHO, the meaning of the word "singletons" in section 11.2.3 of JAX-RS specification where it says "Providers and Application subclasses MUST be singletons or use application scope."If we replace "singletons" with "CDI unmanaged instances that are instantiated only once but that also support injection of dependencies", that suggests one thing,
and if we replace "singletons" with "classes annotated with javax.inject.Singleton" that suggests another. From the fact that "application scope" is used at the end of this sentence, which is a well-defined CDI term, I'm assuming that "singleton" is actually shorthand for, effectively, "classes annotated with javax.inject.Singleton" and the behavior that JSR-330 and CDI require of such classes.
This matters when considering your (3) below.(2) Application.getClasses() can return resources and providers. In the absence of scope annotations, resources should be @RequestScoped (as proposed elsewhere) and providers should be @ApplicationScoped.Right; the second clause should read: "and provider classes present in the return value of Application#getClasses() should be treated as if they were annotated with either javax.inject.Singleton or javax.enterprise.context.ApplicationScoped". The "either" part here means the umbrella specification should clarify this.
(3) Application.getSingletons() may return instances that are not CDI beans.Yes! And furthermore it seems to be the intent of the JAX-RS specification that such objects should be injected by CDI when CDI is in the picture. I'm not sure this part is explicitly spelled out in JAX-RS though.
In MP environments, the use of this method should be (highly) discouraged in favor of @ApplicationScoped classes in (2).Yes but! It's still possible.
So how can (2) be implemented?Brainstorming, but (flailing wildly with flaws I'm sure) hopefully you get the general idea:
- A portable extension uses CDI's Unmanaged facilities to instantiate and perform dependency injection on the Application subclass so 11.2.3 is honored
- portable extension creates a Bean whose creation method returns the unmanaged instance, perhaps with injection points removed (since injection was already performed) or other shenanigans to ensure DI doesn't happen twice (this permits Application to be injected into other CDI beans, which is required by 11.2.3)
- The portable extension calls getClasses() and getSingletons() on the resulting instance. For classes discovered this way, they are added as annotated types. For singletons discovered this way, custom beans are added representing them.
Or, maybe? assuming your JAX-RS implementation does things properly and has a properly implemented CDI integration library (see Jersey, maybe), you might get really lucky and be able to simply do something like the following when the @Initialized(ApplicationScoped.class) Object event is fired:RuntimeDelegate.createEndpoint(new Unmanaged<Application>().newInstance().produce().inject().postConstruct().get(), someEndpointClass);I don't know offhand, for example, whether Jersey-plus-its-CDI-integration-library properly implements all of the stuff we just discussed around section 11.2.3. I'm guessing it misses a few edge cases but maybe you know differently.If in a CDI extension (discovery mode all?), it will need to annotate all resources and providers as it doesn’t know which ones will be returned by Application.getClasses(). Unless the @Provider annotation is mandated (see Servlet discussion above), detecting providers will require inspection of base types.Well, or a portable extension that looks them up from META-INF/services or whatnot and adds them programmatically, or other programmatic approaches.In any case, an Application subclass should be the source of truth regardless of what CDI happens to discover during its scanning phase.This is where things get very murky. I do agree with your interpretation, but perhaps "support the use of CDI-style Beans as root resource classes, providers and Application subclasses" means something above and beyond this? It's not clear to me whether the scanning that "support" implies is to be merged into the results of Application#getClasses() and Application#getSingletons() or superseded by them.If MP wants to support JAX-RS applications relying exclusively on scanning, without an Application subclass,My personal read is that according to section 11.2.3 it must.Interestingly, all of these questions seem to be about the JAX-RS specification in isolation!
--Best,Laird
You received this message because you are subscribed to the Google Groups "Eclipse MicroProfile" group.
To unsubscribe from this group and stop receiving emails from it, send an email to microprofile...@googlegroups.com.
To post to this group, send email to microp...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/microprofile/152df2ec-96be-483c-ad2b-b769b0ab8a0c%40googlegroups.com.
On Nov 15, 2018, at 10:01 AM, Raymond Auge <raymon...@liferay.com> wrote:I sincerely think that care should be taken to clarify the behaviours so there are no doubts even if it means accepting a specific interpretation and making it the rule.
* As Laird indicated, the JAX-RS spec recommends class scanning in Servlet environments. For that purpose, it uses annotations such as @Path (resources) and @Provider (providers). Class scanning is (loosely) enabled by not providing an Application subclass or by providing one that returns nothing.Not just Servlet. Because MicroProfile implementations fall under the category of "a product that supports CDI", it means that regardless of whether I have an Application subclass or not, CDI bean discovery must be in play, according to section 11.2.3 of the JAX-RS specification. (The JAX-RS specification itself in isolation has many issues here IMHO: should an instance returned by Application#getSingletons() trump a discovered bean of the same class? But normally Application#getClasses() trumps Application#getSingletons()….)(Playing devil's advocate, there might be some quibbling over the mysterious and ill-defined "CDI-style Beans" moniker. Does this mean an honest-to-goodness CDI bean (a source of contextual instances) (at the time the specification was written CDI was new so maybe the terminology was a little off here), or an unmanaged instance that supports injection?)I don’t believe MP says anything about Application subclasses being optional (does it?), so let’s assume that they are not as in vanilla JAX-RS. Then,For the sake of discussion, sure, but bear in mind that if in a "product that supports CDI" such as a MicroProfile implementation JAX-RS "implementations MUST support the use of CDI-style Beans as root resource classes", then an Application subclass would be optional, assuming "CDI-style Beans" means "CDI beans".I fully agree. Application is implied optional in those terms.
One doubt is; what would it mean to then have both root level resources AND an application.. or more than one application?- 0 application + n resources implies a "default" application?
- 1 application overrides/replaces the "default” application
- n applications is an error?
(1) When an Application subclass is (somehow) discovered, should it be automatically be annotated with @ApplicationScoped if not already? What if it has a different scope?I do not agree that any magical extra work should be done here. I think that because we have the environment already defined as CDI, applications require a scope and the scope should be @ApplicationScoped. This is clear, precise, leaves no room for interpretation. If an implementation of microprofile wanted to do something such as warn about an unannotated Application class, then by all means. If the implementation just wants to load it, fine, but that should be non-portable (or if you wish, "value added”).
This matters when considering your (3) below.(2) Application.getClasses() can return resources and providers. In the absence of scope annotations, resources should be @RequestScoped (as proposed elsewhere) and providers should be @ApplicationScoped.Right; the second clause should read: "and provider classes present in the return value of Application#getClasses() should be treated as if they were annotated with either javax.inject.Singleton or javax.enterprise.context.ApplicationScoped". The "either" part here means the umbrella specification should clarify this.Completely agree this need to be clarified.(3) Application.getSingletons() may return instances that are not CDI beans.Yes! And furthermore it seems to be the intent of the JAX-RS specification that such objects should be injected by CDI when CDI is in the picture. I'm not sure this part is explicitly spelled out in JAX-RS though.Also agreed.In MP environments, the use of this method should be (highly) discouraged in favor of @ApplicationScoped classes in (2).Yes but! It's still possible.One possibility is to raise this as a cdi definition error.
To sum up a recommendation I feel would do that:- applications require @ApplicationScoped- root level resources and providers require a scope; resources=@RequestScoped, providers=@ApplicationScoped- 0 applications + n resources is interpreted as "default"; new Application() {}- 1 application overrides "default"- n applications raises CDI definition error??- getClasses()-- a class found to be existing annotated type (already discovered by CDI) must raise a definition error, otherwise it is added as an annotated type-- resources=@RequestScoped
-- providers=@ApplicationScoped
- getSingletons()-- are "CDI unmanaged instances that are instantiated only once but that also support injection of dependencies"
-- I don't see why these should be added as beans because they may have been injected from beans…
One place that I've found ill definition between JAX-RS & CDI is with subresource locators. I have to request subresource instances from CDI and then resourceCtx.initResource() those instances with JAX-RS in order to get all CDI annotations & JAX-RS annotations working together. It's a one-liner everywhere I want to return subresources (which I do a lot of the way I create MP Rest Client / WebResourceFactory client APIs), but I feel like it should be automatic instead of manual.