mercredi 28 août 2019

Exemple d’utilisation d’Apache Freemarker : Génération du code

Pourquoi générer du code Java

Java est relativement lourd comme langage; il est très strict mais très efficace. Des fois, on n’a pas le temps (ou ils suffit être comme moi, un peu féniant) pour tout écrire, alors, on fait appel à nos outils pour générer une partie du code. A ce niveau, les différents IDE possèdent tous des outils pour générer les constructeurs et les Setters et Getters et bien d’autres parties de nos classes Java.
Dans cet exemple, je vais compter sur un "template engine" pour générer le code des Java Beans. J’ai choisi comme exemple Apache Freemarker. Je n’ai aucune idée sur les autres "template engines".

Apache Freemarker

Je reprends le diagramme donné par Apache pour expliquer le principe d’un "template engine" :



ce qui est important à noter est l’affirmation ( ici ):

Anything not an FTL tag or an interpolation or comment is considered
static text and will not be interpreted by FreeMarker; it is just
printed to the output as-is.

Par conséquent, Freemarker peut être utilisé pour générer n’importe quel format texte.

L’exemple

Dans cet exemple, j’ai tenté de générer le code d’un Java Bean.

La spécification JavaBeans de Oracle définit les composants de type
JavaBeans comme « des composants logiciels réutilisables manipulables
visuellement dans un outil de conception ».

Ils sont utilisés pour encapsuler plusieurs objets dans un seul objet :
le « bean » (ou haricot en français). Le « bean » regroupe alors tous
les attributs des objets encapsulés, et peut définir d'autres attributs
si besoin. Ainsi, il représente une entité plus globale que les objets
encapsulés de manière à répondre à un besoin métier.

Pour cela, j’ai défini deux classes comme modèle :

public class Variable {

    String variableName;
    String variableType;

}

Et

public class Bean {

    public String beanName;
    public List<Variable> attributes;

}

Ainsi, un Bean peut être créé facilement. A titre d’exemple, si je veux un Bean "User" avec trois attributs : id, userName et password, il suffit un petit bout de code comme le suivant :

Bean user = new Bean();
user.setBeanName("User");
user.setAttributes(new ArrayList<>());
user.getAttributes().add(new Variable("id", "int"));
user.getAttributes().add(new Variable("userName", "String"));
user.getAttributes().add(new Variable("password", "String"));

Par la suite, il fallait créer une petite template avec un constructeur vide et l’ensemble des Setters et Getters :

public class ${bean.beanName} {

 public ${bean.beanName}(){
 }

<#list bean.attributes as attribut>;
 ${attribut.variableType} ${attribut.variableName};

 public void set${attribut.variableName?cap_first}(${attribut.variableType} value){
  ${attribut.variableName} = value;
 }

 public ${attribut.variableType} get${attribut.variableName?cap_first}(){
  return ${attribut.variableName};
 }

</#list>
}

Par la suite, il ne reste qu’jouter le Bean au modèle, puis passer ce dernier à la template chargé pour générer le code nécessaire :

public static void createBean(Configuration cfg, String templateName, Bean bean) throws MalformedTemplateNameException, TemplateException, ParseException, IOException{

        Map root = new HashMap();
        root.put("bean", bean);
        Template template = cfg.getTemplate(templateName);
        Writer out = new OutputStreamWriter(new  FileOutputStream(new File(bean.getBeanName() + ".java")));
        template.process(root, out);

}

Le résultat est bien le fichier source attendu pour le Bean décrit.

En effet, l’outil est très simple à utiliser au point où je me suis amusé à ajouter une template qui génère une fenêtre avec les champs nécessaires. La tâche est loin d’être finie (adapter les champs de saisi selon les types de données), mais le début était très simple.

Vous pouvez trouver le code exemple ici.
Vous pouvez trouver la version PDF de ce post ici.