CDI Qualifiers are Values

I had this realization today that I’m frankly not sure quite what to do with.

The realization, briefly put, is that CDI qualifiers are values for various unnamed aspects.  They are not those aspects themselves.

For example, the often-seen-in-CDI-examples qualifier @Synchronous is really a possible value for a hypothetical aspect called—I don’t know—synchronicity.  @Yellow is really a value for a hypothetical aspect called, presumably, color.  And yet we’re always left to infer what the aspect is from the qualifier itself (representing a possible value for that unnamed aspect).

We do this in English too: if you say “get me my yellow coat,” I don’t have to ask you about what aspect for which yellow serves as a value.  But that’s what’s going on.

This also led me to realize that, seen through a certain lens, there are other implicit qualifiers that are present everywhere, in an abstract sense (not actually in code).  For example, if I run my CDI application in a test environment, then there is this abstract sense in which all of my injection points (and their corresponding beans or producer methods) are semantically qualified with something like @Test, where @Test is a possible value for a hypothetical environment aspect.

What other aspects are there?  Well, there’s environment, I guess, and project stage, maybe, and data center ID, I guess, and region, and phase of the moon…and all of the other things that go into describing my application’s effective coordinates, all of which affect, potentially, what sorts of things are injected.

For non-configuration injection points, when you inject a Frobnicator, there’s only one choice (perhaps disambiguated from a set of alternatives via a META-INF/beans.xml file). So a lot of this just stays in thought experiment land: the Frobnicator you get is, well, the one you get. It’s not like there are dozens of them lying around.

But with configuration, you’re usually talking about plain types (String), indexed under names, suitable for certain worlds and not for others (“don’t use the production database url!”).

Standard procedure among the 34,472 CDI configuration “frameworks” out there is to make a “qualifier” called, say, @Config, with all @Nonbinding-annotated elements, thus rendering it not much of a qualifier at all (primarily so that a single producer method can use it), and then a producer method or a CDI extension or something that is actually in charge of figuring out what the name of the configuration item is whose value should be retrieved (thus turning the “qualifier” into a name, really). Note how using @Config here confuses the fact that a qualifier is a value, not an aspect.

(CDI itself (well, JSR-330 actually) gets confused in a similar way with its own annotations!  The javax.inject.Named “qualifier” is, note, not a value, but an aspect.  The value of the aspect is given by the annotation’s value() element.)

So what to do with all this?  I am not sure as of this writing, but I have this nagging sense that there’s the germ of a more powerful, more properly-aligned-with-the-spirit-of-CDI configuration extension brewing in here.

Interesting Things About Kubernetes And Ports

After decades of Java, I am now reduced to a rank rookie as I work on Kubernetes-related tasks.  It’s fun being the Dumb New Guy again.

It was in that spirit that I started asking some questions on the #kubernetes-users Slack channel.

I learned that the Dockerfile of an image referred to by a Kubernetes Deployment is basically advisory.  Where ports are concerned, specifically, any EXPOSE directive is basically ignored or superfluous. That makes a certain amount of sense.

Instead I was advised that containerPorts are where you state definitively what ports to open on your Container.

As it turns out, this isn’t strictly speaking correct. I found from some careful reading of the Container documentation that the containerPorts directive is also advisory (well, “primarily informational”, whatever that means).

So that all means that you could, conceivably, have a Dockerfile in the mix that never uses EXPOSE, and a Deployment that never uses containerPorts, and you could write a program running on the Docker container in question on whatever port it wants (let’s say 9000), and assuming that you defined a Kubernetes Service with a targetPort of 9000, connections would go through just fine.