Over a million developers have joined DZone.
Silver Partner

JSR-299 & @Produces

· Java Zone

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

Topics:

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}