Ant is a freelance Java architect and developer. He has been writing a blog and white papers since 2004 and writes about anything he finds interesting, related to Java or software. Most recently he has been working on enterprise systems involving Eclipse RCP, Google GWT, Hibernate, Spring and J2ME. He believes very strongly in being involved in all parts of the software life cycle. Ant is a DZone MVB and is not an employee of DZone and has posted 27 posts at DZone. You can read more from them at their website. View Full User Profile

JSR-299 & @Produces

11.11.2011
| 4236 views |
  • submit to reddit

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.
 

From http://blog.maxant.co.uk/pebble/2011/11/07/1320702240000.html

Published at DZone with permission of Ant Kutschera, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Witold Szczerba replied on Fri, 2011/11/11 - 5:21pm

Hi,

first of all I would like to make clear - JSR 299 is NOT coupled with JSF. See my further comments below.

Do I really want EJBs to be the backing beans of web pages?
[...]
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 fact that JSF may have an EJB as a backing bean does not mean you have to put everything there. You can still delegate to another EJB to deal with more "businessy things". I think that in your case, it is still even better when your backing bean is also EJB. Why? When your backing bean is not transaction aware and you want your backing bean to collaborate with two or more EJBs then each time you cross a border between your backing bean and some EJBs - application server would have to open new transaction. When your backing bean is EJB - it is you to decide where are and where are not transaction boundries.

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.

@Produces does not do injection. @Inject does. @Produces registers things in application's injector, so it is an easy way to define factories. I know you know this, I just wanted to make that clear to everybody.

Late in your post, you criticize @Produces like this:

@Inject @LoggedIn User currentUser; 

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?

I think you are missing the point here. This is not about what you can do now and what you were not able to do before. You say that everywhere you need a logged in user, you would like to inject a "Login" bean and ask it for current user. For me that means more coupling without a reason. Why? Because OOP is all about building a web of collaborating objects which "talks" to each other in order to do something meaningful. This is known as a "Tell, Don't Ask" principle. Injecting "Login" bean only to query it for current user does not add anything meaningful to the picture. It is not a functional collaborator. More than that - when creating a unit-test for your use-case, you have to prepare a Login bean stub (yes, a stub, not mock) whereas, following the OOP way of thinking, you should rather prepare mocks. Least, but not last, injecting a Login bean only to query it for a user is almost breaking a "Law of Demeter" principle as well, because the only thing you are interested in is current user, not the login bean. So again - one should ask only for things that they actually need - a current user in that case, no matter who is responsible for providing it.

Now, let's take different point of view. Imagine there is no @Produces annotation. How would you define factories for things that need to be built, initialized and who-knows-what-else before they are ready to use? Every time you would have to do the following:
- create some "provider" interface with a method like getSomething()
- implement a bean for that interface
- inject that provider and query it for 'something'.

Now this can be tricky, I am not sure I can explain, but let me try. Let's say you want to scope your 'something'. How can you do that with your "something provider"? It becomes hard, because you are responsible for calling the getSomething() method. On the other hand, @Produces is always scope-aware. More than that, the bean being injected is, by default, proxied by server so you do not have to control instances. You can inject short-living object into long-living object. The short-living one will be proxied inside long-living one. I know what you say - you can do the same with a 'provider' bean. Just "scope" it, create an instance of "something" once, store it in a private field and return that value in a getSomething() method everytime you need, but isn't it simpler with @Produces? Aren't we supposed to get more help from environment so we can spend more time thinking and coding a business logic?

Ant Kutschera replied on Sat, 2011/11/12 - 11:56am

Hi Witold, thanks for the comments.

You are right, injecting the login bean into another bean is a bad idea.  I didn't write it very well in the article, but I wouldn't inject a backing bean from one view into another, because to do so is confusing the responsibilities of the beans.  I would use a session or conversation scoped model instead.  To me, a backing bean is simply the view model combined with the local controller (it provides data in the format required by the view, and is called when the user clicks somewhere on the view).  So after authenticating the user and loading their profile, the login bean would push that data into a session scoped model.  To read the current user, I would inject the model, and call a method like "getCurrentUser".

Your point about mocking/stubbing is a good one, and one which someone else brought up too.  But my models are pretty dumb, and mocking/stubbing is normally used to replace functionality, not state.  So the comment isn't really relevant.  Sure, like I already said, lots of people today are saying models shouldn't be dumb, but I disagree.  I have very good reasons for keeping models dumb, if you are interested, please ask.

Perhaps I am old school, but I think it is important to keep the backing beans for JSF pages, facades handling transactions and security and models all separate.  So as far as making a backing bean transaction aware, I don't agree.  OK, if I'm writing a mini app, it makes sense, because the overhead of creating a backing bean, facade, model, etc. is over the top.  I just worry, that people learning Java EE today might end up putting everything into one bean, and to me that is no better than putting SQL in a JSP.

I am not happy with how I wrote this article - I've had quite a bit of negative feedback.  But before I wrote it, I did talk to colleagues about my thoughts, and most agreed.  The main thing I have against @Produces is the following.  Think of this code:

    @Inject @Sequential int nextNumberInSequence;
    
My first reaction to that code when I saw it was "where does the number come from?".  Many people say you shouldn't care.  You said "tell, don't ask".  But we spend much more time reading code, than writing it.  I've been maintaining a system for a few years now, and it's expected to be productive for up to 30 years.  The system it is replacing will be 25 years old soon.  So during this softwares life time, most people reading the code will be asking things like "hmmm... someone reported a bug with the sequential numbers and I wonder where that number came from...".

If I had injected a bean which provides me with the number when I ask it to, I just need to hit ctrl+t (in Eclipse) and I can see all the concrete implementations of the bean interface, then select one and instantly see the code which produces the sequence number.  If I don't use an interface for the bean, just a class, then all I have to do is hit F3.

While it isn't that hard to find the producer method when I have one qualifier, it still takes a little longer (at least in Eclipse).  But in more complex systems, two qualifiers might be used, or even more.  Then it gets really hard to find the producer which is annotated with all the relevant qualifiers.  Debugging is harder too, because I have to locate the place where the object is produced and set a break point there, as opposed to simply setting a breakpoint where the method to get the sequential number is called, and stepping into that method.

I can see that there are cases when @Produces is useful (e.g. you want to make an instance of a class available, but that class isn't a bean, and it's class is in a library where you can't modify the code).  But my problem is that all the tutorials out there are suggesting that you use @Produces for even the most trivial tasks.  And in my humble opinion, for the reasons given above, that is wrong.

Cheers,
Ant

Witold Szczerba replied on Sat, 2011/11/12 - 8:03pm

Hi again :)

Think of this code:

    @Inject @Sequential int nextNumberInSequence;
    
My first reaction to that code when I saw it was "where does the number come from?".

 I can see your point here and I do agree that such producers can be hard to find, but for me this is just a matter of tools used. For example you can ask NetBeans 7 to find a declaration of injected artifact, no need to chase it manually.

Of course nothing is going to replace a common sense of developers and everything can be misused. For me, the @Produces mechanism can be a key concept helping to decouple building blocks of applications.

As to the JSF - I really do not feel comfortable going into the details, as I have actually never used it. I can only try to imagine to some point the similarities between JSF and other things I have been doing, but even though I believe it might be useful for backing bean being to be in the same application context as other objects it is talking to. I do believe that separation of concerns is critical when creating something bigger than a "Hello World" tutorial application, but backing bean having EJB context does not automatically mean "what a mess".

Thanks for having a nice conversation :)

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.