CDI Qualifiers are Values, Part 2

In a previous post I wrote that CDI qualifiers are values.

After some more thinking, there are two classes of CDI qualifiers: those that are values for implicit aspects (arbitrary examples: @Synchronous (a value for synchronicity), @Yellow (a value for color)), and rarer ones—those that are both aspects and values for those aspects (as an example, @Named is the aspect; the value of its value element is the qualification value).  There aren’t a lot of the latter, but they do exist.

If you want to write a producer method that works with the latter class of qualifiers, then you must look at the element of the qualifier that represents its value and see if it is meta-annotated with @Nonbinding or not.

If it is, then you are all set: you can just put the qualifier on your producer method, and now your producer method will be able to produce all possible values for that qualifier.

If it is not, then in order to write producer methods you must know in advance of all the members of the domain over which the qualifier’s value element can range.

Consider @Named as an example.  It is a qualifier that does not represent a value.  It represents an aspect.  Its value element holds the value that does the actual qualifying.  But its value element is not meta-annotated with @Nonbinding, so that means there’s no way to write one producer method that can produce items for injection points qualified with the @Named qualifier with arbitrary values.  That is, if your producer method is annotated with @Named(""), then the only injection point it will satisfy is one that is also  qualified with @Named("").  If it is annotated with @Named("fred"), then it will produce objects suitable only for injection points that are also annotated with @Named("fred").

So if you knew all the possible names your application could ever use, you could write a producer method for each of them, annotated appropriately (one annotated with @Named("fred"), one annotated with @Named("alice"), and so on).  Of course, if you knew that, you could just define your own “regular” qualifier annotations: @Fred, @Alice and so on, with an implicit aspect of name.

Whoa, you think; this is cumbersome and in some cases impossible!

Let’s invent a qualifier of the second class called @Labeled, with a single value element. It’s basically kind of like @Named, but with one important difference: on this qualifier we’ll add @Nonbinding to its value element.

Now all you have to do is mark your producer method with @Labeled, and you’ve effectively said, “I’ll take care of anything annotated with @Labeled, no matter what the requested value is.”  You’d better do that, because otherwise the container won’t start up.

This is of course very convenient and the way that a lot of configuration frameworks proceed.  Imagine a configuration framework backed by such a producer method: if someone asks for a String value to be injected at an injection point annotated with @Labeled("fred"), then it is easy for the producer method to go hunting for that value (however it does it) and return it.

There is a faint sense, though, in which this sort of thing doesn’t quite fit the CDI mindset. CDI “wants” you to know all your values in advance whenever possible: that’s why qualifiers are usually values themselves. Then the wiring is utterly explicit: the producer method annotated with @Yellow satisfies injection points also annotated with @Yellow. There is a way in which a producer method annotated with just @Labeled and an injection point annotated with @Labeled("fred") don’t quite plug into that way of thinking.  I have a hazy (possibly misguided) sense that there’s a better way of doing this sort of thing, but I don’t know what it is yet.

Anyway, all of this can serve as a helpful litmus test for clarifying your thinking and identifying which of your qualifiers need @Nonbinding on their elements and which do not.


One thought on “CDI Qualifiers are Values, Part 2

  1. Pingback: Thoughts on Configuration | Blame Laird

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s