Accessing CDI from simple objects?

Viewed 59

Assume I have a configuration class accessible via the stock CDI that defines some application-wide parameters:

@ApplicationScoped
class AppConfig {
  public double getMaxAllowedBrightness() { ... }
};

And I have a simple class for my data objects:

class LightSource {
  double brightness;
  ...

  boolean isValid() {
    double maxAllowedBrightness = ...; // Somehow use AppConfig#getMaxAllowedBrightness() here
    return brightness <= maxAllowedBrightness;
  }
}

How can my data object access the single AppConfig instance?

Somehow I hate the idea of autowiring AppConfig into every single data object (there are lots of them). Is there any other way to get access to AppConfig in the above example from my data object? What's the best pattern to use here?

2 Answers

The simplest example is a runtime lookup akin to:

import jakarta.enterprise.inject.spi.CDI;
CDI.current().select(cls).get();

With cls being the class that you're looking up. (Note the package name, this is the latest version of CDI 2.x in the new jakarta namespace, the original is in javax.)

It gets more detailed from there, but that's the gist of it.

Note, that semantically there's little difference between autowiring something and doing a runtime lookup, especially for something mostly static at the instance level. It's still a dependency. You still have to touch the code of the classes to pull it off.

A nice thing of relying on the autowiring is that you can disable it situationally, and the class reverts to a simple bean, that you can do with what you will. Coding in the lookup, it's a little bit more than that.

Dynamic lookup is more for special circumstances.

On my current project, our team has been doing this using the @Value annotation. In our case, we have all the properties in a properties bean, which I'll call mainAppConfiguration. The bean is populated from a properties file like main-app-config.properties (which was read into the bean with a Properties prop = new Properties().load(mainAppConfigFilePath) method.

Assuming you have something like that set up, then we inject the properties into the classes that need them using a little SpEL magic something like:

  private Integer refreshRateSeconds;
  
  @Value("#{ mainAppConfiguration.getProperties()['funny-property-base-name.refreshRateSeconds'] }")
  public void setRefreshRateSeconds(Integer refreshRateSeconds) {
    if (refreshRateSeconds == null) {
      throw new IllegalArgumentException("Required config property 'funny-property-base-name.refreshRateSeconds' was not found"));
    }
    this.refreshRateSeconds = refreshRateSeconds;
  }

Baeldung has examples (without defaults) and more with defaults.

Related