Configuration des Nodes

Dans la mémoire, la configuration est représentée à l’aide de ConfigurationNodes. Un ConfigurationNode conserve une valeur (Comme un nombre, une chaîne de caractères ou une liste) ou a des nodes enfants, une structure de configuration arborescente. Lorsque vous utilisez un ConfigurationLoader pour charger ou créer de nouvelles configurations, il retournera la node racine. Il est recommandé que vous gardiez toujours une référence vers cette node stockée quelque part.

Note

Selon le ConfigurationLoader utilisé, vous pouvez même obtenir un CommentedConfigurationNode, qui, en plus du comportement normal du ConfigurationNode est capable de conserver un commentaire qui va persister sur le fichier de configuration enregistré.

Valeurs

Valeurs basiques

Les types de valeurs basiques comme les int, double, boolean ou String ou chacun leur propre méthode getter qui retournera valeur ou une valeur par défaut si la node ne contient pas de valeur de ce type. Vérifions si l’administrateur du serveur veut que le module blockCheats de notre plugin soit activé en vérifiant la valeur au chemin modules.blockCheats.enabled.

boolean shouldEnable = rootNode.getNode("modules", "blockCheats", "enabled").getBoolean();

Oui, c’est vraiment aussi simple que cela. Comme dans l’exemple ci-dessus, les méthodes comme ConfigurationNode#getInt(), ConfigurationNode#getDouble() ou ConfigurationNode#getString() existent pour vous permettre de récupérer facilement une valeur de ce type.

Pour définir une valeur basique à une node, utilisez juste la méthode ConfigurationNode#setValue(Object). Ne soyez pas confus qu’il accepte un Object - cela signifie qu’il peut prendre n’importe quoi et qu’il va déterminer comme procéder de lui-même.

Imaginez que le module blockCheats soit désactivé par une commande de l’utilisateur. Ce changement devra être réflété dans la configuration et peut se faire comme suit :

rootNode.getNode("modules", "blockCheats", "enabled").setValue(false);

Avertissement

Les autres types que les types de valeurs de base ne peuvent pas être traités par ces fonctions basiques, et doivent à la place être lues et écrites en utilisant la méthode de (dé)sérialisation décrite ci-dessous. Les types basiques sont ceux qui sont gérés nativements par l’implémentation sous-jacente du format de fichier utilisé par le ConfigurationLoader, mais généralement incluent les types de données primitifs, ainsi que les Strings et les Lists et les Maps de types basiques.

(Dé)Sérialisation

Si vous essayez de lire ou d’écrire un objet qui n’est pas un des types de bases mentionnés ci-dessus, vous devrez passer tout d’abord à travers la désérialisation. Dans l”ConfigurationOptions utilisé pour créer votre ConfigurationNode racine, il y a une collection de TypeSerializers que Configurate utilise pour convertir vos objets en un ConfigurationNode et vice versa.

Pour dire à Configurate quel type il doit traiter, nous devons fournir un TypeToken de guava. Imaginez que nous voulons lire le UUID d’un joueur depuis la node de configuration towns.aFLARDia.mayor. Pour faire ceci, nous devrons appeler la méthode getValeur() tout en fournissant un TypeToken représentant la classe UUID.

import java.util.UUID;

UUID mayor = rootNode.getNode("towns", "aFLARDia", "mayor").get(TypeToken.of(UUID.class));

Cela demande à Configurate de localiser le bon TypeSerializer pour les UUIDs et de l’utiliser pour convertir la valeur stockée en un UUID. Le TypeSerializer (et par extension la méthode ci-dessus) peut levé une ObjectMappingException si il rencontre des données incomplètes ou invalides.

Maintenant si nous voulez écrire un nouvel UUID vers ce node de configuration, la syntaxe est très similaire. Utilisez la méthode setValue() avec un TypeToken et l’objet que vous souhaitez sérialiser.

rootNode.getNode("towns","aFLARDia", "mayor").setValue(TypeToken.of(UUID.class), newUuid);

Note

Sérialiser une valeur va lever une ObjectMappingException si aucun TypeSerializer pour le TypeToken donné ne peut être trouvé.

Pour des classes simples comme UUID, vous pouvez simplement créer un TypeToken en utilisant la méthode statique TypeToken.of(). Mais quand la classe que vous voulez utiliser possède ses propres types de paramètres (comme Map<String,UUID>) la syntaxe devient un peu plus compliquée. Dans la plupart des cas vous saurez exactement quel types de paramètres ça va être au moment de la compilation, donc vous pouvez juste créer un TypeToken en tant que classe anonyme : new TypeToken<Map<String, UUID>>(). De cette façon, même les types génériques peuvent aisément être écrits et lus.

Voir aussi

Pour plus d’informations à propos des TypeTokens, référez-vous à la documentation guava

Les types sérialisables à l’aide de ces méthodes sont :

  • N’importe quelle valeur de base (voir ci-dessus)

  • N’importe quelle Liste ou Map de types sérialisables

  • Les types java.util.UUID, java.net.URL, java.net.URI et java.util.regex.Pattern

  • Tous les types qui ont été faits sérialisables comme décrit sur la page de sérialisation de la configuration

Par défaut

Contrairement à l’API de Sponge, la librairie Configurate n’utilise pas l”Optional pour les valeurs qui pourraient ne pas être présentes, mais plutôt null. Alors que les getters des méthodes primitives (comme getBoolean() ou getInt()) peuvent retourner false ou 0, ceux qui retournent un objet (comme getString()) vont retourner null si aucune valeur n’est présente. Si vous ne voulez pas gérer manuellement ces cas spéciaux, vous pouvez utiliser les valeurs par défaut. Chaque méthode getXXX() discutée plus haut a une forme surchargée acceptant un paramètre supplémentaire comme valeur par défaut.

Jetons un coup d’oeil à l’exemple pour la lecture d’une valeur booléenne à nouveau.

boolean shouldEnable = rootNode.getNode("modules", "blockCheats", "enabled").getBoolean();

Cet appel va retourner false si la valeur false est sauvegardé dans la configuration ou si la valeur n’est pas présente dans la configuration. Étant donné que ces deux cas ne sont pas distinguables nous n’avons pas de moyen simple de définir notre variable à false seulement si c’est la valeur spécifiée dans la configuration. Sauf si nous spécifions true comme valeur par défaut.

boolean shouldEnable = rootNode.getNode("modules", "blockCheats", "enabled").getBoolean(true);

De la même façon, vous pouvez spécifié des valeurs par défaut sur n’importe quelle valeur que vous récupérer depuis la configuration, évitant ainsi les null ou les ObjectMappingException causés par l’absence de la valeur entière. Cela peut aussi fonctionner sur la désérialisation de la méthode getValue(). Quelques exemples :

String greeting = rootNode.getNode("messages", "greeting").getString("FLARD be with you good man!");

UUID mayor = rootNode.getNode("towns", "aFLARDia", "mayor")
                        .getValue(TypeToken.of(UUID.class), somePlayer.getUniqueId());

Une autre application utile de ces valeurs par défaut, c’est qu’ils peuvent être copiés vers votre configuration si nécessaire. Lors de la création de votre node racine de configuration, vous pouvez créer votre ConfigurationOptions avec setShouldCopyDefaults(true). Par la suite, quand vous fournirez une valeur par défaut, Configurate vérifiera d’abord si la valeur que vous essayerez de récupérer est présente, et si elle n’e l’est pas, il écrira la valeur par défaut sur la node avant de retourner la valeur par défaut.

Supposons que votre plugin s’exécute pour la première fois et que le fichier de configuration n’existe pas encore. Vous essayez de le charger avec ConfigurationOptions qui permet de copier les valeurs par défaut et de récupérer une node de configuration vide. Maintenant vous exécutez la ligne rootNode.getNode("modules", "blockCheats", "enabled").getBoolean(true). Comme la node n’existe pas encore, Configurate la crée et écrit la valeur true dessus selon les directives du ConfigurationOptions avant de la retourner. Lorsque la configuration est alors terminée, la valeur true va rester sur la node sans jamais être définie explicitement.