Welcome to Bukkit France

Inscrivez-vous maintenant pour profiter d'un accès total à tout le contenu offert par la meilleur communauté Bukkit française ! Une fois inscrit et connecté, vous pourrez contribuez à la communauté en postant vos propres sujets et questions ou en répondant à ceux existants. Vous pourrez aussi customiser votre profil, recevoir des points de réputations, communiquer avec les autres membres via le chat, et plus encore! 

  • Annonces

    • Pskyco

      Bukkit France passe sous Discord !   20/02/2016

      Bukkit France est désormais passé sur Discord, au revoir donc notre vieux Teamspeak ! Téléchargez le client et venez nous rejoindre sur notre salon en suivant les instructions suivantes.
TheElectronWill

[LIB] Night-Config : les configurations en Java

8 messages dans ce sujet

logo.png

 

Bonjour à tous !

Aujourd'hui je vous présente ma lib de gestion des configurations: Night-Config !

Il en existe déjà beaucoup, mais j'avais envie de quelque chose de plus simple à utiliser, avec les fonctionnalités les plus utiles et de bonnes performances.

 

Tout n'est pas terminé, ce n'est pour l'instant qu'une version Bêta.

À terme, les formats suivants seront supportés :

 

Le projet est disponible sur Github.

 

 

Les bases

L'interface Config définit les méthodes disponibles pour toutes les configurations, notamment des getters & setters pour les valeurs : get[Value/Int/Boolean/String/...](path) et set[Value/Int/...](path, value)

Le chemin des valeurs peut être :

  • une String dans laquelle chaque partie du chemin est séparée par un point. Par exemple "a.b.c" donne cette structure: a { b { c } }
  • une List<String> dont chaque élément est une partie du chemin. Par exemple une liste "a", "b", "c" donne la même structure que précédemment.

 

Exemple :

Config conf = new SimpleConfig();
conf.setString("a.b.c", "abc");
conf.setInt("five", 5);
conf.setDouble("pi", Math.PI);
conf.setList("list", Arrays.asList("a", "b", "c");

String str = conf.getString("a.b.c");
int five = conf.getInt("five");
double pi = conf.getDouble("pi");
List<String> list = conf.getList("list");//Pas besoin de cast, et il n'y a pas de warning !

 

Fichiers de configuration

Il suffit d'utiliser une instance de FileConfig. Il y en aura une pour chaque type de fichier supporté (JsonConfig, TomlConfig, etc)

Voici un exemple avec une configuration JSON :

FileConfig conf = new JsonConfig();
File configFile = new File("path/to/config.json");
try {
   conf.readFrom(configFile);//lecture du fichier dans la config
   conf.writeTo(configFile);//écriture de la config dans le fichier
} catch (IOException ex) {
   //ERREUR
}

 

Pour personnaliser le résultat JSON (le type d'indentation par exemple), vous pouvez utiliser un FancyJsonWriter :)

Config conf;
try (Writer fileWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8))) {
   CharacterOutput output = new WriterOutput(fileWriter);
   FancyJsonWriter.Builder builder = new FancyJsonWriter.Builder();
   builder.indent("    ");//indentation de 4 espaces au lieu de la tabulation qui est le réglage par défaut
   //autres réglages
   FancyJsonWriter writer = builder.build(output);
   writer.writeJsonObject(conf);
}

 

Et si vous avez peu de réglages à faire (ou si vous aimez les grosses chaînes d'appel de fonctions :D) vous pouvez aussi créer le Writer comme ça :

FancyJsonWriter writer = new FancyJsonWriter.Builder().indent("    ").build(output);

 

 

Vérification et correction automatique des configurations

Oui vous avez bien lu : correction automatique des configurations ! Concrètement, tout ce que vous avez à faire est de créer une spécification pour votre config : définir quels chemins doivent exister et quelles valeurs sont correctes. Vous pourrez ensuite, avec un simple appel de méthode, vérifier que votre configuration est correcte et/ou la corriger automatiquement.

Pour tout ça on utilise une ConfigSpecification :

ConfigSpecification spec = new ConfigSpecification();
spec.defineInt("int", 0, -20, 20);//"int" doit être un int compris entre -20 et 20 (inclus). La valeur par défaut est 0
spec.defineString("string", "default", "possibleValueA", "possibleValueB", "possibleValueC", "default");//"string" doit être une String égale à
//"possibleValueA", "possibleValueB", "possibleValueC" ou "default". La valeur par défaut est "default"

boolean isValid = spec.check(conf);//true si et seulement si la configuration 'conf' est correcte
spec.correct(conf);//corrige la configuration

La correction fonctionne ainsi :

  • Toute valeur qui ne devrait pas exister est supprimée
  • Toute valeur qui devrait exister mais qui est incorrecte est remplacée par la valeur par défaut
  • Toute valeur manquante est ajoutée, et la valeur par défaut est utilisée.

 

 

Conversion objet/config

Night-Config peut convertir une configuration en objet Java et vice-versa, à l'aide des classes du paquet reflection.

Et pas besoin d'annoter la classe ni de lui faire implémenter une interface spécifique :)

Un petit exemple avec la classe suivante :

public class MyObject {
   int integer;
   double decimal;
   String string;
   List<String> stringList;
   Config config;
   MyObject subObject;
}

 

Conversion config -> MyObject :

Config conf = new SimpleConfig();
conf.setDouble("decimal", Math.PI);
conf.setString("string", "value");
conf.setList("stringList", list1);
conf.setConfig("config", config1);
conf.setInt("subObject.integer", -1);
conf.setDouble("subObject.decimal", 0.5);
conf.setString("subObject.string", "Hey!");
conf.setList("subObject.stringList", list2);
conf.setConfig("subObject.config", config2);
conf.setConfig("subObject.subObject", null);

ConfigToObjectMapper coMapper = new ConfigToObjectMapper();
MyObject objectInstance = coMapper.map(conf, MyObject.class);

 

Conversion MyObject -> Config :

MyObject object = new MyObject();
// [...] définition des variables de l'objet
ObjectToConfigMapper ocMapper = new ObjectToConfigMapper();
Config conf = new SimpleConfig();
ocMapper.map(object, conf);

 

Modifié par TheElectronWill
colorisation grâce à IntelliJ :)
6 personnes aiment ça

Partager ce message


Lien à poster
Partager sur d’autres sites

Pas mal :) Je vais l'essayer merci pour celle lib !

Partager ce message


Lien à poster
Partager sur d’autres sites
Config conf = new SimpleConfig();
conf.setString("a.b.c", "abc");
conf.setInt("five", 5);
conf.setDouble("pi", Math.PI);
conf.setList("list", Arrays.asList("a", "b", "c");

String str = conf.getString("a.b.c");
int five = conf.getInt("five");
double pi = conf.getDouble("pi");
List<String> list = conf.getList("list");//Pas besoin de cast, et il n'y a pas de warning !
FileConfig conf = new JsonConfig();
File configFile = new File("path/to/config.json");
try {
   conf.readFrom(configFile);//lecture du fichier dans la config
   conf.writeTo(configFile);//écriture de la config dans le fichier
} catch (IOException ex) {
   //ERREUR
}
Config conf;
try (Writer fileWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8))) {
   CharacterOutput output = new WriterOutput(fileWriter);
   FancyJsonWriter.Builder builder = new FancyJsonWriter.Builder();
   builder.indent("    ");//indentation de 4 espaces au lieu de la tabulation qui est le réglage par défaut
   //autres réglages
   FancyJsonWriter writer = builder.build(output);
   writer.writeJsonObject(conf);
}
FancyJsonWriter writer = new FancyJsonWriter.Builder().indent("    ").build(output);
ConfigSpecification spec = new ConfigSpecification();
spec.defineInt("int", 0, -20, 20);//"int" doit être un int compris entre -20 et 20 (inclus). La valeur par défaut est 0
spec.defineString("string", "default", "possibleValueA", "possibleValueB", "possibleValueC", "default");//"string" doit être une String égale à
//"possibleValueA", "possibleValueB", "possibleValueC" ou "default". La valeur par défaut est "default"

boolean isValid = spec.check(conf);//true si et seulement si la configuration 'conf' est correcte
spec.correct(conf);//corrige la configuration
public class MyObject {
   int integer;
   double decimal;
   String string;
   List<String> stringList;
   Config config;
   MyObject subObject;
}
Config conf = new SimpleConfig();
conf.setDouble("decimal", Math.PI);
conf.setString("string", "value");
conf.setList("stringList", list1);
conf.setConfig("config", config1);
conf.setInt("subObject.integer", -1);
conf.setDouble("subObject.decimal", 0.5);
conf.setString("subObject.string", "Hey!");
conf.setList("subObject.stringList", list2);
conf.setConfig("subObject.config", config2);
conf.setConfig("subObject.subObject", null);

ConfigToObjectMapper coMapper = new ConfigToObjectMapper();
MyObject objectInstance = coMapper.map(conf, MyObject.class);
MyObject object = new MyObject();
// [...] définition des variables de l'objet
ObjectToConfigMapper ocMapper = new ObjectToConfigMapper();
Config conf = new SimpleConfig();
ocMapper.map(object, conf);

Ces bouts de code colorés vous ont été fournis par l'Élu de la balise code.

Modifié par while(true);

Partager ce message


Lien à poster
Partager sur d’autres sites

Il y a un bout d'idée qui ressemble à un projet :lol:

 

J'espère que tu auras plus de temps pour l'avancer plus rapidement que moi ahah, bonne chance :)

Modifié par ilicos
2 personnes aiment ça

Partager ce message


Lien à poster
Partager sur d’autres sites

Tu as prévu de pouvoir utiliser XML avec ta lib ? :P Ça pourrait être cool pour sérializer des objets !

Partager ce message


Lien à poster
Partager sur d’autres sites
il y a 56 minutes, Wisteca a dit :

Tu as prévu de pouvoir utiliser XML avec ta lib ? :P Ça pourrait être cool pour sérializer des objets !

please le xml ;(

Tout mais pas ça :x

 

En vrai ça doit pas être complexe pour TheElectronWill pour pouvoir utiliser du Yaml ou Xml

C'est une bonne idée quand même ^^

Partager ce message


Lien à poster
Partager sur d’autres sites
Il y a 20 heures, SkyBeast a dit :

please le xml ;(

Tout mais pas ça :x

 

En vrai ça doit pas être complexe pour TheElectronWill pour pouvoir utiliser du Yaml ou Xml

C'est une bonne idée quand même ^^

Ben quoi c'est génial le XML :mellow: En tout cas moi je trouve^^

Partager ce message


Lien à poster
Partager sur d’autres sites

Je veux bien ajouter xml (et ça serait pas très compliqué) mais faut m'expliquer l'intérêt de la chose pour les fichiers de configuration :

 

Entre ça:

property = value

 

Et du xml :

<property>value</property>

 

... ben je vois pas ce qu'apporte le XML à part que c'est plus long et plus pénible ?

 

Pour sérialiser des objets j'avoue que ça peut être plus pratique car on peut ajouter plus d'infos (encore qu'on pourrait faire la même chose avec des strings dans autre format - mais ça serait moins propre). Mais ça serait peut-être mieux de faire une lib de serialization XML si ça ne sert qu'à ça.

Modifié par TheElectronWill
1 personne aime ça

Partager ce message


Lien à poster
Partager sur d’autres sites

Créer un compte ou se connecter pour commenter

Vous devez être membre afin de pouvoir déposer un commentaire

Créer un compte

Créez un compte sur notre communauté. C’est facile !


Créer un nouveau compte

Se connecter

Vous avez déjà un compte ? Connectez-vous ici.


Connectez-vous maintenant

  • En ligne récemment   0 membre est en ligne

    Aucun utilisateur enregistré regarde cette page.