Home

Add a comment

 

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


Title
Body
HTML : b, strong, i, em, blockquote, br, p, pre, a href="", ul, ol, li, sub, sup
Name
E-mail address
Website
Remember me Yes  No 

E-mail addresses are not publicly displayed, so please only leave your e-mail address if you would like to be notified when new comments are added to this blog entry (you can opt-out later).