Skip to content

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:

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:

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)
    );
}
  1. 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.
  2. The values for JDACProperty#PACKAGES will be returned. You can get the value of any property through this method.