Properties¶
The property system is a core system of JDA-Commands. Its purpose is...
- to allow the dynamic and advance configuration of JDA-Commands through our builder and extension system
- to serve as a central collection point for all values that the user can get during runtime
You can think of it like a really primitive Dependency Injection framework that comes without any annotations.
At its heart, there is basically a big Map mapping properties to different PropertyProviders which then
provide the value of the property.
Note on Propane¶
The property and introspection system of JDA-Commands is based on
Propane.
In most cases, you won't directly access propane but the wrappers around it provided by JDA-Commands
like JDACIntrospection, JDACProperty etc. These are generated by propane as specializations
of general types like IntrospectionSkeleton and Property. If you debug your bot or encounter any problems, it may be helpful
to visit the documentation or source code of Propane.
Properties¶
As said already, basically the whole system is about properties - but what are they really? Well, properties, as the name says, are properties of JDA-Commands as a whole. They can be either:
- a config option to adjust the behaviour of JDA-Commands
- an implementation of exposed services
- or a service provided by the framework that is exposed to the user
Because they're all properties of JDA-Commands, they come predefined as public static final in the Property class
and can be accessed by the user. The user can't create own properties!
Categories of Properties¶
To ensure an intuitive configuration experience, properties are primarily categorized in 3 groups:
- user settable through JDACBuilder -> only configurable by using the designated
JDACBuildermethod - user settable + loadable from extension -> above applies plus values can be provided by
Extensions - provided -> services that are provided by JDA-Commands; the user can use but not create/replace them
Types¶
Due to the diverse nature of properties, JDA-Commands defines 3 different types of properties:
Singleton¶
A SingletonProperty can only have one final instance. For example Localizer is such a property.
To decide which value will be used, the priorities of all JDACPropertyProviders are compared and
the highest will be chosen as the provider for this value. To learn more about this, take a look here
Enumeration¶
A EnumerationProperty is basically a Collection, that will consist of the combined values of
all JDACPropertyProvider for this property.
Each JDACPropertyProvider for property T of type enumeration returns an Collection<T>.
The returned collections of all JDACPropertyProviders are then combined into one
and used as the final value for this property.
Map¶
A MappingProperty is similar to EnumerationProperty except it uses a Map instead a Collection.
The values of all JDACPropertyProviders are accumulated, while the one with higher priority
takes precedence.
Each JDACPropertyProvider for a property K, V of type map returns an Map<K, V>.
The returned maps of all JDACPropertyProviders are then combined into one
and used as the final value for this property.
If multiple JDACPropertyProviders are setting a value for the same key, then
the value of the provider with the highest priority is chosen.
Fallback/ Default Values
For some properties (like JDACProperty#CLASS_FINDER) the default value will be completely
overridden instead of accumulated although the propertys type is enumeration or map.
Whether the default values will be overridden or accumulated together with other values is defined by their fallback strategy
PropertyProvider¶
A JDACPropertyProvider provides a value according to the type of the Property.
That can either be just a simple instance T, an enumeration Collection<T> or
a map Map<K, V>.
Priority¶
Furthermore, a JDACPropertyProvider has a priority that controls the order
in which the values are accumulated. (only important for type singleton and map).
Warning
The priorities ranging from 0 to 100 and the priority Integer#MAX_VALUE are reserved by JDA-Commands.
Internally, we use them as following:
- 0 -> fallback/default values provided by JDA-Commands
Integer#MAX_VALUE-> all values manually set by the user inJDACBuilder
Value Creation¶
An important fact of JDACPropertyProviders is, that the value is computed lazily later in the resolution process,
not when the JDACPropertyProvider is constructed. If another JDACPropertyProvider is chosen instead of yours (due to higher priority),
that means that sometimes your value supplier won't be called at all.
However, this allows you to get the values of other properties as dependencies, because the JDACIntrospection instance used to
call the value supplier is passed to this supplier.
Note
If a cycling dependency is detected during the resolution of dependencies, an exception will be thrown providing information on how the recursion occurred.
Example of JDACPropertyProvider for JDACProperty#CLASS_FINDER.¶
public JDACPropertyProvider<?> provider() {
return new JDACPropertyProvider(
Property.CLASS_FINDER,
Priority.of(200), // just some random non reserved priority
Foo.class, //(1)
ctx -> List.of(new CustomClassFinder(ctx.get(JDACProperty.PACKAGES))) //(2)
);
}
- The JDACPropertyProvider#owner() value is just used for debugging purpose. The name of the class will for example be displayed in the cycling dependencies exception messages.
- The values for
JDACProperty#PACKAGESwill be returned. You can get the value of any property through this method.