Dan, I totally respect your desire to push CDI as an integral part of the "native
Java EE" or rather the "Java EE 6 Web Profile Container" programming model,
but I would like to offer a slightly contrasting point of view. See my further points
inline below.
On Dec 17, 2009, at 8:23 AM, Dan Allen wrote:
I feel strongly that, as a group, we should provide a consistent
recommendation regarding the programming model of JSF by getting behind CDI. Now, I
realize there are Spring developers and supporters on this EG. So, before going any
further, I want to clarify that the point I am making relates specifically to the native
Java EE 6 technology stack. Spring has always been a strong alternative to the native Java
EE programming model and continues to be a great companion of JSF. The common rival that
we want to downplay is JSF managed beans.
First off, I agree that the ultimate goal of pointing users away from the JSF-managed bean
model is a good thing. That said, we (myself and Keith along with the rest of the Spring
team whom we represent) have our reservations about CDI. So while I agree that the
ultimate goal is a good one, I just want to be clear that I am slightly wary of this
getting turned around and becoming a public statement of, "The JSF EG thinks you
should use CDI." If some of the members of the EG want to individually make that
push, that's their right, just as it is ours to say we don't see a great benefit
to choosing CDI over Spring. What I would really like to see is us figuring out the most
possible common ground between CDI and Spring when showing examples that are alternative
to the JSF managed bean facility.
I really want to make it clear that we don't see it as an "us vs. them"
thing when talking about Spring and Java EE on the whole. Spring has always provided
first-class integration with a wide range of the individual parts of EE, and we continue
to do so with EE 6 beyond just JSF 2 as evidenced by our support of specs like JSR-330,
JPA 2, Bean Validation, javax.annotationManagedBean, etc. in the recently finalized Spring
3.0. The major difference being that we enable the use of these pieces in a completely
modular and portable way that is just as powerful in a lightweight servlet container like
Tomcat as it is in a full-blown commercial app server like WebSphere or WebLogic. The
benefits are evidenced by the fact that you can easily use many of these EE 6 pieces
*today* with Spring 3.0 even in a container like WebSphere 6.1 that is still quite widely
deployed and is only J2EE 1.4 compliant.
I'm getting off-topic, but I just want to make the point that we are not anti-EE 6.
When JSF was created, no other facility was available for defining
contextual managed beans. As of Java EE 6, there is now a platform-wide definition of a
managed bean.
I assume you mean javax.annotation.ManagedBean, right? As I mentioned, we do support this
in Spring 3.0. I believe this, as well as the other shared annotations such as @Resource,
@PersistenceContext, @Inject, etc. could be our best common ground to use when showing JSF
2 examples.
With the services of CDI, there is a way to discover, produce, scope,
inject, name and override beans. All of a sudden, the injection facility, and limited
number of services in the JSF managed bean facility looks rudimentary in comparison. And
the reality is, before CDI, most developers likely used an alternative bean container
anyway (probably Spring) to define managed beans. So the JSF managed bean facility has
been falling out of favor for a long time.
Right, but are you saying we should all tell developers to use CDI instead of Spring now
even if they are already happily using Spring? I just don't see CDI being a clearly
better alternative to Spring (in fact, I see the opposite, but I freely admit to being
biased in that regard), and I don't know that we should have an opinion either way
collectively as an EG. Again, individual opinions will vary as to which one to choose,
but as a group it seems we should generally remain agnostic, especially if our overall
goal is to get as many people as possible to be successful with JSF 2.
But there is a more serious problem with continuing to recommend the
use of the JSF managed bean facility. The injections do not take the scope of the injected
bean into consideration. That means, you cannot inject a request-scoped bean into a
session-scoped bean without causing the request-scoped bean to become a session-scoped
bean through attachment. This is a very typical occurance with having managed beans in a
web application. CDI not only keeps beans in different scopes loosely coupled, it hides
the scope at the injection point.
I'd just like to point out again for the sake of contrast that Spring 3.0 supports the
same sort of approach quite well. We of course supported this previously with our
"scoped-proxy" feature since back in Spring 2.0, but it had to be configured
per-bean and was thus only slightly less annoying than configuring JSF managed beans. JSF
was a major part of the use case for making it work "by default" with
annotation-based configuration without having to do extra work.
But I won't be able to use CDI in a Servlet Container, right?
Not true. The CDI reference implementation (Weld) provides a single extension JAR
(weld-servlet.jar) that you drop into your web application archive and you get a full CDI
environment (you just don't get EJBs, but that's to be expected).
And by proxy you also don't get declarative transaction support, correct? To me,
that's an immediate show-stopper for any non-trivial application vs. what you get with
Spring in a servlet container.
Isn't CDI just a Red Hat thing?
Of course not. We should all be behind CDI. As the spec lead, Red Hat worked very hard to
define a set of services for Java EE managed beans that would make the development of
enterprise applications simpler. That's exactly the type of effort we all put in for
the JSF 2 specification. (JSF 2 was forged by all of us collectively. CDI has the same
story). So CDI is your technology, one that you can use in Java EE 6 or even outside of
it. There is no reason to back away from it.
With all due respect, I still fail to see why we should *all* be behind CDI.
Perhaps a lot of the heated debating over dependency injection turned
you off, but that heated debate really made the whole platform better because EG members,
like us, talked and worked things out in the end.
Actually, what turns me off is that what we ended up with seems to only be partially
worked out and is still a bit of a mess, to be perfectly blunt. I'll elaborate more
on that in my discussion of the examples below.
@ManagedBean
@RequestScoped
public class BlogEditor {
@ManagedProperty("#{blogDao}") BlogDao blogDao;
// getters and setters required
}
First off, I assume these (including @ManagedBean) are all from the javax.faces.bean set
of annotations. Agreed, in this particular example, I would not recommend this approach.
What about @ViewScoped though? That's one of the more useful pieces of JSF 2 in my
opinion. I don't believe there is an out-of-the-box CDI-equivalent, right? I would
assume it's not hard to implement a custom @ViewScoped that CDI would recognize?
We want to show them:
@Named
@RequestScoped
public class BlogEditor {
@Inject BlogDao blogDao;
}
So first of all, I think it would be great if we'd ended up with something like the
above that would "just work" in both CDI and Spring. But we didn't. We do
actually support the use of @Named as a class-level annotation like this in Spring 3.0.
But I'm curious, why in CDI do you recommend using @Named vs.
javax.annotation.ManagedBean? It seems to me like @ManagedBean has more clearly defined
semantics at the class-level.
Then we're back to the problem of the scopes. We of course support various scope
annotations in Spring, and support something equivalent to your above example, but
don't specifically support the CDI scope annotations. What really has me a bit
confused is why the CDI scopes don't use @Scope from JSR-330 and instead use the
JSR-299-specific @NormalScope. The JSF scopes don't either, for that matter, but I
assume that's because 330 was finalized well after. See, this is what I mean by it
being a bit of a mess. We've got some JSF-specific scopes, we've got CDI-specific
scopes, we've got Spring-specific scopes, etc. Spring can and will ultimately support
the equivalent of all of the useful ones (including @ConversationScoped in the near
future...I really wish we could have just relied on JSF or CDI for that), but it sadly
seems like we ended up with more fragmentation rather than less.
So in the above example, we at least have @Named and @Inject as commonly supported things.
I really wish there were one common, complete and portable set of scope annotations we
could support in Spring, but there isn't.
I'm asking you to consider my request to get behind CDI.
I'm perfectly fine with a world where CDI and Spring co-exist peacefully. Despite my
own misgivings about CDI, I acknowledge that it appeals to some. The goal of moving away
from the JSF managed bean is a good one. But as the collective EG whose goal is to see as
much adoption as possible of JSF 2, and given the corporate realities of how soon most
people are going to be using an EE 6 container, I don't see how we can be asked to
promote it as *the* choice of the EG.
Cheers,
Jeremy