...
Another API change is replacing existing Builder<T>
classes with java.util.function.Supplier<T>
. To support backward compatibility, when a static factory method returns an object that implements Builder<T>
or Supplier<T>
, then that instance is injected and used as a factory for its type T
.
The Core plugin type is updated to use this injection API so that in addition to the existing support for injecting @PluginElement
, @PluginAttribute
, @PluginBuilderAttribute
, @PluginValue
, @PluginNode
, and @PluginConfiguration
instances, this is extended to support for injection via fields, methods, and constructors, along with injection of any other instances Injector has bindings for or knows how to create bindings on demand for. Classes that can have on-demand bindings are injectable classes which are classes with either one @Inject
constructor or a no-args constructor. Implementations of LogEventFactory
are a good example of injectable classes where the choice of class is configurable at runtime, though the dependency chain involved can be made explicit while removing boilerplate dependency injection code to where this class is relevant. An abbreviated example of what a Supplier<LoggerConfig>
class may look like:
Code Block |
---|
public class Builder implements java.util.function.Supplier<LoggerConfig> {
// ...
// note that methods with qualified parameters are implicitly @Inject
public Builder withLevel(@PluginAttribute Level level) {
this.level = level;
return this;
}
public Builder withLoggerName(
@Required(message = "Loggers cannot be configured without a name") @PluginAttribute String name) {
this.loggerName = name;
return this;
}
public Builder withRefs(@PluginElement AppenderRef[] refs) {
this.refs = refs;
return this;
}
public Builder withConfig(@PluginConfiguration Configuration config) {
this.config = config;
return this;
}
public Builder withFilter(@PluginElement Filter filter) {
this.filter = filter;
return this;
}
// need to specify @Inject here because LogEventFactory is an unqualified bean
@Inject
public Builder setLogEventFactory(LogEventFactory logEventFactory) {
this.logEventFactory = logEventFactory;
return this;
}
@Override
public LoggerConfig get() {
// ...
}
}
|
Keys and Bindings
The Key<T>
class provides a way to identify plugins by type, optional qualifier, and a name. Existing @PluginAttribute
and @PluginValue
annotations are natural qualifier types, though given that these annotations are duplicated in log4j-plugins and log4j-core, a more generic mechanism is needed to treat these as equivalent. This is where the name aspect of a Key
comes in; all named-style qualifier annotations are treated as @Named
qualifiers. The ConfigurationInjector
and ConfigurationBinder
API in log4j-plugins is replaced with a simpler strategy for supplying a (possibly converted) value for a particular Node
instance. Node
s can be configured via Injector
which is where general dependency injection occurs along with binding of provided configuration attributes in the Node
instance. Annotation-handling strategies for configuration injection are replaced with a parsing strategy while strategies for binding are inlined into the general logic of Injector
.
...