Configuration API



  • Bienvenue !

    La grande majorité des API proposées par Java ou par des programmeurs sont compliquées à utiliser ou ne sont adaptées qu'à certains types de configuration. J'ai donc décidé de créer ma propre API (que je pourrai donc utiliser facilement), libre à vous de ne pas l'utiliser ^^.

    #Présentation(Présentation)

    La configuration API, bien que peu utile dans le domaine du modding, permet de sauvegarder facilement des valeurs dans un fichier afin de les récupérer ultérieurement. Elle vous permet de créer un fichier de configuration qui pourra être sauvegardé et chargé. Le système est basé sur le principe (et pas sur le code source) du "NBTTag" de Minecraft.
    Les options d'ajout et d'accès aux données présentes dans l'API sont entièrement optimisées et supportent pleinement le multi-threading, excepté les options de chargement, de sauvegarde et de gestion du fichier qui ne doivent pas être exécutées simultanément sous peine de corruption des données.

    Trêve de bavardages, vous pouvez télécharger l'API ci-dessous, avec son historique des changements et ses tutoriels.

    #Téléchargements(Téléchargements)

    Télécharger la dernière version en date (BÊTA 1.0)

    La version actuelle n'est pas compatible avec Java 6, vous pouvez en télécharger une compatible avec Java 5 et Java 6 en suivant ce lien.

    Télécharger la Javadoc
    (version Html)

    Historique des changements :

    Version BÊTA 1.0

    ❗ Le système de fichiers ayant été refait, les anciennes versions peuvent devenir illisibles. Un convertisseur a été mis en place sur cette version de l'API mais certaines variables peuvent causer des erreurs, veuillez vérifier cela.

    • Ajout de l'annotation @Discouraged signifiant que la méthode utilisée est déconseillée
    • Ajout de l'objet ConfigList (liste serializable)
    • Refonte complète des systèmes internes de l'API (aucun changement côté utilisateur)
    • Ajout d'un convertisseur automatisé provisoire pour le passage de la version ALPHA 1.1 (et inférieur) à la version BÊTA 1.0
    • Correction d'un bug intervertissant la clé de cryptage et la clé de décryptage dans la méthode setCryptedString()

    Version ALPHA 1.1 Télécharger

    • Ajout du type 'char'
    • Optimisation des performances de la méthode getKeyList()
    • Ajout de la possibilité d'ajouter des objets dans les objets
    • Refonte du système de sauvegarde/chargement

    Version ALPHA 1.0 Télécharger

    • Création de la Configuration API

    A faire :

    • Ajouter la possibilité de définir des objets dans les objets.
    • Refaire le système de chargement/sauvegarde

    :idea: Vos propositions, vos questions et les bugs rencontrés sont les bienvenus, alors n'hésitez pas ! 🙂

    Installation

    Commencez par déplacer le fichier téléchargé dans votre "Workspace".
    L'API doit être ajoutée sur chaque projet. Tout d'abord, ouvrez Eclipse et créez votre projet si vous n'en avez pas. Faites un clic droit sur votre projet et sélectionnez "Properties".

    Dans l'onglet "Libraries" du menu "Java build path", cliquez sur le bouton "Add External JARs…".

    Eclipse va maintenant vous demander de sélectionner un fichier. Sélectionnez le fichier que vous avez déplacé précédemment puis cliquez sur "Ouvrir".

    Fermez la fenêtre "Properties" en appuyant sur "Ok".
    Voilà, l'API est maintenant prête à être utilisée. Concernant les tutoriels sur son utilisation, je vous renvoie à la section suivante.

    Utilisation

    I. Utilisation de base

    A. Gestion du fichier

    Dans cette partie, nous allons voir comment créer un fichier de configuration et comment enregistrer des paramètres basiques.
    Tout d'abord, créons un fichier de configuration. Il existe deux manières d'en créer :

    ConfigurationFile cfg = new ConfigurationFile("C:/test.cfg");
    //Ou encore en utilisant Java NIO2
    Path path = Paths.get("C:/test.cfg");
    ConfigurationFile cfg2 = new ConfigurationFile(path);
    

    Le fichier de configuration crée va donc se trouver dans "C:/test.cfg". Vous pouvez à tout moment récupérer la localisation du fichier de configuration en faisant :

    Path p = cfg.getFilePath();
    

    Bien entendu, vous pouvez gérer le fichier à partir de l'API :

    Path destination = Paths.get("C:/tutoriel/test.cfg");
    cfg.delete();
    cfg.move(destination);
    cfg.rename("tutoriel.tuto");
    cfg.exists();//Renvoie true si le fichier existe sur le disque
    

    Enfin, il est possible de charger et sauvegarder le fichier (logique 🆒 ).

    
    cfg.load();
    cfg.save();
    
    

    Quelques explications sur le fonctionnement de l'API :
    Lorsque vous définissez des valeurs, elles sont stockées dans l'objet ConfigurationFile et se sauvegardent uniquement lorsque vous lui dites de se sauvegarder. Même chose pour le chargement, les valeurs seront chargées uniquement après avoir fait un cfg.load().
    Attention, tous les changements non enregistrés sont écrasés lors du chargement.
    Enfin, la méthode…

    cfg.clear();
    

    ...supprime toutes les valeurs en mémoire pour libérer de la RAM.
    Maintenant que vous savez comment gérer le fichier, nous allons voir comment ajouter ou supprimer des valeurs.

    B. Gestion des valeurs

    Pour définir une valeur, il suffit de faire :

    cfg.setBoolean(key, value);
    

    La clé key est une chaîne de caractères correspondant à un nom de votre choix. Elle vous permettra de récupérer la valeur plus tard.
    La valeur value est la valeur attribuée à la clé. Dans l'exemple, soit true, soit false.
    Pour récupérer la valeur, il faudra utiliser :

    boolean bool = cfg.getBoolean(key)
    

    La clé key sera donc identique à celle spécifiée plus haut.
    Il existe 7 types d'objets pouvant être ajoutés :

    • Character
    • String
    • Boolean
    • Long
    • Integer
    • Double
    • Short
    • Float

    La liste des classes peut être obtenue en faisant :

    ConfigurationFile.ALLOWED_OBJECTS //Liste de Class
    

    ❗**ATTENTION : Si une valeur n'est pas affectée via la méthode ***cfg.setBoolean()*, une NullPointerException sera levée !

    Voici quelques exemples d'utilisations pour clarifier tout ça :

    ConfigurationFile cfg = new ConfigurationFile("C:/test.cfg");
    cfg.setString("str","Bienvenue");
    cfg.setString("autreStr"," sur le topic de l'API configurationFile");
    cfg.setInteger("int",7017);
    cfg.save();//Sauvegarde de toutes les valeurs dans le fichier
    
    

    Dans un autre projet :

    ConfigurationFile cfg = new ConfigurationFile("C:/test.cfg");
    System.out.println(cfg.getString("str") + cfg.getString("autreStr") + " ! Valeur : " + cfg.getInteger("int"));
    

    Sortie console :

    Bienvenue sur le topic de l'API configurationFile ! Valeur : 7017
    

    Magique non ? 😄

    II. Utilisation avancée

    Dans cette partie, nous allons voir comment faire pour enregistrer des objets. Car oui, c'est possible ! 🙂

    Tout d'abord, créons notre classe :

    public class Humain{
    public int age, taille;
    public boolean female;
    public String nom = "", couleurCheveux = "";
    }
    
    

    Un humain basique donc ^^. Maintenant je souhaite pouvoir le mettre dans le fichier de configuration.
    Il suffit simplement de le faire implémenter l'interface ConfigSerializable.

    public class Humain implements ConfigSerializable{
    //Bla bla bla
    }
    

    On insère les méthodes et on remplace avec les valeurs (voir commentaires) :

    public class Humain implements ConfigSerializable{
    public int age;
    public float taille;
    public boolean female;
    public String nom = "", couleurCheveux = "";
    
    @Override
    public String getClassDescriptor() {
    //Le nom de l'objet, ici humain
    return "humain";
    }
    
    @Override
    public String getClassVersion() {
    //La version de la classe, qui va nous permettre de savoir si la classe présente dans le fichier est plus récente ou non
    return "1.0.0";
    }
    
    @Override
    public boolean loadFromConfig(ConfigSettings arg0) {
    //Permet de charger l'objet depuis le fichier de configuration
    this.age = arg0.getInteger("age");
    this.taille = arg0.getFloat("taille");
    this.female = arg0.getBoolean("isFemale");
    this.nom = arg0.getString("nom");
    this.couleurCheveux = arg0.getString("couleurCheveux");
    return true;//Mettez ce que vous voulez ici, ça sert simplement à savoir si l'importation a réussi ou non.
    }
    
    @Override
    public boolean writeToConfig(ConfigSettings arg0) {
    //Permet d'enregistrer l'objet dans le fichier de configuration
    arg0.setInteger("age", this.age);
    arg0.setFloat("taille", this.taille);
    arg0.setBoolean("isFemale", this.female);
    arg0.setString("nom", this.nom);
    arg0.setString("couleurCheveux", this.couleurCheveux);
    return true;//Voir plus haut
    }
    }
    

    Voilà pour l'objet humain. Vous voyez, ce n'est pas bien compliqué ^^.
    Pour l'enregistrer et le charger dans le fichier :

    Humain humain1 = new Humain();
    humain1.age = 18;
    humain1.taille = 1.75F;
    humain1.female = false;
    humain1.nom = "EclipseOnFire";//Ouais no comment :P
    humain1.couleurCheveux = "brun";
    
    ConfigurationFile cfg = new ConfigurationFile("C:/test.cfg");
    cfg.writeObject("humain1", humain1);
    cfg.save();
    
    cfg.clear();
    
    cfg.load();
    Humain humain2 = new Humain();
    cfg.readObject("humain1",humain2);
    //Voilà, notre humain2 est désormais le même que humain1 !
    System.out.println(humain1.equals(humain2));
    
    

    Sortie console :

    true
    

    Depuis la version BÊTA 1.0, il est possible d'ajouter une liste d'objets grâce à la classe ConfigList. Cet objet s'utilise de la même manière qu'un objet List mis à part le fait que seuls les types de base cités plus haut peuvent être placés dans cette liste. Elle se sauvegarde et se charge comme un objet classique.

    
    ConfigurationFile f = new ConfigurationFile("C:/test.cfg");
    ConfigList <string>strangeList = new ConfigList<string>(String.class);//Quelques explications seront données plus bas
    strangeList.add("Salut la compagnie !");
    strangeList.add("Héhé !");
    strangeList.remove("Héhé !");
    System.out.println(strangeList.get(0));
    f.writeObject("maListe", strangeList);
    //etc…
    
    //On peut aussi le construire à partir d'un objet List :
    List <string>maListe = new ArrayList<string>();
    ConfigList <string>autreListe = new ConfigList<string>(String.class, maListe);
    
    //On peut aussi définir les variables de la liste après son instanciation :
    strangeList.setList(maList);//Toutes les valeurs de strangeList sont remplacées par celles de maListe
    
    //Et ça marche même dans l'autre sens :
    List <string>encoreUneListe = new ArrayList<string>();
    encoreUneListe = strangeList.toList();
    
    //Ou encore :
    List <string>ilEnAPasMarreAvecSesListes = new ArrayList<string>();
    strangeList.addAll(ilEnAPasMarreAvecSesListes);
    strangeList.removeAll(ilEnAPasMarreAvecSesListes);
    
    //Bref, il y a beaucoup de possibilités ! :)
    
    

    La liste doit être instanciée avec la même Class spécifiée en paramètre de classe. Pourquoi ? Pour la simple et bonne raison qu'utiliser la réflexion Java pour connaître le type d'objet spécifié en paramètre de classe est beaucoup trop lent, il est donc préférable de demander à l'utilisateur de se répéter un peu plutôt qu'ajouter des morceaux de code ignobles pour obtenir le même résultat, ne croyez-vous pas ? 😄

    Voilà, le tutoriel touche à sa fin, je vous remercie d'avoir pris le temps de le lire ! N'hésitez pas à poster vos impressions, les bugs, les erreurs que vous rencontrez et vos questions ! ;)</string></string></string></string></string></string></string></string></string></string>


  • Modérateurs

    J'ai peur de te faire peur (woah) mais ton code est compatible avec Java 7, et pas Java 6 (niveau requis pour MC).

    Sinon, bon boulot 😄


  • Moddeurs confirmés

    Ça ressemble fortement a la class Properties sauf que tu gères en plus les écritures fichier et les cast.
    Sinon il existe les BDD qui sont extrêmement simple a utiliser une fois qu'on connait le SQL 😉
    SQLite par exemple est très simple a mettre en place 😉



  • J'ai peur de te faire peur (woah) mais ton code est compatible avec Java 7, et pas Java 6 (niveau requis pour MC).

    Ah… Possible... M'enfin comme je l'ai dit dans le post c'est pas très utile pour le modding puisque le fichier de configuration est illisible lorsqu'on l'ouvre ^^. C'est plutôt une API en général.

    @'Blackout':

    Ça ressemble fortement a la class Properties sauf que tu gères en plus les écritures fichier et les cast.
    Sinon il existe les BDD qui sont extrêmement simple a utiliser une fois qu'on connait le SQL 😉
    SQLite par exemple est très simple a mettre en place 😉

    En fait j'ai fait des recherches et j'ai pas trouvé de trucs qui me convienne, d'autant plus qu'écrire une classe Config et l'écrire dans un fichier pour chacun de mes programmes, c'est répétitif… J'ai donc décidé d'écrire ma propre classe.

    J'y pense, faudrait que j'améliore le système de sauvegarde O_o. Le truc avec les Exception ou null c'est totalement pourri.
    Renvoyer un objet ConfigInfo contenant toutes les informations sur les éventuelles erreurs serait beaucoup plus adapté ^^.



  • La version ALPHA 1.1 est sortie ! Consultez l'historique des changements pour plus d'informations !


  • Moddeurs confirmés

    Utilise le système exception déjà existant 😉
    Je serais curieux de savoir comment tu implémentes tes fonctions sans utiliser Properties, tu pourrais git ton API ?



  • @'Blackout':

    Utilise le système exception déjà existant 😉
    Je serais curieux de savoir comment tu implémentes tes fonctions sans utiliser Properties, tu pourrais git ton API ?

    Heu oui mais il faudrait faire en sorte que ce soit l'utilisateur qui ferme (close()) le fichier et la règle n°1 : ne jamais faire confiance à l'utilisateur 😛
    Heu en fait je suis pas trop tenté par mettre mon code accessible (je veux dire en général, pas que pour l'API).
    Sinon j'ai crée mon propre système avec des Hashtable, une qui enregistre les types et une autre qui enregistre les valeurs. C'est simple 🙂


  • Moddeurs confirmés

    Je pense que ton API tiens en une class, qui extends Properties.
    La class Properties possède un parser optimisé et générique pour faire des cfg, tu devrais te renseigner sur cette class si tu veux améliorer ton API 😉



  • @'Blackout':

    Je pense que ton API tiens en une class, qui extends Properties.
    La class Properties possède un parser optimisé et générique pour faire des cfg, tu devrais te renseigner sur cette class si tu veux améliorer ton API 😉

    Nan d'accord mais excuse mon entêtement, je préfère mon système, au moins je sais comment il fonctionne.



  • La version BÊTA 1.0 est sortie ! :anniv:
    L'API est en BÊTA car elle a été refaite et est 2x plus performante (C'est testé 🙂 ) !
    De plus, la JavaDoc est à votre disposition, direction les téléchargements !

    De nombreux changements, notamment :

    • L'ajout des listes
    • Le changement du système de sauvegarde et de chargement
      Et plus encore si vous allez voir l'historique des changements !

    Ce topic est ouvert aux suggestions et aux commentaires !



  • La nouvelle version est-elle compatible java 6 ? Je l'aurais bien utiliser pour des app android mais c'est du java 6 😕



  • @'gagoi':

    La nouvelle version est-elle compatible java 6 ? Je l'aurais bien utiliser pour des app android mais c'est du java 6 😕

    Normalement elle devrait l'être. Je suis actuellement en train de vérifier sa compatibilité. Très difficile d'ailleurs vu que Oracle n'offre plus de JDK aux utilisateurs pour les versions inférieures à Java 7…



  • ok. Je sais pas si je pourrais essayer dans la semaine. Tiens moi au courant. Je te dis si ça marche pour moi avant la fin de l'année normalement 🙂



  • Je viens de trouver l’incompatibilité : j'utilise l'objet Path pour l'API, ce qui est incompatible avec Java 6. Je vais créer une autre version de l'API pour Java 6 et 5 (ce serait bête de se priver de l'objet Path).


  • Modérateurs

    @'EclipseOnFire':

    Je viens de trouver l’incompatibilité : j'utilise l'objet Path pour l'API, ce qui est incompatible avec Java 6. Je vais créer une autre version de l'API pour Java 6 et 5 (ce serait bête de se priver de l'objet Path).

    Se priver de l'objet Path (et la classe Paths en passant) ne devrait pas être vraiment dérangeant pour une petite API comme celle-ci 😉



  • Ok merci 🙂



  • @'jglrxavpok':

    Se priver de l'objet Path (et la classe Paths en passant) ne devrait pas être vraiment dérangeant pour une petite API comme celle-ci 😉

    Tu crois ? J'aime pas trop l'objet File il est trop… galère puisqu'il gère mal les OS sur certains points.


  • Modérateurs

    @'EclipseOnFire':

    @'jglrxavpok':

    Se priver de l'objet Path (et la classe Paths en passant) ne devrait pas être vraiment dérangeant pour une petite API comme celle-ci 😉

    Tu crois ? J'aime pas trop l'objet File il est trop… galère puisqu'il gère mal les OS sur certains points.

    Faut savoir contourner 😉



  • @'jglrxavpok':

    Faut savoir contourner 😉

    C'est sûr ^^. En plus je dois avouer que je suis plus habitué à NIO2 donc ça me facilite pas la tâche !

    Bref, je viens de finir, voici le lien de téléchargement pour la version Java 5 et Java 6 : Téléchargement.



  • Ok merci 🙂


Log in to reply