<< When tool strategy gets on your nerves | Home | A really simple but powerful rule engine >>

JSR-299 & @Produces

I've been reading JSR-299 and I have a few thoughts.

First, a quote from chapter 1:

"The use of these services significantly simplifies the task of creating Java EE applications by integrating the Java EE web tier with Java EE enterprise services. In particular, EJB components may be used as JSF managed beans, thus integrating the programming models of EJB and JSF."

The second sentence made my ears prick up. Do I really want EJBs to be the backing beans of web pages? To me that sounds like one is mixing up responsibilities in MVC. Sure, there are people out there who say that an MVC Controller should be skinny and the model should be fat (youtube ad). Perhaps I'm old school, but I prefer my JSF page to have a backing bean which is my view model and deals with presentation specific logic, and when it needs transaction and security support, it can call through to an EJB which deals with more businessy things.

The JSR then goes on to introduce the @Produces annotation. I don't like that annotation and the rest of this blog posting is about why.

When I need an object, like a service or a resource, I can get the container to inject it for me. Typically, I use the @Inject, @EJB, @Resource or @PersistenceContext annotations. In the object which has such things injected, I can write code which uses those objects. I let the container compose my object using those pieces and other beans. There are many advantages, like having code which is easily testable because I can compose the object out of mocks if required, or like being able to configure its composition rather than hard coding it. And we are all used to composing objects like this, from the earliest days of Spring, if not before.

Now, with @Produces, we have a new way to declare where things come from. Take the example in the JSR, where a Login bean is shown (chapter 1). The Login bean "produces" the current user (page 4). Well, let's start with some code:

    @Produces @LoggedIn User getCurrentUser()

If I read that code out loud, I say something with a similar meaning to: "The bean called Login produces the currently logged in user".

Well, that doesn't make too much sense to me, because coming at the design from a pure OO point of view, starting with use-cases, there is no Login bean mentioned in the use case, and even if there were, it does not "produce" the user! The user exists before they login to the software. They are simply authenticated and perhaps authorised after login. The login component of the software (which could be represented by the Login bean) can provide the details of the currently logged in user. The syntax used in that code above has a poor semantic meaning, in my view.

So if this is the modern trendy way of passing information around in a JSF app, I have to ask myself whether we were not able to do such things in the past? Or was it really hard to program before we had the @Produces annotation? Let's look at one solution; some code in a bean which needs to know the logged in user.

    @Inject Login loginBean;

To use that, the Login bean would need to be declared as being @SessionScoped, and guess what - it is already marked so in the JSR example.

To access the current user, I would simply write code like this:

    loginBean.getCurrentUser().getName() blah blah

Simple huh?

If you don't like the idea of injecting the Login bean, then why not simply create a session scoped bean called "CurrentUser" and during login, set the authenticated user attributes into that session scoped bean? Why go to the lengths of adding yet another way of injecting objects, namely the @Produces annotation? Because there is a different way of doing injection, the whole mechanism has become more complex. I believe it is these types of complexity which cause newbies to give up Java EE before fully understanding it, and which cause existing Java advocates to give up and move to Grails, etc.

To go with the @Produces annotation, we are given qualifiers. Qualifiers are effectively type safe names used for filtering, and as such, potentially better than String constants in an interface somewhere used in conjunction with an @Named annotation. Here is why I don't think Qualifiers should be used as the norm, but rather as the exception. The class of object being injected should have a suitable name to tell the reader what is going on. Consider this code, which injects the current user which the login bean produces:

    @Inject @LoggedIn User currentUser;

There is unnecessary triplication going on in that line. "LoggedIn", "User" and "currentUser". In the ideal world, I don't want three names here, I want one. Java forces me to declare the type, which is actually not really that necessary, because the compiler could, using conventions, infer the type from the name. But let's not go there, and instead accept that we have to declare a type. Why on earth then, do I want to additionally declare a qualifier? I don't, it's a waste of finger energy. Only when there is ambiguity would I be required to use a qualifier. But if I have a session scoped model, which contained the user, I could spare myself the energy of using a qualifier. I would simply inject the model bean and pull the current user out of it. That is what I have been doing for years without a problem. My Mum always told me not to fix something which isn't broken.

At this JBoss getting started guide, they give an example of producing a random number, with code like this (in the producer):

    @Produces @Random int next() {
        return getRandom().nextInt(maxNumber - 1) + 1;
    }

and this code in the consumer:

    @Inject @Random int someRandomNumber;

Sure, it's a toy example. But what is wrong with injecting the Generator bean (which contains that producer method), and calling the method on it which generates the random number? I could even work with @Alternative if I wanted to decide on the actual implementation at deployment time.

For me, injecting the bean, rather than the value is very important for readability. It gives the reader (maintainer) contextual information about where that value is coming from. In my mind, the following code is much better. It is quicker to write, because I don't need to create a qualifier annotation.

    @Inject Generator generator;

And then in that class, some code to use the generator:

    generator.nextRandomInt();

Section 1.3.3 of the JSR gives an example of setting up the entity managers for injection into beans:

    @Produces @PersistenceContext(unitName="UserData") @Users
    EntityManager userDatabaseEntityManager;

And then here, the code which uses that entity manager:

    @Inject @Users EntityManager userDatabaseEntityManager;

Oh, and don't forget the code for the @Users annotation... I end up with two extra files (the annotation and the producer). Is all that code really better than the following, which is simply put into a bean requiring the entity manager:

    @PersistenceContext(unitName=Units.UserData)
    EntityManager userDatabaseEntityManager;

I'm just not convinced that the "modern" & trendy, yet complex JSR-299 way of doing it is better.

Section 3.3 then goes on to tell us a bit more about why producers exist and in which circumstances we might want to use them:

- the objects to be injected are not required to be instances of beans

Since almost every class is now a bean, I am hard pushed to think of a case where I could not create a bean if I wanted something injected.

- the concrete type of the objects to be injected may vary at runtime

This is exactly what @Alternative and @Specialize annotations are for, and I do not need to use a producer to vary the concrete runtime implementation.

- the objects require some custom initialization that is not performed by the bean constructor

Adding the @Inject annotation to a constructor tells the container which constructor to call when special construction is required. How can a producer produce something which a bean couldn't?

Section 3.4.2 then talks about declaring producer fields. The example they give shows the field having default (package) visibility, yet as far as I can tell, any bean in the deployment bundle, even one outside the producers package, can use the "product". This is a little like indecently assaulting Java.

So to summarise, I guess I just want to put out a plea to future spec authors. If you can't work out a way to do things simply, especially if we already have that mechanism, please don't go and make things more complicated than they need to be. I don't want to learn 92 pages of JSR just to be good at using beans, when I already have to learn thousands of other pages of JSR just to get working with Java EE.

© 2011, Ant Kutschera

Tags : ,
Social Bookmarks :  Add this post to Slashdot    Add this post to Digg    Add this post to Reddit    Add this post to Delicious    Add this post to Stumble it    Add this post to Google    Add this post to Technorati    Add this post to Bloglines    Add this post to Facebook    Add this post to Furl    Add this post to Windows Live    Add this post to Yahoo!


Re: JSR-299 & @Produces

To start with, I really hope that all your @Inject, @PersistenceContext, @Resource and others are _not_ decorating member fields, as you do it in all your examples, because such code is just not testable. You should either do it using constructor or method injection - only them can you test the class providing mocks (unless you set fields using reflection, which seems a really, really dumb idea when there are better alteriatives). The example with the Login bean being injected is wrong, it violates the Law of Demeter - take a look what that is. Now, to test, you need to mock the whole (potentially bigger) Login bean, and stub the method that returns the user. Nice step forward. The code that you write in _each and every one of the methods that need the current user_ is the same and has to be repeated, whereas the @Produces does it for you in a single place only. Again, nice step forward in your own solution. "If you don't like the idea of injecting the Login bean, then why not simply create a session scoped bean called "CurrentUser" and during login, set the authenticated user attributes into that session scoped bean?" That's exactly what the producer does for you, with one short method and an annotation. "But if I have a session scoped model, which contained the user, I could spare myself the energy of using a qualifier." Again, do all that (agreed, not much, but still repetitive) in each class that requires that. Good luck. About qualifiers, I am not happy with them either, and use them sporadically - most of the time I have just a single implementation of an interface, or no interface at all (I can already hear the interface-for-all guys call me heretic ;d). They do have their uses though, and without them we were in trouble. "But what is wrong with injecting the Generator bean (which contains that producer method), and calling the method on it which generates the random number?" Again, you have to do it everywhere you need a random number. Imagine the tests - you need to make sure that the randomizer is seeded correctly, which is not difficult, but can get out of hand the more tests using it you create. Or you mock the randomizer, and stub the nextInt() method or sth. With injecting the int directly, just consider how much less noise, and how much easier it is to test your class. And again, Law of Demeter, anybody? "For me, injecting the bean, rather than the value is very important for readability. It gives the reader (maintainer) contextual information about where that value is coming from. In my mind, the following code is much better. It is quicker to write, because I don't need to create a qualifier annotation." For me, the name of the variable providers the information about what the hell that thing is. For readability, you need as little noise as possible, which is not the case when you inject bigger objects and call methods on them to get smaller ones and work with them. About the qualifier - it is an example, you don't need it if you ever inject only random ints - you just don't use a qualifier, and every injection point with type int or Integer is random. You only add a qualifier when you add another int producer, like @Sequential. Consider now that you have a bean that produces sequential ints; not your classes inject either this or the random bean (or the same bean with these two methods, but this somehow strikes me as smelly), and call methods on them, instead of just saying to the world (Weld?) that you are expecting a @Random / @Sequential int. I consider the latter much more expressive and meaningful. "Oh, and don't forget the code for the @Users annotation... I end up with two extra files (the annotation and the producer). Is all that code really better than the following, which is simply put into a bean requiring the entity manager: @PersistenceContext(unitName=Units.UserData) EntityManager userDatabaseEntityManager; " Yeah, and in our example you end up with a surrogate Units class with public static (hopefully final) String constants. But ok, this example doesn't show off much superiority of annotations in my opinion either. "- the objects to be injected are not required to be instances of beans Since almost every class is now a bean, I am hard pushed to think of a case where I could not create a bean if I wanted something injected." I will help you, then. A CDI Bean is something that the CDI container knows of, which means it is in a jar with beans.xml (I personally hate this requirement, but understand the need for it) _and_ either have a no-arg constructor, or an @Inject one. What do you do with classes that you are not in the position to change the sources for? Like 3-party libs that are oblivius to DI? _These_ are not CDI Beans, and the only way to inject them is... use a producer. I consider @Produces methods as 'adapters', changing non-bean 'legacy' classes into beans. Of course, you can create a custom wrapper yourself that is a CDI Bean, and wraps the 'legacy' instance, but now this is complex and somehow dirty, and you have to use new yourself, which is kinda against DI. "- the concrete type of the objects to be injected may vary at runtime This is exactly what @Alternative and @Specialize annotations are for, and I do not need to use a producer to vary the concrete runtime implementation." No, they are not. They are still static, and they allow you to turn on only one alternative in the beans.xml file (if you turn on two, you have ambiguous injection sources). The problem is different - you have an interface (Plugin) and 10 implementations, and you _don't know_ which one you will be using in a certain class (for example, it depends on user input that is available only at runtime), which means you don't know which @Alternative to turn on. With the CDI solution, you can get all plugin implementations, iterate, check some conditions and pick the right instance. "- the objects require some custom initialization that is not performed by the bean constructor Adding the @Inject annotation to a constructor tells the container which constructor to call when special construction is required. How can a producer produce something which a bean couldn't?" Normally, a clean constructor should only assign fields, not do any initalization - in the enterprise world you do it in @PostConstruct. This probably has a lot to do with the fact that proxies (that Guice, Weld, and Spring use) often use subclassing, which would mean the constructor could be called twice or even more often. A producer is like this @PostConstruct, but for _non-bean_ classes (see above what that means). "Section 3.4.2 then talks about declaring producer fields. The example they give shows the field having default (package) visibility, yet as far as I can tell, any bean in the deployment bundle, even one outside the producers package, can use the "product". This is a little like indecently assaulting Java." You are configuring an injector here, not trying to implement a class according to Java rules. It can be protected as well if you like, or maybe even public (not sure, haven't read the specs for some time now). Generally, I consider this post complete rubbish full of FUD. You seem not to get the basic ideas of DI, certain OO principles and just don't get CDI yet. Don't worry, comes with experience. Normally, I don't answer, but as I saw it on JavaLobby, I had to ;d Please read the specs if you still haven't, go to mailing lists, ask questions about the what and they how and most importantly the why - you are going to profit from it. That being said, I am not a big fun of CDI in certain aspects, I think there is still a lot to improve. For example, I don't like the fact that all classes in a CDI archive that have a def constructor are by default beans - this proves problematic when you write a producer for such a class, and suddenly you have a ambiguity. There is also no 'right' way to turn the bean off - I tend to use @Typed with an empty list of types, which essentially turns the bean off. There are some @Veto annotations in Seam (or maybe Solder). CDI 1.1 may add that, and it might add XML based config which will say which package we want to scan, down to class granularity. But hey, XML? Really? Another thing that pisses me of is the non-centralized configuration of the injector - the producers, classes and so on are just scattered around the codebase. I prefer very much the Google Guice approach of modules, and Spring JavaConfig - I consider the latter state of the art currently.

Re: JSR-299 & @Produces

Hi Ant,
Very interesting thought about @Produces. But I think I have to clarify some points you mentioned.

1) @Produces is a simple way to implement the Factory Method pattern. The examples in the specs are not very useful to understand that meaning of @Produces and don't show a good use case for @Produces.

2) The example of Section 1.3.3 is a workaround:
@Produces @PersistenceContext(unitName="UserData") @Users
EntityManager userDatabaseEntityManager;
And then here, the code which uses that entity manager:
@Inject @Users EntityManager userDatabaseEntityManager;
Because the Java EE resources like EntityManager are NOT CDI beans it's not possible to inject things like the EntityManger in a CDI bean. The first snippet is in a EJB where one have access to the EntityManager via @PersistenceContext and the second part is a CDI bean which uses the produced EntityManager.
I think this way will be obsolet with Java EE 7 when the JSF, CDI, EJB stuff is aligned.

Kind Regards, Simon

Re: JSR-299 & @Produces

Hi Simon,

Thanks for the feedback.

With regards to your second point, I tried it, and you are right, I can't just inject a persistence context into a CDI bean. But I wonder if that is because the spec writers were thinking that a CDI bean is designed for the web layer, and a persistence context is designed for the EJB layer (where transactions are handled)? I don't like the idea of injecting a persistence context into a CDI bean anyway (using @Produces or any other way). Although it is better than writing SQL in a JSP, IMHO it is still mixing up concerns.

Cheers,
Ant

Re: JSR-299 & @Produces

Hi Anonymous (-/62.91.33.77),

I thought for a while about whether I would approve your comment, because frankly, it's tone is very aggressive. The fact you haven't left your name didn't help. In the future, please be a little nicer :-)

I won't comment on all your points, but some are interesting.

1) The snippets are not mine, rather copied mostly from the spec. Your tip on injecting on setters rather than injecting on fields is a good one.

2) Login Bean - I didn't explicitly say that I prefer injecting a login bean or current user bean. I might indeed prefer injecting a bean which contains my entire model... All of these conform to Demeter to some degree, which according to Wikipedia is summarised as:

"each unit should have only limited knowledge about other units: only units closely related to the current unit" - no problem here, as the "backing" bean is related to a model bean;

"Each unit should only talk to its friends; don't talk to strangers" - again, no problem here;
"Only talk to your immediate friends" - yup, again, no problem here.

Maybe you need to lookup what Demeter is about, before telling me I am wrong. My world isn't as black and white as yours.

"About qualifiers..." - Yes, I do understand them, you don't need to explain them. Thanks anyway.

"For me, the name of the variable providers the information about what the hell that thing is. For readability, you need as little noise as possible"

I guess we will just have to disagree here. Something I can add is this: I have spent years maintaining large systems where we are often hunting for potential bugs. If I want to find the implementation of say an EJB which the class I am investigating references, it is easy to do. In standard Eclipse, I put my cursor on the interface class, hit ctrl+t and Eclipse shows me all the implementations. If I have a variable with "@Random" and "int" in it definition, and nothing else, I have no idea where to start looking. Well I guess I have to look for where the @Random qualifier is implemented. In the end, in my experience, I will spend more time looking.

"I consider the latter much more expressive and meaningful" - and I don't, I guess we will just have to differ on our opinions.

You go on to give some good examples of when @Produces would be really useful (non-beans, implementation is dynamic at runtime). So good, @Produces does have it's uses. But none of the examples I have seen restrict the @Produces annotation to such cases, rather over enthusiastic people get carried away, and inject random ints...

"Generally, I consider this post complete rubbish full of FUD. You seem not to get the basic ideas of DI, certain OO principles and just don't get CDI yet. Don't worry, comes with experience. Normally, I don't answer, but as I saw it on JavaLobby, I had to." - I might not get the point of @Produces, but come on seriously, insulting me on my own blog like this? I fully understand DI, OO and I am pretty sure I get CDI. This posting was simply a rant about my opinion that @Produces is mostly unnecessary. Why are you so angry in your comments?

Please be a little more polite in the future.

Ant

Re: JSR-299 & @Produces

Hi Ant,

It's just because CDI was the latest spec in Java EE 7 and they couldn't go back and change all the other specs.

I hope this will be addressed in Java EE 7.

There is lot more to do. In JSF and CDI are now the same Annotations (@ApplicationScoped, @SessionScoped and @RequestScoped) and the @ManagedBean annotation is now superfluous because of @Named.

Greetings, Simon

Add a comment Send a TrackBack