Qualifiers and Configuration Coordinates in Configuration

This post is part of a larger series, I guess, maybe, that is heading toward what a good Java configuration API might look like.

(My usual disclaimers: I work for Oracle on the Helidon project, but never speak for the big red O unless I have to (this is not one of those times). I am also a committer on MicroProfile Config (but have reservations about the project) and Jakarta Config (and have reservations about its direction). I’m not writing here in any of the roles listed above (I rarely do).)

I’ve written before about how Java configuration, reduced to its essence, when viewed from an application developer’s standpoint, has nothing to do with dynamic typing or named properties or converters or tree nodes or all the other things that people immediately think of that look and smell like System properties for no good reason. Instead, it must be a low-level, deliberately limited precursor to things like dependency injection systems (since it will presumably be used to configure them). Precursor or no, it is still about asking for a particular kind of object suitable for a particular kind of application running in a particular kind of place and receiving it. Full stop.

I’ve also written about how a great example of such a configuration system API, as utterly straitjacketed as it is (on purpose), is java.util.ServiceLoader: pass it a type, get back an object that was configured in a place that doesn’t require code to be recompiled to reconfigure.

So what does suitability mean here? What is a place? What does it mean to have an object suitable for an application? Isn’t there just one application?

I like to think of this in terms of configuration space. Configuration space is a {emulates Carl Sagan} huge multidimensional void that contains all possible deployments of your application. When you deploy your application, you are, whether you realize it or not, situating it in configuration space.

I will occasionally call the the various points along configuration axes that you use to identify your application in configuration space configuration coordinates. They’re like the latitude and longitude that pick out your application in configuration space.

Other times I will call these coordinates qualifiers, after CDI’s qualifiers: they are additional ways to further describe whatever it is you’re talking about. Acquiring a Car may logically require that you specify exactly what kind of Car implementation you’re looking for, i.e. a suitable one that is qualified by qualifiers you supply.

Dependency injection systems, as noted, almost all have the notion of qualifiers. The only real difference is that most dependency injection systems begin by assuming that if you have an unqualified injection point, you are asking for the default thing that might satisfy the injection point.

Configuration is different. An application is implicitly qualified, logically speaking, by the configuration coordinates that describe its location in configuration space. If I run my application in the test environment and in some specific cloud region with experimental features turned on, the application, as developed by the application developer, really shouldn’t have to change at all to ask for a different thing (or else we would not, by definition, be talking about configuration!). So if the application developer is asking for a Car, she should continue asking for a Car, i.e. she shouldn’t have to recompile her code just because her application is in a different “place”.

That would seem to contradict the statement earlier that acquiring a Car may require that you specify exactly what kind of Car implementation you’re looking for. You can work around this conceptually by saying, OK, the configuration system, when it comes up, must first figure out what the implicit qualifiers of the application it “belongs to” are. That is: qualifiers are primordial things to configuration systems.

Consider Java’s own ResourceBundle, which was not really designed to be a configuration system, but which does acknowledge the primordial nature of implicit qualifiers. When you ask for a ResourceBundle, the underpinnings of the system figure out what your application’s coordinates are in resource bundle space, and load a resource bundle for you that is suitable for where your application finds itself. Less stuffily: if the current locale is German, then you’ll get the German resource bundle. If it’s unset, then you’ll get the default one. Your code doesn’t change. Locale, in this case, is an example of a qualifier that is implicit and locates your application in a particular kind of space.

Consider Spring, which features configuration profiles, a clumsy and coarse-grained way to give a name to logical bundles of qualifiers. Ask for a particular thing, and depending on what profile your application has, you might get the profile-specific version of that thing or the default one. The developer of the application doesn’t change her code.

Consider Netflix’s Archaius, which allows you to define a CascadeStrategy, under the covers which is a rather clumsy way to emulate a ResourceBundle.Control object. Same deal; your application ends up being located in configuration space by a mechanism that you don’t really have to think about as an application developer: if you ask for a particular configuration item, then the one that is most suitable for your application’s “location” will be given to you, without your code having to change.

Many of these configuration or configuration-like systems that work with qualifiers, whether they know it or not, also tend to treat them as hierarchical, and bake them into the configuration names. Obviously, qualifiers need not be hierarchical, and equally obviously do not change the fundamental name of the thing they qualify, but, oddly, this became convention at some point, and so this is how they are often modeled—a practice which obscures what is really going on. For example, in English, if you’re looking for a hostname, even if you’re looking for one suitable for the development environment, you’re still looking for a hostname, not a dev.hostname.

If you stretch all of this to the breaking point, then it’s also the case that a name of a particular configuration item is just another qualifier! If you’re looking for a Frobnicator named goop, then you’re looking for a Frobnicator with qualifiers of name=goop, environment=development (let’s say), experimentalFeatures=on (let’s say), and so on. But a name is as good a qualifier as any to elevate to principal status, so there’s no need to go crazy here.

So then: we have at the core of our configuration concepts types (the kinds of things the developer is trying to acquire from configuration) and qualifiers (the configuration coordinates identifying the application in configuration space), as well as names (which are really just an obvious elevated kind of qualifier).

This should sound familiar. Any dependency injection heads out there will recognize that types and qualifiers are exactly what you use in every dependency injection system on the planet to retrieve objects. Most DI systems will represent them as Java annotations, but if you dig into them you’ll see that that is mainly for the strict immutability semantics that annotations happen to carry with them, not for anything that is somehow magic about annotations per se.

Finally, there is another Java-centric system out there that does all of the following:

  1. Allows the application developer to request a qualified Java object of a particular type
  2. Allows the application developer to further qualify that request (and actually qualify individual pieces of a request)
  3. Allows the application developer to supply representational hints about the Java object being returned
  4. Mediates between potentially competing result producers to deliver the result that is the most suitable for the caller’s “location” in “space”

That system is JAX-RS/Jakarta RESTful Web Services! Obviously I’m not suggesting that Jakarta RESTful Web Services is a good configuration system (for one thing, it is too high-level and the concepts involved are at the wrong architectural level). But I am suggesting that the fact that it deals with paths to Java-typed resources, qualified by header values, media types, locales and all the other implicit coordinates that locate an application in space is worth looking at in the abstract. I hope to sketch that out in another post.

Some of the Things I Don’t Like About MicroProfile Config

Here are some things I don’t like about the MicroProfile Config APIs (and really also most APIs like them) and the ways in which they are defined (or not defined) to work. I’m writing them down in no particular order so I don’t forget. This is obviously related to my prior post.

If I’m handed an opaque application that uses MicroProfile Config, I don’t know the names or types of the configuration properties it will seek, if any. So I don’t know what configuration to author.

If your opaque library happens to seek “fred” (and it’s opaque so I can’t know this up front; see above; but let’s say I use strings or something and get a good guess) and my library also seeks “fred“, and yours expects a certain String format for “fred” (so that it can convert it to some specialized object), and mine expects a different String format for “fred“, and I combine the two libraries into an application, and there are Converters from you and Converters from me and various ConfigSources involved, there’s no way that I can see to reconcile this other than trial and error at runtime.

If I put a ConfigSource on the classpath with ordinal Integer.MAX_VALUE that returns a random String for every value sought, or do something well-intentioned but accidental like this, pretty much everything will fail at runtime and it’s difficult to understand why. (In general, if you have to resort to ordinals or priorities in anything, you have already lost; what you’re actually after is a reduction algorithm.)

A ConfigSource can report whatever it wants from getOrdinal, so even if you set a config_ordinal property in its backing data somehow, you don’t know if your setting will be used.

A ConfigSource can return whatever it likes as its name, and since this is used as a tiebreaker in sorting, sorting is indeterminate. So which ConfigSource “answers the phone” is also indeterminate from run to run.

We insist that developers model business objects because developers know the names and types of the data they use (Person has a getAgeInYears() method that returns a positive int, not a method like getProperty(String name, Class<?> type)). But MicroProfile Config forces configuration (where the application also knows the names and types of the configuration data it consumes) to be consumed via dynamically-typed, Map-like probe requests (Config.getValue("personAge", int.class)). That’s very odd.

A Config can return an empty set for the configuration property names it claims to support because the set of such available names may change from moment to moment, or may not be able to be determined for any reason. So an application developer doesn’t know what she can ask for via the probing APIs. (Can she ask for “fred“? If she asks for “fred” twice and gets two null responses, does that mean that “fred” is never supported? Or maybe just that coincidentally “fred” couldn’t be retrieved during that particular time window? She doesn’t know, and can’t know.)

A ConfigSource can do whatever it wants, as can a Converter, as can ConfigSourceProviders, and they can all come from the classpath, whether user-, application-, application-server- or library-supplied, or all four, and a Config is essentially just a shell around these ConfigSources and Converters and ConfigSourceProviders, so not only do you not know what you can ask for, you don’t know whether it will be delivered to you for any given call you make, or, if it can, whether it can be delivered to you with the type you want, or, if you make it this far, whether such typed data can be delivered to you again with the same type if you make the same call, or if you restart the application if the same things you observed last time will hold true this time.

Since a Converter can do whatever it wants and can be user- or system-supplied, then even with the Config::getConverter method you don’t know what kind of suitable conversion is available at any given point for any given property.

Given a configuration property named “fred“, there’s no way to know what type(s) its value may successfully be converted to (other than String).

Configuration, in other words, is by spec unpredictable in name, type, availability, idempotency and determinism. That’s bizarre.

While the APIs and specified behavior for the Config-locating-and-assembly subsystem (ConfigProviderResolver) to conceivably work with any ConfigSource and Converter and Config implementations, in practice doing things like mixing and matching one vendor’s ConfigProviderResolver with another’s ConfigProvider doesn’t work.

Applications are associated with ClassLoader instances in some vague way. They could be associated with Object instead (provided the Object-in-question’s equals and hashCode methods are stable) and everything would still work. This tells you that ClassLoader association is unnecessary.

When a classloader is unloaded, various internal resources inside any MicroProfile Config implementation must be released, but there’s no real specification about how this should be done. In practice, to do this properly

There’s no specified way to configure MicroProfile Config with MicroProfile Config. There are occasional places where the need for this is visible and an attempt has been made to address it (config_ordinal, ConfigSourceProvider), but with no real systemic approach.

Notions of how to close and otherwise release resources including Converters inside any MicroProfile Config implementation require absurdly complicated WeakReference machinations in any specification-compliant implementation for no really good reason (see above). Otherwise you leak ClassLoaders.

Since you don’t know from call to call whether “fred” is available, let alone what type it can be converted to (since its format could change or conversion could be random), then injection of its value via CDI should really be defined in terms of only Provider injection. Alas. So an Integer-typed, @ConfigProperty-annotated CDI injection point that was “validated early” can fail later, or not, at runtime, which is the very sort of thing CDI is designed to prevent.

Overall, the APIs conflate the problems of object acquisition (“get me a ham sandwich”) with those of object production (“make a ham sandwich out of its parts and hand it over”), binding (“to make a ham sandwich, find bread, ham, cheese, mayo, mustard and lettuce”) and sourcing (“you find the bread in the breadbox unless it’s already out and then it’s on the counter, the cheese is in the cheese drawer, and the mayo is usually on the top shelf of the fridge, unless you have to open a new bottle….”). Then the results are served up with unpredictable scalar probing methods (unless I’m using CDI injection, I have to ask for the bread, then the condiments, then the lettuce and put them together, assuming I actually got results for these). This is all very strange. I just want a ham sandwich. The person making the ham sandwich probably cares a great deal about all this stuff, but I wouldn’t be asking them for a ham sandwich if I wanted to make it myself! (Also I’m never going to convert bread to mustard.)

Finally, an application developer also basically just wants a ham sandwich. She wants to receive a HerApplicationConfigThatSheDesigned object in some ceremony-free manner that’s appropriate for the environment her application is in, and call typed methods on it at various points during the lifespan of her application to get the information she needs, handling errors in the way that she sees fit. You can see examples of this in the wild. Consider this, and then re-read what’s above and sit with it.

There are so, so, so many ways this whole area could be better. I hope to say more soon.

MicroProfile Config and Other Configuration Musings

Disclaimer: I work for Oracle but never speak for them when I can help it, and especially not on this blog.

Here are some unstructured musings on MicroProfile Config and configuration in Java in general.

Extremely Quick MicroProfile Config Overview

MicroProfile Config is a Java-centric, read-only configuration library. At its most fundamental level, you ask it for a named textual value, tell the system what Java type in your program the textual value should have for this request, and get that typed value back. For example, you might ask the system for a value corresponding to the name wheel.circumference, and specify that it should be returned as an Integer:

final Integer wheelCircumference = config.getValue("wheel.circumference", Integer.class);

Then, unbeknownst to the requesting application developer, MicroProfile Config uses at least three different abstractions to hide where this named scalar value comes from and how it is muscled into its final typed form.

Incidentally, by “scalar”, I mean, very loosely, something like very simple textual values. That is, the atomic nugget of information in MicroProfile config is individual “flat” strings named by opaque names. At the lowest level, you are always asking MicroProfile Config for individual text nuggets, not anything more complicated. Everything else is built on top of that.

For example, MicroProfile Config does layer some Java Beans-like object building facilities on top of this scalar value manufacturing system. You can sprinkle some annotations around and cause a Wheel object to come into being with getCircumference() and getSpokes() accessors, but this Wheel object will in such a case always be produced out of the scalar values for (say) wheel.circumference and wheel.spokes with appropriate data type conversion applied (a primitive form of part of the concept of object binding). I’ll term these kinds of values made up of multiple other values composites: the Wheel type is a composite; its individual properties here all happen to be scalars.

So much for a quick overview of MicroProfile Config.

Of Names And (Typed) Values

One of the problems you have when you have any scalar-centric key-value system like MicroProfile Config is: if you ask for something by name, then you have to determine what the (Java) type of that thing is in order to use it. Either there is exactly one type (for example, System.getenv("foobar") always yields a String), or you have to somehow know what the type of the named thing is, potentially applying appropriate type conversions along the way (for example, System.getProperties().get("foobar") returns an Object; it is now up to you to figure out what to do with that value).

MicroProfile Config forces the application developer to specify the type during lookup (e.g. config.getValue("wheel.circumference", Integer.class)). (There’s no way to learn if it makes sense to type a wheel.circumference property as an Integer; you just kind of have to know that it is. Or if you want to look at it the other way, equivalently, the configuration author has to use common sense to figure out what kind of usage her textual configuration nugget will have within any arbitrary application. This is of course a problem, and we’ll talk about it later.)

One of the questions that immediately arises is: suppose the configuration information is fundamentally textual in nature. Who converts "27" into (effectively) Integer.valueOf(27)? (What if the configuration value is "27 inches"?)

MicroProfile Config has the concept of a stateless Converter that accepts a String and converts it to a particular type if possible. There can be user-supplied Converters and built-in ones. All of them are overridable. So somewhere in the system there will be a Converter that can convert Strings to Integers, so it will kick in and the application developer will get back a value equal to (say) Integer.valueOf(27). So far so good.

Of course, if the application developer calls config.getValue("wheel.circumference", java.awt.Point), there may be no such Converter so she may be out of luck, but won’t learn this until runtime. So, of course, she can supply her own Converter that converts Strings to Points, and hope that it is used (and not overridden deliberately or accidentally by some other component’s Converter that also converts Strings to Points but in a different way, by reading a different kind of textual format, for example).

This is where we start talking about the fact that Converters can have priorities and are sorted in a particular way, can be packaged with any library or container, and discovered from various locations, and—

But let’s back way up.

Why is the application developer looking up values by arbitrary names in the first place? Is that really what she wants to do? Isn’t this just an unfortunate means to an end? Take some time to think about this.

Suppose she were magically able to call a typed method on a hypothetical configuration object sourced from a hypothetical configuration system instead:

final Integer circumference = HypotheticalConfiguration.get().getWheel(FRONT).getCircumference();

From her point of view, how the circumference of the front wheel is found or produced or manufactured by the configuration system is entirely immaterial. Maybe it was deserialized. Maybe it was a Java Record that got assembled out of its record components somehow. Maybe it fell from the sky. Maybe Jackson kicked in and did object binding from JSON. Maybe it’s a JPA entity retrieved, already constructed and converted, from the database. Maybe it sprang full-fledged from an underlying directory system. Maybe it was built by a JNDI ObjectFactory. Maybe it resulted from a storm of Java Beans PropertyEditor operations. She doesn’t know, and she doesn’t care. Nor does she have to worry about accidentally making typos in configuration value names, or about supplying the wrong data conversion type. If you look carefully, her use case does not mention the production side of things at all. There’s a wheel circumference, you get it by calling getCircumference() on a Wheel object, and it returns an Integer. The end.

Remember, she is an application developer, so she can (and ultimately must) express her requirements using the Java language—as she does here. Here, she defines the composite Wheel type to feature whatever properties of whatever type she wishes. There is no need to “go after” those properties individually as textual scalars by some kind of name. It is up to whatever “back end” of the hypothetical configuration system to make whatever is needed, however it wants to, which may involve textual scalars and object binding or may not. Those kinds of problems are now pushed off entirely into the domain where they properly belong: that of production, object binding and instantiation, which are none of her concerns. But more on that aspect a little later.

So why are there these arbitrarily-typed key-value Java configuration systems, if there are so many opportunities to make mistakes with them?

For environment variables, of course, the answer is simple: environment variables can be passed to programs of any type, not just Java, so they are expressed in the lowest common denominator of the operating system: simple humble strings, so that’s what you ask for as an application developer, and exactly what you receive.

And something like System.getProperty("foobar") is a convenient wrapper around (String) Hashtable.get("foobar") because system properties can be supplied on the command line where, again, they must be strings. (However, note that it is possible for someone to install a Glorp-typed object into the Properties object returned by System.getProperties() under the name “foobar” in which case System.getProperty("foobar") will of course fail. There’s our old friend type conversion again and all the problems it entails.)

And for systems like JNDI or java.util.Preferences that allow for reading and binding you need to make sure that the application developer can write things into the abstracted directory that other programs written in other languages can read. So scalars are the way to go here.

But for Java-only, read-only configuration? Where the application developer doesn’t have to write anything “back” to the configuration system? There is nothing in her use cases that requires untyped lookups by arbitrary name. It is, to be sure, a pattern that we’ve all gotten used to because we all look up system properties and environment variables by arbitrary name, and system properties and environment variables are some of the things that configuration systems usually abstract over, but, again, there’s no requirement that this be so of a configuration system that supports application developer use cases.

Back to MicroProfile Config for a moment.

In MicroProfile Config, you can inject a composite object like this (though I don’t think you can look one up programmatically?):

// Somewhere in your program
@Inject
@ConfigProperties
@Front
private Wheel wheel;

// …provided that somewhere else you also have something like:
@ConfigProperties(prefix = "wheel")
@Front
public interface Wheel {
  public Integer getCircumference();
  public Integer getSpokes();
}

So they recognize the utility of composite configuration objects even if it’s clumsy for them to make one.

Now wheel in the example above will receive an instance of Wheel whose getCircumference() method will return an Integer created from the wheel.circumference textual property as converted by some Converter<Integer> somewhere (likewise, the getSpokes() method will return an Integer created from the wheel.spokes textual property as converted by some Converter<Integer> somewhere).

This is nicer for the application developer, because now she doesn’t have to worry about spelling out scalar names (typos!) and (often non-discoverable) data conversions (oops, wrong type) herself.

But even here it strikes me as bizarre that MicroProfile Config leaks concerns from one domain into another. Specifically, it leaks object binding concerns (the fiddly bits about how a Wheel is produced, including the prefix element of the strangely-named ConfigProperties annotation) into the application developer’s usage domain (she doesn’t give a flying hoot about how a Wheel is produced, but oddly here has to indicate binding information herself even though binding isn’t her concern, and either the configuration author has to make sure that her named textual configuration nuggets have exactly the names dictated by the object binding requirements—e.g. drop “get“, lowercase the first character of what follows—or the application developer has to make sure that her composite object has accessors that line up with the configuration author’s textual configuration nugget names).

Why not leave binding concerns where they belong (on the “production” side), and usage concerns where they belong (on the “consumption” side)?

On DropWizard

Let’s take a hopefully relevant detour into DropWizard land for a moment. Disclaimer: I have no affiliation with or opinion about DropWizard; it is just an example of a larger point I want to make.

In DropWizard, a master configuration object is handed to you. You can’t escape it. You must define such a configuration object. Here’s what I mean; look for where HelloWorldConfiguration shows up:

public class HelloWorldApplication extends Application<HelloWorldConfiguration> {
    public static void main(String[] args) throws Exception {
        new HelloWorldApplication().run(args);
    }

    @Override
    public String getName() {
        return "hello-world";
    }

    @Override
    public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {
        // nothing to do yet
    }

    @Override
    public void run(HelloWorldConfiguration configuration,
                    Environment environment) {
        // nothing to do yet
    }
}

When your HelloWorldApplication starts (via its main method), the run method will eventually be called, and you can see that it is supplied with a master configuration object (in this case a HelloWorldConfiguration object). How did it get there? It doesn’t matter.

Here’s what the HelloWorldConfiguration object might look like (I’ve cribbed this whole thing from the DropWizard documentation itself):

import io.dropwizard.Configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.validation.constraints.NotEmpty;

public class HelloWorldConfiguration extends Configuration {
    @NotEmpty
    private String template;

    @NotEmpty
    private String defaultName = "Stranger";

    @JsonProperty
    public String getTemplate() {
        return template;
    }

    @JsonProperty
    public void setTemplate(String template) {
        this.template = template;
    }

    @JsonProperty
    public String getDefaultName() {
        return defaultName;
    }

    @JsonProperty
    public void setDefaultName(String name) {
        this.defaultName = name;
    }
}

If you’ve been around the block a few times, you can see that there are Jackson annotations all over it. (You’ll also know that the setters are not necessary!) But apart from that (and even the annotations aren’t necessary depending on how Jackson is used), it’s a POJO. As it should be!

Now look back at theHelloWorldApplication. The application developer has no idea where the HelloWorldConfiguration object came from or how it was made, when you look at the actual application code. That is, the use case made manifest by the application code itself has no object binding or production concerns in it whatsoever. At an abstract level, the application developer has:

  • Defined what her configuration looks like (by virtue of creating the HelloWorldConfiguration type and defining the getters she’ll call on the HelloWorldConfiguration object in her run method)
  • Advertised this configuration to whoever and/or whatever is going to supply her with such a thing

By advertising, I mean an abstract notion of: has put this class somewhere where people (such as configuration authors) know to look for it. Advertising can take many forms, from placing a file in a well-known spot to listing the file’s location in a file that is itself in a well-known spot (e.g. the Java ServiceLoader contract), or a variety of other means. In DropWizard, some of the advertising is baked into the application itself: if you were, for example, to javap the HelloWorldApplication.class file, you would be able to figure out what the master configuration object is.

Anyway, the master configuration object here is just Java code. There are no name-based lookups involved. There’s no data conversion. There are no conventions to follow. The application developer will call configuration.getTemplate(), for example, and get exactly what she is expecting as an instance of exactly the Java type she’s expecting it. If she added getComplicatedHairball() to it, then she’d get a ComplicatedHairball object back to work with. She can’t make typos, or her class won’t compile. She can’t specify the wrong data types for conversion. Namespace clashes between components are no longer a thing. All of this is because use case concerns are in the right place and don’t leak.

Back to DropWizard specifics. On the production and unmarshaling side, DropWizard is opinionated: it turns out that the configuration author must write her configuration in YAML, and Jackson is used to muscle this YAML into an instance of the master configuration object, following its usual object binding conventions. (Many of you will know that this of course does not require that there be any annotations on the HelloWorldConfiguration object at all, and that any customizations can be made using mixin annotations or Jackson ObjectMapper incantations. The point here is that even the Jackson bits are not required to sully the HelloWorldConfiguration if you really want to keep things pure.)

They’ve also left themselves some wiggle room with this sensible architecture: even though DropWizard is currently opinionated, if you squint you can see that if it decided to change its configuration-object-producing machinery from YAML-and-Jackson to XML-and-JAXB, the application developer’s code would not really change.

Fantasyland

DropWizard is opinionated on how configuration objects are unmarshaled, but as noted there’s some architectural wiggle room, and so now let’s travel to fantasyland for a moment.

Let’s pretend there exists in the world some kind of facility like DropWizard’s configuration machinery, but instead of requiring the configuration author to write YAML (or JSON) in a specific file or classpath resource, and instead of requiring Jackson to be used for object binding—in fact, instead of requiring object binding at all—let’s pretend this “back end” production mechanism is pluggable. Let’s pretend a hypothetical configuration system can locate what back end it’s going to use to make configuration objects. Seriously, let’s pretend.

Oh look, nothing really changes from the application developer’s use cases or standpoint!

Specifically, she doesn’t have to change any names or data type conversion code. She doesn’t have to make sure that composites have names that “work with” the configuration system. She still can’t make typos and still can’t provide incorrect typing information. Component namespaces are still safe. All of those problems are now (properly!) the concern of whatever concrete back end provider is in the picture, and the concrete back end provider doesn’t have to deal in scalars at all.

Let’s further pretend that the back end provider is not one that uses object binding, Jackson- or MicroProfile Config-based or otherwise. Perhaps it is something like Hibernate that loads an entity straight out of a database. In this example, the data conversion happens at the native database level so there’s no need for data conversion to surface at the configuration system level at all, because it’s already being handled by a combination of the database, JDBC and Hibernate.

Or let’s say that MicroProfile Config is the back end provider, and uses a whole bunch of config.getValue("someScalar", SomeType.class) invocations to assemble a composite, namely the master configuration object. Or maybe somehow it uses the same mechanism that it uses to produce @ConfigProperties-annotated objects today. The usual problems that MicroProfile Config has with things like “which Converter will be used” and “which ConfigSource will produce scalar value x” and “how do I set an empty string” and “what do we do about nondeterministic ConfigSource ordering” and so on are still in play, but now they are isolated where they belong, namely in the domain of object production and binding, and do not impact the application developer use cases in any way. The configuration author—the person responsible for authoring the scalar textual values that MicroProfile Config will fundamentally consume—also now has the benefit that she can at least have the possibility of discovering what configuration she must supply since the master configuration object type is advertised, and contains all relevant naming and typing information.

Or maybe the master configuration object itself simply is a MicroProfile Config Config object, if the application developer desperately wants to work fundamentally with it for some reason, in which case the back end is absurdly simple. Who am I to stop her? Or maybe it’s a Properties object. Or a JNDI Context. Or a File. Or anything else, really. Fantasyland handles this too because all that is required is that it be able to produce a Java object of some kind that the application developer can work with.

On Configuration in General

This starts to get into: now we’re just talking about plain Java objects, so just what is configuration anyway? That of course is an enormous question and I don’t have the time, space or inclination to deal with that here. But! I can say that as far as a configuration system is concerned: configuration objects should probably be able to be whatever you want them to be. On the reading end, it’s just POJOs. On the production/writing end, it’s just how those objects get built.

Often times here is an unspoken assumption that configuration systems that produce “rich” Java objects—composites—should tread carefully, as there are many other subsystems that deal with the production and management of such objects. For example, CDI lets you write producer methods that produce rich objects out of other objects. So shouldn’t CDI be in charge of producing rich objects? In some vague unspecified way you want configuration to not really tread on these subsystems’ toes.

Here I tend to think that a configuration object is whatever the application developer wants it to be. If she wants a configuration system to produce a ferociously complicated master configuration object singleton, then that is her (possibly ill-advised) right. It may not be a very good choice, but it isn’t really something that the configuration system should have an opinion about.

An application developer will probably want to work with a master configuration object that is relatively simple that can then be used as raw materials for higher order Java objects. “Relatively” simple is of course fuzzy: A Bicycle CDI bean, for example, might be produced by a CDI producer method, not by configuration, but using two Wheel objects sourced from the master configuration object and injected into the producer method’s parameter list.

At some point I hope to prototype such a system so it’s easier to talk about; stay tuned.

Weld and Client Proxy Creation

(Taking a break from my blog post series in progress to write down stuff that I stepped through today on how Weld creates client proxies.)

The CDI specification says that if you have a managed bean in a normal scope (think: class with something like @ApplicationScoped or @RequestScoped on it), it must have a non-private, zero-argument constructor (and must not be final) so that a CDI implementation can proxy it.

You may have noticed when using Weld’s implementation of CDI SE that this seems not to be required. I can do this:

@ApplicationScoped // normal scope
public class B {
  private B() {} // hmm, seems to violate specification
  @Override public String toString() { return "B"; }
}

…and can inject an instance of that wherever I like:

@Dependent
public class A {
  @Inject
  public A(final B b) { // hmm; how does CDI/Weld make b?
    super();
    System.out.println(b); // you'll see "B" on the console
  }
}

Here is how that works.

When Weld’s CDI SE implementation starts up, it looks for a configuration item that indicates relaxed construction. This can be supplied in a few different ways, but the easiest way to supply it is by setting the org.jboss.weld.construction.relaxed System property to a textual representation of a boolean value (i.e. “true” or “false“). In Weld’s implementation of CDI SE, if you do nothing, the value of this configuration item is effectively true. In Weld’s implementation of CDI as found in application servers, the value of this configuration item is effectively false. This is worth noting.

First, the easy path: if for whatever reason relaxed construction is not enabled, then we stop here. My example above will fail and Weld will correctly tell you that it has no way to create a B instance because B is “unproxyable [sic]” according to the rules laid out by the specification.

Let’s assume that relaxed construction is enabled. Weld begins by looking for a ProxyInstantiator implementation:

https://github.com/weld/core/blob/be7382b01c4a56c54f92873c1c2ebf0445714bfe/impl/src/main/java/org/jboss/weld/bootstrap/WeldStartup.java#L335

That causes the create method to be called on the ProxyInstantiator.Factory class with access to the configuration subsystem:

https://github.com/weld/core/blob/151e1fedcc16d6d2dfec3ecdf1c095f75fdd995d/impl/src/main/java/org/jboss/weld/bean/proxy/ProxyInstantiator.java#L128-L129

The create method begins by assuming that the ProxyInstantiator that will be used is the DefaultProxyInstantiator:

https://github.com/weld/core/blob/151e1fedcc16d6d2dfec3ecdf1c095f75fdd995d/impl/src/main/java/org/jboss/weld/bean/proxy/ProxyInstantiator.java#L90

Then, if relaxed construction is enabled (which it is in this example), Weld will try two other hard-coded implementations in order, using the first “valid” one (we’ll see what that means shortly):

https://github.com/weld/core/blob/151e1fedcc16d6d2dfec3ecdf1c095f75fdd995d/impl/src/main/java/org/jboss/weld/bean/proxy/ProxyInstantiator.java#L91-L103

The first of these implementations is the UnsafeProxyInstantiator, whose instantiation strategy is to use the sun.misc.Unsafe class (redirected in modern JDKs to the jdk.internal.misc.Unsafe class) to create an instance of a class without using constructors at all:

https://github.com/weld/core/blob/151e1fedcc16d6d2dfec3ecdf1c095f75fdd995d/impl/src/main/java/org/jboss/weld/bean/proxy/UnsafeProxyInstantiator.java#L47-L49

This is worth noting because you might be logging proxy instantiation inside your zero-argument constructor, but if this strategy is selected for whatever reason, your constructor won’t be called. I’ve personally been burned by this and have now seen others burned by it as well.

If that UnsafeProxyInstantiator class is not available or can’t be used for any reason, then a second non-standard ProxyInstantiator implementation is tried instead, which uses sun.reflect.ReflectionFactory under the covers (which in modern JDKs is sort of redirected to jdk.internal.reflect.ReflectionFactory). This class will happily use a private zero-argument constructor:

https://github.com/weld/core/blob/151e1fedcc16d6d2dfec3ecdf1c095f75fdd995d/impl/src/main/java/org/jboss/weld/bean/proxy/ReflectionFactoryProxyInstantiator.java#L52-L60

(In this case of course your private zero-argument constructor will be called so any logging you do in there will show up.)

(You can see how it does this here:)

Finally, if neither of these non-standard instantiation strategies works, then the already-constructed DefaultProxyInstantiator is used instead, which does what you think it does, and adheres to the standard:

https://github.com/weld/core/blob/be7382b01c4a56c54f92873c1c2ebf0445714bfe/impl/src/main/java/org/jboss/weld/bean/proxy/DefaultProxyInstantiator.java#L42-L44

That is how the proxy object itself is created. Note that this does not create the actual underlying instance. For that, a private constructor is just fine (in Weld’s CDI implementations, anyway).

Note also that the underlying instance is not created until a business method on the proxy is invoked. Note as well that any method defined by java.lang.Object, other than toString(), is not considered a business method.

Hopefully this helps someone!

On Portability

I’m primarily (as always) talking Java, here. This post has a larger purpose but I’m not there yet. If all goes according to plan this post will make sense with some others to follow. At the moment it probably doesn’t make much sense. If that’s your thing, read on. You may be interested in the prior post in this series.

What is portability?

“Portable” just means capable of being carried. If you can pick it up and put it down, it’s portable. If you can take it from one “place” to another, it’s portable. My knapsack is portable. My piano is not, at least by me alone. Nor, really, is my crushing sense of self-doubt, but that’s another story.

Unless you’re just waving your hands, in computers and software when you’re talking about portability you have to talk about where the carrying is happening. Usually the word “across” or “between” is involved: A program might be portable across operating systems; a framework extension might be portable across different implementations of the framework; and so on.

In computers and software, we also usually add concepts of functionality and immutability to this. An application or a binary or a script is portable across computers or environments if, when you pick it up from one computer or environment and put it down on or into another computer or environment without changing it, it still works or can work. A pure Java application is portable across operating systems (or should be) because assuming you have java lying about at the destination you can pick up your CatsLOL.class file from a Windows computer and put it down on a Linux computer and run it in the same way without changing it. A binary resulting from a compiled and linked C program may not be (and usually is not) portable from one operating system to another.

A software component (like a library or a jar file or an individual Java class that is not a program) is also portable, even if you’re not switching operating systems or languages. You can pick a component up and put it (or a copy of it) down in multiple applications and incorporate it that way. In some sense you have “carried” it from wherever it was to several different destinations without changing it. This can happen even if you leave it in place: dynamic loading of libraries and classes is kind of a form of carrying, if you look at it right; the program doing the dynamic loading imports the library or class, thus notionally carrying it from one place to its own address space. “Reusability” is another (awful) word for this, along with other real winners like “composability”.

There are other sorts of more abstract things (let’s restrict ourselves to the software industry) that can be carried from one “place” to another and used without modification. If I leave one employer and go to another, I take my brain (hopefully) and experience with me, or at least the parts that are not signed away to the former employer somewhere. Publicly available stuff I learned from books, videos, websites, reference manuals and even certain source code may be portable from one work environment to another and I may be able to get up to speed more quickly as a result.

Things can be more or less portable. Sometimes something is 100% portable provided that the new environment it is being carried to is juuuuuuust right. If it is, then you put the thing down, it plugs into the new environment and runs exactly the same way as it did in the old environment. A pure Java program is a good example of this. A Java program that relies on a native library, by contrast, may find in the new environment that the environment-specific native library it needs for that environment is missing. If that library is put in the right place, then everything works. Another Java-centric example is: a Java framework extension or participant may be more or less portable depending on which features of the framework it uses or extends and how likely those features are to exist across the environments the Java framework extension or participant might be ported to. Then, even more abstractly, my knowledge of the JAX-RS API is fully portable from one job to another to the extent that the new job mandates proper use of the JAX-RS API. My knowledge of C++, on the other hand, probably isn’t very portable from one job to another because C++ permits lots of flavors and styles and maybe the old job and new job feature completely different styles of C++ programming. Also I’m joking about my knowledge of C++. So is everyone else.

To talk about software portability, particularly application portability, you often have to talk about platforms and platform implementations, because often what you’re really saying is that a given application is portable across a given platform’s multiple implementations. So then: an application is fully portable across platform implementations to the extent that there is more than one implementation of that platform and it doesn’t matter which platform implementation you pick to run it. Pick it up from one platform implementation; put it down in another: did it run? It’s portable! Congratulations! I probably didn’t write it.

So is a Jakarta EE application fully portable? It can be. If your application follows the platform specification, then you know it will (at least theoretically) run on platform implementations A and B in exactly the same way. If it uses features from one platform implementation, then you cannot necessarily pick it up from platform implementation A and run it unchanged in platform B, because platform B might not have those features.

Is a CDI SE application fully portable? This is sort of a nonsensical question, because CDI SE is not really a platform, but a framework. Regarding application portability, therefore, the answer is no. Now, certainly a CDI SE component (an extension, a bean, etc.) can be portable between CDI SE implementations and can be reused in various CDI SE applications: it can be picked up and carried from one CDI SE program and repackaged into another CDI SE program. If it uses Weld APIs, though, for example, then it is not fully portable across CDI SE implementations (like OpenWebBeans).

Is a Spring application fully portable? Yes and no. A Spring application packaged as a fat jar is just a Java program, so yes, you can port it from one Java environment to another, but given Java’s program portability promises this is almost tautological. Or, if you like: there aren’t two implementations of the Spring platform. From that perspective, therefore, a Spring application isn’t portable because there’s nothing to port it to. A Spring program packaged as a .war file, on the other hand, could conceivably be fully portable across Jakarta EE platform implementations provided that it carries all of its baggage with it (i.e. a Jakarta EE server will almost certainly not have any Spring libraries preinstalled). At this point, though, it just collapses into being a Jakarta EE application, so see above.

Is a DropWizard application portable? No. There’s nothing to port it to. There aren’t two implementations of a hypothetical DropWizard platform.

Is a Java application portable? Well, yes, but trivially so, and at a different sort of level. You can indeed run a Java program on different operating systems, and Java is a platform, so therefore a Java program is portable across operating systems. But given that we’re talking about portability across platforms, this foundational level of portability isn’t very interesting for this article.

Is a MicroProfile application portable? No, because there is no such thing as a MicroProfile platform, so there’s nothing to port it to. There are things that use MicroProfile APIs and even implement them but there’s no standard way to make some kind of hypothetical MicroProfile application and somehow run it in all of them.

Is an arbitrary binary portable? No; we’ve already covered that above.

If I make a binary using GraalVM’s native image facility, is the resulting binary portable? No, for the same reasons.

Is a Quarkus application portable? No; it’s just a binary. There’s nothing to port it to.

Is a Helidon SE application portable? No; it’s just a Java program that uses some libraries. There’s nothing to port it to.

Is a Helidon MP application portable? No; it too is just a Java program that uses some libraries, some of which happen to be partially specified. There’s nothing to port it to.

Is an OpenLiberty application portable? To the extent that it is a Jakarta EE application, yes; to the extent that it is not, no.

Is a Payara application portable? Same answer: to the extent that it is a Jakarta EE application, yes; to the extent that it is not, no.

Is an Oracle WebLogic Server application portable? Same answer.

OK, there are a lot of “no”s above. That’s not to say component and knowledge portability isn’t in play across the board. Some arbitrary examples:

  • A CDI component can be portable between CDI SE-, Helidon MP-, MicroProfile- and Jakarta EE-based applications
  • A Spring component can be portable between Spring applications
  • A JAX-RS resource class can be portable between DropWizard, Helidon MP, MicroProfile- and Jakarta EE-based applications
  • A component that uses org.eclipse.microprofile.config.Config is portable to any library or application that has MicroProfile Config available to it

…and so on.

More to come that may tie back to this article.

CreationalContext Observations

Here are some random observations concerning CreationalContext, a funky little architecturally polluting blemish on the surface of CDI’s otherwise pretty good set of APIs. (I’ve written before on this little nugget.)

There is no documentation that says what a CreationalContext is. The class javadoc reads, in total:

Provides operations that are used by the Contextual implementation during instance creation and destruction.

So its purpose is exactly that of its two operations, one of which (push()) can be properly implemented as a no-op as we’ll see below. That means its purpose is solely to house the release() method.

To portably create a CreationalContext, you use BeanManager#createCreationalContext(Contextual). For the purposes of destroying dependent objects, which is the interface’s sole documented purpose, the supplied Contextual is never used.

A CreationalContext is architecturally tightly coupled to a Context implementation for the Dependent scope. If you implement one, you have to implement the other because there is no portable way for an arbitrary Context implementing the Dependent scope to indicate to a CreationalContext that a dependent object needs to be tracked for subsequent destruction by the release() method. But in Weld you cannot supply your own instance of a Context for the Dependent scope, because the Weld-supplied one is always active, and there can be at most one active Context for a scope, and there is no way to remove a Context. So therefore you cannot supply your own implementation of CreationalContext in Weld unless you couple it to Weld interfaces and abstract classes…in which case why are you supplying one in the first place?

Weld implements CreationalContext by constructing a tree of them: each one tracks dependent objects added by its child. This means that Weld’s CreationalContext implementation is also tightly coupled to Weld’s implementation of BeanManager: every time a contextual reference is acquired, whether via injection or programmatically, a new “child” CreationalContext is created. This tree structure is not necessarily needed to perform dependent object cleanup (since, for example, OpenWebBeans implements CreationalContext without such a tree structure). The result is that in Weld many CreationalContextImpl objects get created that do nothing.

push() and release() have nothing to do with each other. In fact you can pass the TCK by implementing push() as a no-op. Many developers you talk to think that these methods are related. Almost nobody knows how to use them properly. You are, it turns out, supposed to always (probably within a finally block) call release() as the last thing you do in a custom bean’s destroy() method. Otherwise it is possible that your program will leak memory.

release() means, simply, “destroy dependent objects tracked by this CreationalContext“. Of course it may not be exactly this CreationalContext, because it might be a tree of such CreationalContexts. Or maybe it’s “destroy all dependent objects reachable from the creation of whatever it was that caused this CreationalContext to come into existence”. No specification language indicates whether release() must be idempotent. Obviously it would sure be nice if it were, so CDI implementations tend to make it so.

Remember that according to the specification a CDI implementation can destroy an unreferenced dependent object at any point by any means for any reason, so strictly speaking release() isn’t really a method that should have ended up in the specification (it’s an implementation detail). It’s clearly convenient so maybe that’s why it ended up in here.

The only time you need a CreationalContext is when you know that a contextual instance is going to be created. If you know that a contextual instance already exists, then the CreationalContext will never be used by the Context#get(Contextual, CreationalContext) method.

I often wonder why instead of this strange API there wasn’t a DependentContext interface, extending Context, that would allow you to add and destroy dependent object hierarchies, since we already know that Dependent is a special scope. There’s probably a good reason but I can’t think of what it is at the moment.

CreationalContext Deep Dive

What is a CreationalContext in CDI?

A perfect example of how naming things is the hardest problem in software engineering, really. The only method that it exposes that anyone should really be concerned with, release(), is used at destruction time, and has nothing to do with creating anything.

Here’s how I would describe it:

A CreationalContext is a bean helper that automatically stores @Dependent-scoped contextual instances on behalf of some other bean that has references to them, and ensures that they are cleaned up when that bean goes out of scope.

That’s basically it.

Consider a bean, B, that has a reference to a @Dependent-scoped bean, D. In Java terms, it might have a field like this:

@Inject
private D d;

Now, if the Bean implementation that created this B contextual instance has its destroy(T, CreationalContext<T>) method called, then B will be destroyed. B, in other words, will be the first argument.

When B is destroyed, you want to make sure that its dependent objects are also destroyed. But you also don’t want to burden the programmer with this. That is, you don’t want to make the programmer have to jump through some hoops inside B‘s logic somewhere to say “oh, when I’m destroyed, make sure to arrange for destruction to happen on my d field”. That should just happen automatically.

To allow this to happen automatically, CDI locates this logic inside a CreationalContext (yes, a “creational” context, even though we’re doing destruction. Naming is hard.). At the moment a CreationalContext is released, it has “in” it:

  • A bean that it is helping (usually)
  • A set of dependent instances that belong to the bean that it is helping
  • For each of those dependent instances some way to tie it to the Contextual (the Bean) that created it

When release() is called, the CreationalContext iterates over that set of dependent instances and their associated Beans and calls destroy() on each of those Beans.

So the programmer didn’t have to do any of this work. She just @Injected a D into a field and even if D is some sort of custom object it gets destroyed properly.

(It all follows from this that release() implementations must be idempotent and pretty much should never be called except from within a destroy() method of a custom bean. They also must work on only the bean that is being helped, and not on every dependent object “known” to the CreationalContext.)

OK, that’s all fine, but how did all these objects get “into” the CreationalContext in the first place?

When B was created, via a Bean‘s create(CreationalContext<T>) method, the container supplied that method with a new, empty CreationalContext that is associated with the Bean doing the creating. That is, prior to the create call, the container called beanManager.createCreationalContext(beanThatIsCreatingBInstances), and the resulting CreationalContext is supplied to beanThatIsCreatingBInstances‘s create method as its sole argument.

What does a custom Bean author here need to do with this CreationalContext as she implements the create method? The answer is: ignore it completely. That’s easy.

(More to the point: push(Object) does not, as you might be tempted to believe, stuff a @Dependent-scoped object into the CreationalContext such that release() will have any effect on it. The two methods are completely orthogonal. Around this point you should start getting suspicious: how does a dependent object get “into” an arbitrary CreationalContext anyway? An excellent question.)

In the case of managed beans—ordinary CDI beans, with @Inject annotations and whatnot processed by the container without any special funny business—remember that the container will take care of satisfying the injection points. So in the case of B with a D-typed d field injection point, the container will arrange for a D-type-producing bean to be invoked and then will automatically arrange for that dependent object to be stuffed into the CreationalContext.

That’s a lot to take in. Let’s try to break it down.

Recall that the container created a brand new CreationalContext to serve as the bean helper for B when it is about to call B‘s create method.

In order to “make” a B, the container is going to have to satisfy its D-typed injection point (the d field in our example).

To satisfy the D-typed injection point, the container will need to find out what scope is in effect. It will discover that the scope is @Dependent (since our example says so; presumably D is annotated with @Dependent which allows the container to call BeanManager#getContext(Class<? extends Annotation>)).

With the right Context in hand, the container will ask it for an appropriate D instance. The method that the container uses here is Context#get(Contextual<T>, CreationalContext<T>). Here, the container does not create a new CreationalContext. It passes the CreationalContext it has made for creating the B instance. That’s important.

A Context is responsible for doing basically whatever it wants to return an instance, so long as if a new instance is required it results (ultimately) from the return value of Contextual#create(CreationalContext<T>).

The @Dependent-scoped Context is obliged to create a new instance with every request, so it will dutifully invoke Contextual#create(CreationalContext<T>) and get back a new D instance. (If we pretend for just a moment that D is made by some kind of custom bean, the custom bean author never had to touch the CreationalContext when she implemented the create method. She probably just returned new D() or something similar.)

OK, so now the Context has possession of a new D object. But before it hands it back to the caller, it is going to stuff it in the supplied CreationalContext as a dependent instance. After all, the @Dependent-scoped Context always produces dependent objects that are tied to some “higher-order” bean, and we know that this is what CreationalContext instances are for: to store such dependent objects together with their referencing bean.

So it’s fine to say all this, but how does the @Dependent-scoped Context implementation actually add a dependent object to the CreationalContext? We’ve already seen the push(Object) method is not for this purpose.

It does it via proprietary means.

Weld, for example, does it via casting. This can get interesting since a user can supply her own @Dependent-scoped Context implementation: in order to add dependent objects herself she must tie her Context implementation to Weld.

You might think you could have your own @Dependent-scoped Context implementation that arranges for a CreationalContext to be used as a key into a Map of this kind of state. Then you wouldn’t be bound to a particular implementation of CDI. But of course if someone calls release() on a CreationalContext, you would have to somehow arrange to be notified of such a call, and that’s impossible.

So the upshot is that the CDI vendor, who returns CreationalContext implementations from BeanManager#createCreationalContext(Contextual<T>), is the only one who can supply any @Dependent-scoped Context implementations, no matter what the specification says.

Returning back to what the end user should “do” with a CreationalContext: the answer is basically ignore it. If you are writing a custom Bean implementation, then as the last operation in your delete implementation you can do this:

if (cc != null) {
  cc.release();
}

Otherwise, just leave the thing alone.

Decoding the Magic in Weld’s Instance Injection

I went down this rathole today and wanted to write it down.

In CDI, let’s say you have an injection point like this:

@Inject
@Flabrous // qualifier, let's say
private Instance<Frobnicator> flabrousFrobnicators;

The container is obligated to provide a built-in bean, whatever that is, that can satisfy any injection point whose raw type is Instance.

If you think about this for a moment or two you’ll realize that this is really weird. The container cannot possibly know “in advance” what injection points there will be, and so can’t actually create one bean for a @Default Instance<Frobnicator> and another for a @Flabrous Instance<Frobnicator>. So somehow its built-in bean has to be findable and appropriate for any possible combination of parameterized type (whose raw type is Instance) and sets of qualifiers.

Weld solves this problem by rewriting your injection point quietly on the fly (or at least this is one way to look at it). This was quite surprising and I was glad to finally find out how this machinery works.

For example, in the code above, as part of my injection point resolution request I have effectively said: “Hey, Weld, find me a contextual reference to a contextual instance of the appropriate bean found among all beans that are assignable to an Instance<Frobnicator>-typed injection point and that have the @Flabrous qualifier among their qualifiers.” Of course, Weld cannot actually issue the bean-finding part of this request as-is, because there is no such bean (how could it possibly pre-create an Instance<Frobnicator>-typed bean with @Flabrous among its qualifiers?). So how does this work, exactly? Something must be going on with @Any but it’s nowhere to be seen here and isn’t applied by default to injection points.

It turns out Weld recognizes a class of beans that they call façade beans for which all injection requests are effectively rewritten (during the bean-finding part of the resolution process). Instance is one kind; Event is another; Provider is another and so on—you can see why they’ve decided these are special sorts of things.

At any rate, when you ask for a façade bean, the request that is made for the bean itself uses only the @Any qualifier, no matter what you’ve annotated your injection point with. All beans, including built-in ones, have the @Any qualifier, so the one true container-provided Instance bean will be found. And there’s our answer.

OK, that’s fine, but in the example above now we have a qualifier, @Flabrous, that we actually want to use, or we wouldn’t have gone to all this trouble. How does that get applied, given that it is ignored in the bean sourcing part of the injection resolution request?

Weld has tricked its own innards into supplying what is technically an inappropriate bean—it pretended that we asked for an @Any-qualified Instance<Frobnicator> bean even though we didn’t—but now that it has it, it can ignore whatever qualifiers the bean bears (@Default and @Any, as it turns out, and none other) because they’re no longer relevant once the bean is found. All that matters now is contextual instance mechanics.

Because Instance and Event and Provider and other façade beans are required to be in @Dependent scope, it turns out that the current injection point is available and can be used internally by the bean itself to find out what qualifiers are in effect so that it can create an appropriate contextual instance. And that’s exactly what happens: the bean supplied by Weld is an extension of AbstractFacade which uses the injection point to determine what qualifiers are in effect.

This whole process is of course deeply weird and I’d imagine that it or derivative effects rely on a hard-coded list of façade beans somewhere. Sure enough, here’s an example of the sort of thing I mean.

Another way to approach this sort of thing might be to introduce a super-qualifier or something instead that says, hey, if a bean is qualified with this super-qualifier then it matches all qualifier comparison requests (which is really what’s going on here).

Anyway, I hate magic and am glad to have found out how this works!

ByteBuddy and private static final fields

Boy is this amazingly difficult. I’m writing it here so I won’t forget. I hope this helps someone else. Hopefully, too, there is a less verbose way to accomplish this.

The excerpt below does private static final MethodHandle gorp = MethodHandles.lookup().findStatic(TestPrivateStaticFinalFieldInitialization.class, "goop", MethodType.methodType(void.class)); in ByteBuddy. *** goop shows up on the console at the end. I have a StackOverflow post in case this changes.

Awful formatting courtesy of your friends at WordPress:

// Excerpt from JUnit Jupiter unit test whose class is named
// TestPrivateStaticFinalFieldInitialization:

  @Test
  final void testAll() throws Throwable {

    final MethodDescription findStaticMethodDescription = new TypeDescription.ForLoadedType(MethodHandles.Lookup.class)
      .getDeclaredMethods()
      .filter(ElementMatchers.named("findStatic"))
      .getOnly();
    
    final MethodDescription methodHandlesLookupMethodDescription = new TypeDescription.ForLoadedType(MethodHandles.class)
      .getDeclaredMethods()
      .filter(ElementMatchers.named("lookup"))
      .getOnly();

    final MethodDescription methodTypeMethodTypeMethodDescription = new TypeDescription.ForLoadedType(MethodType.class)
      .getDeclaredMethods()
      .filter(ElementMatchers.named("methodType")
              .and(ElementMatchers.isStatic()
                   .and(ElementMatchers.takesArguments(Class.class))))
      .getOnly();
    
    final ByteBuddy byteBuddy = new ByteBuddy();
    DynamicType.Builder<?> builder = byteBuddy.subclass(Object.class);
    builder = builder
      .defineField("gorp", MethodHandle.class, Visibility.PRIVATE, Ownership.STATIC, SyntheticState.SYNTHETIC, FieldManifestation.FINAL)
      .invokable(ElementMatchers.isTypeInitializer())
      .intercept(MethodCall.invoke(findStaticMethodDescription)
                 .onMethodCall(MethodCall.invoke(methodHandlesLookupMethodDescription))
                 .with(new TypeDescription.ForLoadedType(TestPrivateStaticFinalFieldInitialization.class))
                 .with("goop")
                 .withMethodCall(MethodCall.invoke(methodTypeMethodTypeMethodDescription)
                                 .with(new TypeDescription.ForLoadedType(void.class)))
                 .setsField(new FieldDescription.Latent(builder.toTypeDescription(),
                                                        "gorp",
                                                        ModifierContributor.Resolver.of(Visibility.PRIVATE,
                                                                                        Ownership.STATIC,
                                                                                        SyntheticState.SYNTHETIC,
                                                                                        FieldManifestation.FINAL).resolve(),
                                                        TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(MethodHandle.class),
                                                        Collections.emptyList())));
    final Class<?> newClass = builder.make().load(Thread.currentThread().getContextClassLoader()).getLoaded();
    final Field gorpField = newClass.getDeclaredField("gorp");
    gorpField.setAccessible(true);
    final MethodHandle methodHandle = (MethodHandle)gorpField.get(null);
    assertNotNull(methodHandle);
    methodHandle.invokeExact();
  }

  public static final void goop() {
    System.out.println("*** goop");
  }

On Terminology

The hardest thing in software engineering is naming things.

We have some conventions, but not a lot. Many of those conventions come from design patterns. For example, we have builders and adapters and factories and visitors and so on.

But there are strikingly few conventions about how to name other things. For example, when implementing an interface that consists of a single method that can return something either new or old, what should we call it? The JDK has settled on the term Supplier, which maybe is fine, but then the method is called get, rather than supply. Does get really capture what a Supplier does? Again, naming things is hard.

As another example, sometimes factories assemble things out of raw materials—and then simply return what they’ve assembled, over and over. Is that actually what a factory does? No, it is not. Naming things is hard.

My own personal dictionary includes these concepts and I try to use them very carefully in my own software:

  • A supplier may create something or return a single instance of a prefabricated something, or switch arbitrarily. I avoid producer or provider since they don’t really convey why something is being retrieved or made: when something is supplied, by contrast, it is because there is a need, and the supplying fulfills the need.
  • A factory always creates something.
  • If something is backed, then it is implemented in terms of something else. This lets me do things with the adapter pattern but adapter is a terrible word that doesn’t tell you what is being adapted to what and hence which aspect is more primal.
  • If something is default, then it is usually a straightforward something that can be extended or overridden or otherwise made more complicated or performant or interesting. I try to avoid simple, since simplicity should be an emergent property, not something legislated.
  • I try to avoid the word provision since for very strange reasons in the computer industry it often means to create something out of thin air, rather than its English meaning, which is to stock. (When you provision your pantry, you don’t build the pantry, you put cans on its shelves.)
  • Priority is always always always largest-number-wins. Unlike most bug systems I’ve worked with, in English the highest priority problem is the one deserving the most attention. (If you want smallest-number-wins, you’re probably looking for rank. Avoid the use of ordinal entirely since many projects use it to mean priority, and others use it to mean something roughly akin to an indicator of which item should come out of an array first.)
  • An arbiter is something that takes in two or more inputs that may have some ambiguity (or not) and performs arbitration on them, selecting a single output for further processing.
  • If I am tempted to use the word module in any way, shape or form, then I know I have failed spectacularly in every possible way. Something that is a module is inscrutable, which is a fancy way of saying that you really have no idea what it is. Component is rarely any better. Feature is even worse.
  • Name is usually an indication that I haven’t thought the problem domain through well enough. Same goes for description. Both have inherent localization issues as well.
  • A facet is a selection of notional attributes of some other thing that go together. This is a nice terminology pattern to use to keep your classes small and to encourage composition.
  • Helper is right out. Same goes for util or utils or utility. If I am tempted to write any of these, I write crap instead so that it is quite clear that that is what I am creating.
  • In the realm of configuration, a setting is a name. A value or a setting value is a value for a setting. When you have many settings, you have many names, not many values, or at least you’re not talking about the values. (I deliberately try to avoid configuration and property since these are massively overloaded and confusing: is configuration a bunch of something, or just one thing? Is a property a name-value pair, or just a name? Or just a value?)

I’m sure there’s more where this came from. What are some of your terminology systems?