Recherche de site Web

Analyser les fichiers de configuration JSON avec Groovy


Évitez le débat sur l'utilisation ou non de JSON comme format de configuration et apprenez simplement à l'analyser à l'aide de Groovy.

Les applications incluent généralement un certain type d'état ou de configuration par défaut ou « prêt à l'emploi », ainsi qu'un moyen permettant aux utilisateurs de personnaliser cette configuration en fonction de leurs besoins.

Par exemple, LibreOffice Writer donne accès à des éléments tels que les données utilisateur, les polices, les paramètres de langue et (bien) plus encore via Outils > Options dans sa barre de menus. Certaines applications (comme LibreOffice) fournissent une interface utilisateur pointer-cliquer pour gérer ces paramètres. Certains, comme Tracker (la tâche GNOME qui indexe les fichiers), utilisent des fichiers XML. Et certaines, notamment les applications basées sur JavaScript, utilisent JSON, malgré les protestations de beaucoup (par exemple, cet auteur et cet autre auteur).

Dans cet article, j'éviterai le débat sur l'opportunité d'utiliser ou non JSON comme format de fichier de configuration et j'expliquerai comment analyser ce type d'informations à l'aide du langage de programmation Groovy. Groovy est basé sur Java mais avec un ensemble différent de priorités de conception qui font que Groovy ressemble davantage à Python.

Installer Groovy

Puisque Groovy est basé sur Java, il nécessite également une installation Java. Vous trouverez peut-être des versions récentes et décentes de Java et Groovy dans les référentiels de votre distribution Linux. Ou vous pouvez installer Groovy en suivant les instructions sur son site Web. Une alternative intéressante pour les utilisateurs de Linux est SDKMan, que vous pouvez utiliser pour obtenir plusieurs versions de Java, Groovy et de nombreux autres outils associés. Pour cet article, j'utiliserai la version OpenJDK11 de ma distribution et la version Groovy 3.0.7 de SDKMan.

Le fichier de configuration JSON de démonstration

Pour cette démonstration, j'ai récupéré ce JSON auprès de Drupal (c'est le fichier de configuration principal utilisé par le CMS Drupal) et je l'ai enregistré dans le fichier config.json :

{
  "vm": {
    "ip": "192.168.44.44",
    "memory": "1024",
    "synced_folders": [
      {
        "host_path": "data/",
        "guest_path": "/var/www",
        "type": "default"
      }
    ],
    "forwarded_ports": []
  },
  "vdd": {
    "sites": {
      "drupal8": {
        "account_name": "root",
        "account_pass": "root",
        "account_mail": "box@example.com",
        "site_name": "Drupal 8",
        "site_mail": "box@example.com",
        "vhost": {
          "document_root": "drupal8",
          "url": "drupal8.dev",
          "alias": ["www.drupal8.dev"]
        }
      },
      "drupal7": {
        "account_name": "root",
        "account_pass": "root",
        "account_mail": "box@example.com",
        "site_name": "Drupal 7",
        "site_mail": "box@example.com",
        "vhost": {
          "document_root": "drupal7",
          "url": "drupal7.dev",
          "alias": ["www.drupal7.dev"]
        }
      }
    }
  }
}

Il s'agit d'un joli fichier JSON complexe avec plusieurs niveaux de structure, comme :

<>.vdd.sites.drupal8.account_name

et quelques listes comme :

<>.vm.synced_folders

Ici, <> représente le niveau supérieur sans nom. Voyons comment Groovy gère cela.

Analyser JSON avec Groovy

Groovy est livré avec le package groovy.json, qui regorge de toutes sortes de trucs sympas. L'une des meilleures parties est la classe JsonSlurper, qui comprend plusieurs méthodes parse() qui convertissent JSON en une Map Groovy - une structure de données avec valeurs stockées par rapport aux clés.

Voici un joli et court programme Groovy nommé config1.groovy qui crée une instance JsonSlurper, puis appelle l'une de ses méthodes parse() pour analyser le JSON dans un fichier et convertissez-le en une instance Map appelée config, et écrit enfin cette carte :

import groovy.json.JsonSlurper

def jsonSlurper = new JsonSlurper()

def config = jsonSlurper.parse(new File('config.json'))

println "config = $config"

Exécutez ce programme sur la ligne de commande dans un terminal :

$ groovy config1.groovy
config = [vm:[ip:192.168.44.44, memory:1024, synced_folders:[[host_path:data/, guest_path:/var/www, type:default]], forwarded_ports:[]], vdd:[sites:[drupal8:[account_name:root, account_pass:root, account_mail:box@example.com, site_name:Drupal 8, site_mail:box@example.com, vhost:[document_root:drupal8, url:drupal8.dev, alias:[www.drupal8.dev]]], drupal7:[account_name:root, account_pass:root, account_mail:box@example.com, site_name:Drupal 7, site_mail:box@example.com, vhost:[document_root:drupal7, url:drupal7.dev, alias:[www.drupal7.dev]]]]]]
$

La sortie affiche une carte de niveau supérieur avec deux clés : vm et vdd. Chaque clé fait référence à sa propre carte de valeurs. Notez la liste vide référencée par la clé forwarded_ports.

Hein. C'était facile, mais cela ne faisait qu'imprimer des choses. Comment accéder aux différents composants ? Voici un autre programme qui montre comment accéder à la valeur stockée dans config.vm.ip :

import groovy.json.JsonSlurper

def jsonSlurper = new JsonSlurper()

def config = jsonSlurper.parse(new File('config.json'))

println "config.vm.ip = ${config.vm.ip}"

Exécuter:

$ groovy config2.groovy
config.vm.ip = 192.168.44.44
$

Ouais, c'est facile aussi. Cela profite du raccourci Groovy qui signifie :

config.vm.ip

dans Groovy équivaut à :

config['vm']['ip']

lorsque config et config.vm sont tous deux des instances de Map, et que les deux sont équivalents à :

config.get("vm").get("ip")

en Java.

Voilà pour la simple gestion du JSON. Que se passe-t-il si vous souhaitez avoir une configuration standard et laisser l'utilisateur la remplacer ? Dans ce cas, vous souhaiterez peut-être avoir une configuration JSON codée en dur dans le programme, puis lire la configuration utilisateur et remplacer les paramètres de configuration standard.

Supposons que la configuration ci-dessus soit standard et que l'utilisateur souhaite en remplacer seulement une partie, juste les valeurs ip et memory dans la structure vm , et mettez-le dans le fichier userConfig.json :

{
  "vm": {
    "ip": "201.201.201.201",
    "memory": "4096",
  }
}

Vous pouvez le faire en utilisant ce programme :

import groovy.json.JsonSlurper

def jsonSlurper = new JsonSlurper()

// use parseText() to parse a string rather than reading from a file
// this gives us the “standard configuration”

def standardConfig = jsonSlurper.parseText("""
{
  "vm": {
    "ip": "192.168.44.44",
    "memory": "1024",
    "synced_folders": [
      {
        "host_path": "data/",
        "guest_path": "/var/www",
        "type": "default"
      }
    ],
    "forwarded_ports": []
  },
  "vdd": {
    "sites": {
      "drupal8": {
        "account_name": "root",
        "account_pass": "root",
        "account_mail": "box@example.com",
        "site_name": "Drupal 8",
        "site_mail": "box@example.com",
        "vhost": {
          "document_root": "drupal8",
          "url": "drupal8.dev",
          "alias": ["www.drupal8.dev"]
        }
      },
      "drupal7": {
        "account_name": "root",
        "account_pass": "root",
        "account_mail": "box@example.com",
        "site_name": "Drupal 7",
        "site_mail": "box@example.com",
        "vhost": {
          "document_root": "drupal7",
          "url": "drupal7.dev",
          "alias": ["www.drupal7.dev"]
        }
      }
    }
  }
}
""")

// print out the standard configuration

println "standardConfig = $standardConfig"

// read in and parse the user configuration information

def userConfig = jsonSlurper.parse(new File('userConfig.json'))

// print out the user configuration information

println "userConfig = $userConfig"

// a function to merge the user configuration with the standard

def mergeMaps(Map input, Map merge) {
    merge.each { k, v ->
        if (v instanceof Map)
            mergeMaps(input[k], v)
        else
            input[k] = v
    }
}

// merge the configurations and print out the modified
// standard configuration

mergeMaps(standardConfig, userConfig)

println "modified standardConfig $standardConfig"

Exécutez ceci comme :

$ groovy config3.groovy
standardConfig = [vm:[ip:192.168.44.44, memory:1024, synced_folders:[[host_path:data/, guest_path:/var/www, type:default]], forwarded_ports:[]], vdd:[sites:[drupal8:[account_name:root, account_pass:root, account_mail:box@example.com, site_name:Drupal 8, site_mail:box@example.com, vhost:[document_root:drupal8, url:drupal8.dev, alias:[www.drupal8.dev]]], drupal7:[account_name:root, account_pass:root, account_mail:box@example.com, site_name:Drupal 7, site_mail:box@example.com, vhost:[document_root:drupal7, url:drupal7.dev, alias:[www.drupal7.dev]]]]]]
userConfig = [vm:[ip:201.201.201.201, memory:4096]]
modified standardConfig [vm:[ip:201.201.201.201, memory:4096, synced_folders:[[host_path:data/, guest_path:/var/www, type:default]], forwarded_ports:[]], vdd:[sites:[drupal8:[account_name:root, account_pass:root, account_mail:box@example.com, site_name:Drupal 8, site_mail:box@example.com, vhost:[document_root:drupal8, url:drupal8.dev, alias:[www.drupal8.dev]]], drupal7:[account_name:root, account_pass:root, account_mail:box@example.com, site_name:Drupal 7, site_mail:box@example.com, vhost:[document_root:drupal7, url:drupal7.dev, alias:[www.drupal7.dev]]]]]]
$

La ligne commençant par modified standardConfig montre que les valeurs vm.ip et vm.memory ont été remplacées.

Les lecteurs avertis remarqueront que je n'ai pas vérifié les JSON mal formés et que je n'ai pas non plus pris soin de m'assurer que la configuration utilisateur avait du sens (ne crée pas de nouveaux champs, fournit des valeurs raisonnables, etc.). Ainsi, la jolie petite méthode récursive pour fusionner les deux cartes n’est probablement pas très pratique dans le monde réel.

Eh bien, j'ai dû laisser quelque chose pour mes devoirs, n'est-ce pas ?

Ressources géniales

Le site Apache Groovy propose de nombreuses documentations intéressantes. Une autre excellente ressource Groovy est M. Haki. Et une très bonne raison d'apprendre Groovy est de continuer et d'apprendre Grails, qui est un framework Web full-stack merveilleusement productif construit sur d'excellents composants comme Hibernate, Spring Boot et Micronaut.

Articles connexes: