Spring-framework: Implement CDI 2.0 in Spring To Make Integration With New Jakarata EE Projects Easy

Created on 12 Jan 2019  路  7Comments  路  Source: spring-projects/spring-framework

Now Java EE is rebranded as Jakarta EE i.e is More Open Source. Its going to add many new projects
fast which will be cloud native and will be build on top of CDI. First One In the Bucket is JNoSQL.
http://www.jnosql.org/
We want the integration of all these new Projects with Spring. So now its required for Spring to implement CDI 2.0 and make Spring as one of the Vendor implementing CDI 2.0 so all these new projects comming under Jakrata EE can be easily integrated with Spring. This will enhance the Scope of Spring, Many part of CDI already work with Spring like @Inject @Naming, so will require some more work. This will also end the long controversy happened between SpringSource, Google(Guice) and Oracle because of CDI specification.

Most helpful comment

This is a complex topic; I'll provide a comprehensive summary of our position here.

CDI defines a complete framework from top to bottom, from API to SPI, with complete rules for user-level defaults and even for SPI behavior. It wasn't designed to be implemented by existing frameworks, and it shows since there's only Weld and OpenWebBeans actually implementing it as dedicated CDI providers. Independently minded frameworks - established ones such as Spring and Guice as well as recent candidates such as Dagger - can only really support the JSR-330 subset with component model elements which are easy to integrate into existing frameworks, next to custom component conventions.

For Spring specifically, there are long-established conventions and APIs/SPIs which we need to retain for the Spring programming model: for backwards compatibility but also for newly started Spring (Boot) applications for which those conventions are ideal. CDI differs in many respects there: its scoping rules with a 'dependent' default, full-class proxies generated for every single bean etc. From a modern-day perspective, CDI is also way too annotation-specific at all levels, even in its SPIs, whereas Spring's annotation support is a user component model on top of an entirely programmatic core container with entirely programmatic SPIs. In recent Spring versions, we're exploring this particular strength more and more with our functional bean registration and retrieval APIs and not least of it all our Kotlin support.

Jakarta EE hosted at the Eclipse Foundation doesn't change any of these factors. It is still primarily an umbrella for servers which happen to ship a CDI provider out of the box. If you'd explicitly like to use CDI in such an environment, e.g. to integrate other EE specifications through it, there's nothing wrong with Weld or OpenWebBeans as it comes with your server. Yet another CDI implementation coming from Spring's side doesn't really add value there, in particular if it has to break compatibility with the rest of the Spring ecosystem and cannot act as a natural bridge between both kinds of environments.

It is technically not hard to design EE specifications for independent use (outside of a server and outside of a CDI environment). Many existing efforts such as Servlet, WebSocket, JMS, JTA, JCA, JPA, Bean Validation, Concurrency Utilities are proven to be a fine match with Spring, and I expect that to continue in their Jakarta EE incarnations. If some Jakarta EE projects such as JSF or JNoSQL decide to focus on CDI only, it is their choice to limit their users to CDI environments; by having programmatic registration and lookup APIs as well, they'd be usable not only in CDI but also in Spring and any custom Java stacks.

All in all, even in 2019, we still have no intentions towards implementing CDI, for the same technical and pragmatic reasons. The Jakarta EE stakeholders may want to keep Spring's container conventions in mind for their own design choices, and we're generally happy to participate in the continued evolution of the specifications that we are already involved in, making sure that they remain a good match for Spring. And for JNoSQL specifically, if its stakeholders want it to be CDI-bound, Spring users can simply continue building on our Spring Data set of projects as a well-established choice for alternative datastore access.

All 7 comments

This is a complex topic; I'll provide a comprehensive summary of our position here.

CDI defines a complete framework from top to bottom, from API to SPI, with complete rules for user-level defaults and even for SPI behavior. It wasn't designed to be implemented by existing frameworks, and it shows since there's only Weld and OpenWebBeans actually implementing it as dedicated CDI providers. Independently minded frameworks - established ones such as Spring and Guice as well as recent candidates such as Dagger - can only really support the JSR-330 subset with component model elements which are easy to integrate into existing frameworks, next to custom component conventions.

For Spring specifically, there are long-established conventions and APIs/SPIs which we need to retain for the Spring programming model: for backwards compatibility but also for newly started Spring (Boot) applications for which those conventions are ideal. CDI differs in many respects there: its scoping rules with a 'dependent' default, full-class proxies generated for every single bean etc. From a modern-day perspective, CDI is also way too annotation-specific at all levels, even in its SPIs, whereas Spring's annotation support is a user component model on top of an entirely programmatic core container with entirely programmatic SPIs. In recent Spring versions, we're exploring this particular strength more and more with our functional bean registration and retrieval APIs and not least of it all our Kotlin support.

Jakarta EE hosted at the Eclipse Foundation doesn't change any of these factors. It is still primarily an umbrella for servers which happen to ship a CDI provider out of the box. If you'd explicitly like to use CDI in such an environment, e.g. to integrate other EE specifications through it, there's nothing wrong with Weld or OpenWebBeans as it comes with your server. Yet another CDI implementation coming from Spring's side doesn't really add value there, in particular if it has to break compatibility with the rest of the Spring ecosystem and cannot act as a natural bridge between both kinds of environments.

It is technically not hard to design EE specifications for independent use (outside of a server and outside of a CDI environment). Many existing efforts such as Servlet, WebSocket, JMS, JTA, JCA, JPA, Bean Validation, Concurrency Utilities are proven to be a fine match with Spring, and I expect that to continue in their Jakarta EE incarnations. If some Jakarta EE projects such as JSF or JNoSQL decide to focus on CDI only, it is their choice to limit their users to CDI environments; by having programmatic registration and lookup APIs as well, they'd be usable not only in CDI but also in Spring and any custom Java stacks.

All in all, even in 2019, we still have no intentions towards implementing CDI, for the same technical and pragmatic reasons. The Jakarta EE stakeholders may want to keep Spring's container conventions in mind for their own design choices, and we're generally happy to participate in the continued evolution of the specifications that we are already involved in, making sure that they remain a good match for Spring. And for JNoSQL specifically, if its stakeholders want it to be CDI-bound, Spring users can simply continue building on our Spring Data set of projects as a well-established choice for alternative datastore access.

What about Jakarta Inject? (the existing @Inject annotations, but in a new namespace)

What about Jakarta Inject? (the existing @Inject annotations, but in a new namespace)

It already supports it.

So it uses jakarta-inject 1.0 already?

See #25354

I use Spring Boot 2.3.2.RELEASE in one of my projects and jakarta.inject.Inject works.

I found this page because I was searching for why jakarta.inject.Provider doesn't work (no bean definition found). As I need it, I rollback to use javax.

So it uses jakarta-inject 1.0 already?

I was using this: compile group: 'jakarta.inject', name: 'jakarta.inject-api', version: '2.0.0'

I'm posting this to help others that might be stuck. It is possible to run Springboot + Spring + CDI in one application. I have multiple production based apps for past year doing so. The care is to understand what part is CDI vs spring vs boot. Some customization is ultimately necessary.

For my implementations, they are full WELD CDI based projects with mixture of soap, rest, and jsf. As they were multi module projects, I simply dropped in a new spring boot module and run as an executable JAR. I'm further using Spring Security as well. That module does the typical spring boot items. There is no direct spring outside that module. Most of the CDI based JARS need to be extracted to disk due to how WELD / Jandex works and more specifically how the URL magic works in spring boot to allow executable JAR files with BOOT-INF/lib. Issues to overcome are related to the bridging together. Joinfaces being a JSF solution results in most of the magic working because they were forced into the CDI corner. Deltaspike further helps. Since both Spring and CDI understand @Inject, it is important to consider overlap. If spring tries to wire anything that is CDI with @Inject, it's going to fail at startup. The driver of the app being spring boot with embedded tomcat in my case, there is overlap that will by itself prevent application startup. So what I did was write a customized Bean Provider from deltaspike that can manipulate the meta data at runtime. I then wrote a companion annotation called @PostInject. The classes in question then where problematic in the integration (soap, servets, others), I changed @Inject to @PostInject and used @PostConstruct to call the customized bean manager to cause injection at runtime which reads all the annotations and injects into the mix @Inject when it sees @PostInject. Most of Deltaspikes BeanProvider therefor is copied with with a point just before the injection occurs to add the metadata. By doing so, I've been able to get everything to run without issue or conflict.

There is overhead in the solution but it does work and there is really not that much code involved to make it work.

Verisons in use: Spring 5.2.8.RELEASE, Spring boot 2.3.3.RELEASE, Spring Security 5.3.4.RELEASE, Deltaspike 1.9.4, Joinfaces 4.3.0, Weld 3.1.5.Final, JSF 2.3.14, Jersey 2.31, HK2 2.6.1, and Java Metro 2.4.4.

Was this page helpful?
0 / 5 - 0 ratings