Guide des Directives Bidji pour Templates FreeMarker

Introduction

Ce document décrit toutes les directives disponibles pour écrire des templates de génération de code avec BidjicTask. Les directives simplifient l’accès aux métadonnées des modèles Bidjim (entités, propriétés, relations) dans vos templates FreeMarker.

Date de création : 2026-02-06 Basé sur : BidjicTask.freemarkerize() - analyse complète du code source


Table des Matières

  1. Comment Utiliser ce Guide
  2. Syntaxe Générale
  3. Variables Disponibles
  4. Directives par Catégorie
  5. Exemples Complets
  6. Matrice d’Usage
  7. Pièges Courants
  8. Migration vers Nouvelle Syntaxe

Comment Utiliser ce Guide

Pour Commencer

  1. Lisez la section Syntaxe Générale pour comprendre les deux types de directives
  2. Consultez Variables Disponibles pour savoir quelles variables sont accessibles
  3. Parcourez les directives par catégorie pour trouver celle dont vous avez besoin
  4. Référez-vous aux Exemples Complets pour des cas d’usage concrets

Conventions

  • 🟢 Active : Directive recommandée, stable
  • 🟡 Utilisable : Directive fonctionnelle mais spécifique
  • 🔴 Deprecated : À éviter, sera supprimée dans futures versions
  • ⚠️ Attention : Nécessite précautions d’usage

Syntaxe Générale

Les directives Bidji utilisent deux syntaxes distinctes :

1. Syntaxe avec ? (Query/Fonction)

${entity?properties}
${entity?dataform_properties}
${property?type_or_string}

Usage : Appel de fonctions qui retournent des données calculées ou filtrées

2. Syntaxe avec .@ (Accès Attribut)

${entity.@name}
${entity.@package}
${property.@type}

Usage : Accès direct aux métadonnées de l’entité ou propriété


Variables Disponibles dans les Templates

Lorsque BidjicTask traite un template, il injecte automatiquement les variables suivantes :

Variable Type Description Exemple
bidji Bidjim Objet racine du modèle ${bidji.entity}
entity Entity L’entité courante (depuis bidji.entity) ${entity.@name}
Model String Nom du modèle (= nom fichier .bidjim) ${Model} → “User”
Package String Package extrait du chemin du fichier ${Package} → “com.myapp”
Module String Module extrait du chemin du fichier ${Module} → “user”
Model?api ModelHelper Helper Java pour accès aux métadonnées ${Model?api.get_entity_properties(entity)}

Note : Les variables Package et Module sont extraites automatiquement du chemin du fichier .bidjim. Exemple : com/myapp/user/User.bidjim → Package="com.myapp", Module="user", Model="User"


Directives par Catégorie

1. Application et Modèle

app?entities 🟢

Retourne la liste de toutes les entités de l’application.

Syntaxe :

${app?entities}

Retourne : List<Entity> - Liste des entités

Exemple :

[#foreach entity in app?entities]
  - Entité : ${entity.@name}
[/#foreach]

Se transforme en : app.getEntities()


model?has_complex_types 🟢

Vérifie si le modèle utilise des types complexes (non primitifs).

Syntaxe :

${model?has_complex_types}

Retourne : boolean

Exemple :

[#if model?has_complex_types]
import java.util.*;
[/#if]

Se transforme en : Model?api.has_complex_types()


2. Entités - Propriétés

entity?properties 🟢

Retourne toutes les propriétés d’une entité.

Syntaxe :

${entity?properties}

Retourne : List<Map> - Liste de propriétés (chaque propriété est une Map avec @name, @type, etc.)

Exemple :

[#foreach property in entity?properties]
    private ${property.@type} _${property.@name};
[/#foreach]

Se transforme en : Model?api.get_entity_properties(entity)

Usage typique : Génération de POJO complets, itération sur tous les champs


entity?native_properties 🟢

Retourne uniquement les propriétés de types primitifs (String, Integer, Boolean, etc.).

Syntaxe :

${entity?native_properties}

Retourne : List<Map> - Liste de propriétés natives

Exemple :

[#-- Générer uniquement les champs scalaires --]
[#foreach property in entity?native_properties]
    private ${property.@type} ${property.@name};
[/#foreach]

Se transforme en : Model?api.get_native_properties(entity)

Différence avec entity?properties : Exclut les relations (1-N, N-N) et types complexes


entity?dataform_properties 🟢

Retourne les propriétés destinées aux formulaires de saisie.

Syntaxe :

${entity?dataform_properties}

Retourne : List<Map> - Liste de propriétés pour formulaires

Exemple :

<form>
[#foreach prop in entity?dataform_properties]
    <label>${prop.@name}</label>
    <input type="text" name="${prop.@name}" />
[/#foreach]
</form>

Se transforme en : Model?api.get_dataform_properties(entity)

Usage typique : Génération de formulaires HTML/JSP, écrans de création/édition


entity?datatable_properties 🟢

Retourne les propriétés destinées aux tableaux de données.

Syntaxe :

${entity?datatable_properties}

Retourne : List<Map> - Liste de propriétés pour tableaux

Exemple :

<table>
  <thead>
    [#foreach prop in entity?datatable_properties]
    <th>${prop.@name}</th>
    [/#foreach]
  </thead>
</table>

Se transforme en : Model?api.get_datatable_properties(entity)

Usage typique : Génération de grilles de données, vues liste


entity?data_properties 🟢

Retourne les propriétés pour formulaires ET tableaux (union des deux).

Syntaxe :

${entity?data_properties}

Retourne : List<Map> - Liste de propriétés communes

Se transforme en : Model?api.get_data_properties(entity)

Usage typique : Génération de code qui traite à la fois formulaires et listes


3. Entités - Métadonnées

entity.@name 🟢

Nom de l’entité.

Syntaxe :

${entity.@name}

Retourne : String

Exemple :

public class ${entity.@name} {
    // ...
}

Se transforme en : Model?api.get_entity_name(entity)


entity.@package 🟢

Package de l’entité.

Syntaxe :

${entity.@package}

Retourne : String

Exemple :

package com.mycompany.${entity.@package};

Se transforme en : Model?api.get_entity_package(entity)


entity.@module 🟢

Module de l’entité.

Syntaxe :

${entity.@module}

Retourne : String

Exemple :

// Module: ${entity.@module}

Se transforme en : Model?api.get_entity_module(entity)


entity.@icon 🟡

Icône associée à l’entité (pour interfaces utilisateur).

Syntaxe :

${entity.@icon}

Retourne : String - Nom de l’icône

Exemple :

<i class="icon-${entity.@icon}"></i>

Se transforme en : Model?api.get_entity_icon(entity)


entity.@taggable 🟡

Indique si l’entité est taggable.

Syntaxe :

${entity.@taggable}

Retourne : boolean

Se transforme en : Model?api.get_entity_taggable(entity)


entity.@delete 🟡

Indique si l’entité peut être supprimée.

Syntaxe :

${entity.@delete}

Retourne : boolean

Se transforme en : Model?api.get_entity_delete(entity)


entity.@default_sort 🟡

Champ de tri par défaut de l’entité.

Syntaxe :

${entity.@default_sort}

Retourne : String - Nom du champ

Exemple :

ORDER BY ${entity.@default_sort}

Se transforme en : entity.getDefaultSort() ⚠️ Appel direct, pas via ModelHelper


entity2.@name et entity2.@package 🟡

Identique à entity.@name et entity.@package mais pour une deuxième entité dans le contexte.

Usage : Lorsqu’on travaille avec des relations entre deux entités

Exemple :

[#assign target = Model?api.get_entity(relation.@type)]
// Relation: ${entity.@name} -> ${target.@name}

4. Entités - Interface Utilisateur

entity?detail_tabs 🟡

Retourne la liste des onglets pour la vue détail.

Syntaxe :

${entity?detail_tabs}

Retourne : List - Liste des onglets

Se transforme en : Model?api.get_detail_tabs(entity)


entity?has_detail_tabs 🟡

Vérifie si l’entité possède des onglets de détail.

Syntaxe :

${entity?has_detail_tabs}

Retourne : boolean

Exemple :

[#if entity?has_detail_tabs]
<div class="tabs">
  [#foreach tab in entity?detail_tabs]
    <div class="tab">${tab.name}</div>
  [/#foreach]
</div>
[/#if]

Se transforme en : Model?api.has_detail_tabs(entity)


entity?first_datatable_tab 🟡

Retourne le premier onglet de type datatable.

Syntaxe :

${entity?first_datatable_tab}

Se transforme en : Model?api.first_datatable_tab(entity)


entity?has_filter_by_month 🟡

Vérifie si l’entité a un filtre par mois.

Syntaxe :

${entity?has_filter_by_month}

Retourne : boolean

Se transforme en : Model?api.has_filter_by_month(entity)


entity?is_monthly_table 🟡

Vérifie si l’entité utilise un widget de table mensuelle.

Syntaxe :

${entity?is_monthly_table}

Retourne : boolean

Se transforme en : Model?api.is_monthly_table(entity)


Vérifie si la table a un footer (totaux/agrégats).

Syntaxe :

${entity?has_table_footer}

Retourne : boolean

Se transforme en : Model?api.has_table_footer(entity)


5. Entités - Relations

entity?one_to_many_properties 🟢

Retourne les propriétés de type 1-to-many (collections).

Syntaxe :

${entity?one_to_many_properties}

Retourne : List<Map> - Liste des relations 1-N

Exemple :

[#foreach rel in entity?one_to_many_properties]
    private List<${rel.@type}> ${rel.@name};
[/#foreach]

Se transforme en : Model?api.get_entity_one_to_many_properties(entity)


entity?many_to_many_properties 🟢

Retourne les propriétés de type many-to-many.

Syntaxe :

${entity?many_to_many_properties}

Retourne : List<Map> - Liste des relations N-N

Se transforme en : Model?api.get_entity_many_to_many_properties(entity)


entity?is_created_in 🟡

Vérifie si l’entité est créée dans le contexte d’une autre.

Syntaxe :

${entity?is_created_in}

Se transforme en : Model?api.is_created_in

⚠️ Note : Cette directive nécessite des paramètres supplémentaires - voir code source pour usage exact


entity?creates 🟡

Vérifie si l’entité crée d’autres entités.

Syntaxe :

${entity?creates}

Se transforme en : Model?api.creates


6. Entités - Logique Métier

entity?dump 🔧

Dump debug de la structure complète de l’entité.

Syntaxe :

${entity?dump}

Retourne : String - Représentation textuelle de l’entité

Usage : Debugging uniquement

Se transforme en : Model?api.dump_entity(entity)


7. Propriétés - Types et Valeurs

property?type_or_string 🟢

Retourne le type de la propriété, ou “string” par défaut.

Syntaxe :

${property?type_or_string}

Retourne : String - Type Java

Exemple :

[#foreach prop in entity?properties]
    private ${prop?type_or_string} ${prop.@name};
[/#foreach]

Se transforme en : Model?api.get_property_type(property.@name, 'string', false)


property?nullable_type_or_string 🟢

Retourne le type de la propriété avec marqueur nullable (?string).

Syntaxe :

${property?nullable_type_or_string}

Retourne : String - Type avec ? si nullable

Exemple (Dart/Kotlin) :

String? name;
int? age;

Se transforme en : Model?api.get_property_type(property.@name, '?string', true)


property?dbtype 🟢

Retourne le type de base de données correspondant.

Syntaxe :

${property?dbtype}

Retourne : String - Type SQL

Exemple :

CREATE TABLE ${entity.@name} (
  [#foreach prop in entity?properties]
  ${prop.@name} ${prop?dbtype},
  [/#foreach]
);

Se transforme en : Model?api.get_property_dbtype(property.@name)

Mapping typique :

  • String → VARCHAR
  • Integer → INT
  • DateTime → TIMESTAMP

property?default_value 🟢

Retourne la valeur par défaut de la propriété.

Syntaxe :

${property?default_value}

Retourne : String - Valeur par défaut

Exemple :

private String status = "${property?default_value}";

Se transforme en : Model?api.get_property_default_value(property.@name)


column?type_or_string / column?dbtype / column?default_value 🟡

Identique aux directives property?* mais pour les colonnes.

Usage : Contexte de génération de schémas de base de données

Se transforme en : Mêmes appels que property?* mais avec column.@name


column?is_property 🟡

Vérifie si une colonne correspond à une propriété de l’entité.

Syntaxe :

${column?is_property}

Retourne : boolean

Se transforme en : Model?api.has_property(column.@name)


8. Propriétés - Attributs (Deprecated) 🔴

⚠️ Les directives suivantes sont des ALIASES inutiles - utilisez directement .@ à la place !

property?kind_of_string → Utilisez property.@kind_of_string 🔴

Ancienne syntaxe :

[#if property?kind_of_string]

Nouvelle syntaxe (recommandée) :

[#if property.@kind_of_string]

Autres aliases deprecated :

  • property?kind_of_number → property.@kind_of_number
  • property?is_array → property.@is_array
  • property?editable → property.@editable
  • property?optionselect → property.@optionselect
  • property?optionfilter → property.@optionfilter
  • property?optioncomputed → property.@optioncomputed

Raison de la dépréciation : Ces directives sont de simples aliases qui n’apportent aucune valeur. L’accès direct .@ est plus clair.


9. Entités Imbriquées

nested?entity 🟢

Récupère la définition d’une entité référencée dans une propriété nested.

Syntaxe :

${nested?entity}

Retourne : Entity - Définition de l’entité

Exemple :

[#assign nestedEntity = nested?entity]
// Type nested: ${nestedEntity.@name}

Se transforme en : Model?api.get_entity(nested.@type)


nested?entity.@default_sort 🟢

Récupère le champ de tri par défaut d’une entité nested.

Syntaxe :

${nested?entity.@default_sort}

Se transforme en : Model?api.get_entity(nested.@type).getDefaultSort()

⚠️ Attention : Cette directive doit être appliquée AVANT nested?entity dans le preprocessing (ordre critique)


nested?properties 🟢

Récupère les propriétés d’une entité nested.

Syntaxe :

${nested?properties}

Se transforme en : Model?api.get_entity_properties(nested.@type)


nested?native_properties 🟢

Récupère les propriétés natives d’une entité nested.

Syntaxe :

${nested?native_properties}

Se transforme en : Model?api.get_native_properties(nested.@type)


10. Widgets

widget?property 🟡

Récupère la propriété associée à un widget.

Syntaxe :

${widget?property}

Retourne : Property - Définition de la propriété

Se transforme en : Model?api.get_entity_property(entity, widget.@property)

Usage typique : Génération d’interfaces utilisateur complexes avec widgets personnalisés


11. Debugging

property?dump 🔧

Dump debug de la structure complète de la propriété.

Syntaxe :

${property?dump}

Retourne : String - Représentation textuelle

Se transforme en : Model?api.dump_property(property)


Exemples Complets

Exemple 1 : Génération de POJO Java

[#assign entity = bidji.entity]
package com.mycompany.${entity.@package}.${entity.@module};

/**
 * ${entity.@name} entity
 */
public class ${entity.@name} {

    // ========== Propriétés natives ==========
    [#foreach property in entity?native_properties]
    private ${property.@type} ${property.@name};
    [/#foreach]

    // ========== Relations 1-N ==========
    [#foreach rel in entity?one_to_many_properties]
    private List<${rel.@type}> ${rel.@name} = new ArrayList<>();
    [/#foreach]

    // ========== Constructeur ==========
    public ${entity.@name}() {
    }

    // ========== Getters/Setters ==========
    [#foreach property in entity?properties]

    public ${property.@type} get${property.@name?cap_first}() {
        return this.${property.@name};
    }

    public void set${property.@name?cap_first}(${property.@type} ${property.@name}) {
        this.${property.@name} = ${property.@name};
    }
    [/#foreach]
}

Exemple 2 : Génération de Schéma SQL

[#assign entity = bidji.entity]
CREATE TABLE ${entity.@name} (
    id SERIAL PRIMARY KEY,
    [#foreach prop in entity?native_properties]
    ${prop.@name} ${prop?dbtype}[#if prop?default_value??] DEFAULT '${prop?default_value}'[/#if],
    [/#foreach]
    created_at TIMESTAMP DEFAULT NOW()
);

[#-- Index sur le champ de tri par défaut --]
[#if entity.@default_sort??]
CREATE INDEX idx_${entity.@name}_${entity.@default_sort} ON ${entity.@name}(${entity.@default_sort});
[/#if]

Exemple 3 : Génération de Formulaire HTML

[#assign entity = bidji.entity]
<form id="form-${entity.@name}">
    <h2>[#if entity.@icon??]<i class="${entity.@icon}"></i>[/#if] ${entity.@name}</h2>

    [#foreach prop in entity?dataform_properties]
    <div class="form-group">
        <label for="${prop.@name}">${prop.@name?cap_first}</label>
        [#if prop.@kind_of_string]
        <input type="text" id="${prop.@name}" name="${prop.@name}" />
        [#elseif prop.@kind_of_number]
        <input type="number" id="${prop.@name}" name="${prop.@name}" />
        [#else]
        <input type="text" id="${prop.@name}" name="${prop.@name}" />
        [/#if]
    </div>
    [/#foreach]

    <button type="submit">Enregistrer</button>
</form>

Exemple 4 : Génération de Repository (DAO)

[#assign entity = bidji.entity]
package com.mycompany.${entity.@package}.repository;

import java.util.List;
import com.mycompany.${entity.@package}.${entity.@name};

public interface ${entity.@name}Repository {

    ${entity.@name} findById(Long id);

    List<${entity.@name}> findAll();

    [#if entity.@default_sort??]
    List<${entity.@name}> findAllOrderBy${entity.@default_sort?cap_first}();
    [/#if]

    ${entity.@name} save(${entity.@name} entity);

    [#if entity.@delete]
    void deleteById(Long id);
    [/#if]
}

Matrice d’Usage des Directives

Tableau récapitulatif de la fréquence d’utilisation estimée des directives :

Directive Fréquence Cas d’Usage Principaux Complexité
entity?properties ⭐⭐⭐⭐⭐ POJO, DTO, itération complète Faible
entity.@name ⭐⭐⭐⭐⭐ Noms de classes, tables Très faible
entity.@package ⭐⭐⭐⭐⭐ Packages Java/Python Très faible
entity?dataform_properties ⭐⭐⭐⭐ Formulaires UI Moyenne
entity?datatable_properties ⭐⭐⭐⭐ Grilles de données Moyenne
entity?native_properties ⭐⭐⭐⭐ Propriétés scalaires uniquement Faible
property?type_or_string ⭐⭐⭐⭐ Types Java/TypeScript Moyenne
property?dbtype ⭐⭐⭐⭐ Schémas SQL Moyenne
entity?one_to_many_properties ⭐⭐⭐ Relations collections Moyenne
entity.@module ⭐⭐⭐ Organisation multi-modules Faible
entity?many_to_many_properties ⭐⭐ Relations N-N Moyenne
entity.@default_sort ⭐⭐ Tri par défaut Faible
nested?entity ⭐⭐ Navigation relations Élevée
property?default_value ⭐⭐ Valeurs initiales Faible
entity?has_detail_tabs ⭐ UI complexe Moyenne
entity.@icon ⭐ Interfaces graphiques Faible
widget?property ⭐ UI widgets custom Élevée
Deprecated ❌ Ne plus utiliser -

Légende Fréquence :

  • ⭐⭐⭐⭐⭐ : Très fréquent (90%+ des templates)
  • ⭐⭐⭐⭐ : Fréquent (60-90%)
  • ⭐⭐⭐ : Occasionnel (30-60%)
  • ⭐⭐ : Rare (10-30%)
  • ⭐ : Très rare (<10%)

Pièges Courants

1. Ordre des Directives Nested ⚠️

Problème :

[#-- INCORRECT - L'ordre compte ! --]
${nested?entity}
${nested?entity.@default_sort}  [#-- Ne fonctionnera pas ! --]

Solution :

[#-- CORRECT - default_sort d'abord --]
${nested?entity.@default_sort}
${nested?entity}

Raison : Le preprocessing applique les règles dans un ordre spécifique. nested?entity.@default_sort doit être transformé avant nested?entity, sinon il sera partiellement transformé et cassé.


2. Confusion entre ? et .@

Problème :

${property?name}  [#-- Erreur ! --]
${entity?package} [#-- Erreur ! --]

Solution :

${property.@name}  [#-- Correct --]
${entity.@package} [#-- Correct --]

Règle :

  • Utilisez ? pour les fonctions (retournent des listes ou calculs)
  • Utilisez .@ pour les attributs (accès direct)

3. Directives Deprecated

Problème :

[#if property?kind_of_string]  [#-- Deprecated ! --]

Solution :

[#if property.@kind_of_string]  [#-- Correct --]

Raison : Les directives property?kind_of_* sont de simples aliases. Utilisez directement .@ pour plus de clarté.


4. Accès à entity2 au lieu d’entity

Problème : Utiliser entity2 sans raison

Solution : N’utilisez entity2 que dans les contextes où vous travaillez explicitement avec deux entités (ex: relations)


5. Oublier Model?api pour les nested

Problème :

[#assign target = nested.@type]  [#-- Type brut, pas l'entité --]

Solution :

[#assign target = nested?entity]  [#-- Récupère l'entité complète --]

Migration vers Nouvelle Syntaxe

Une nouvelle syntaxe plus claire est en cours de développement. Voici un aperçu :

Syntaxe Actuelle (Legacy)

[#foreach prop in entity?properties]
    private ${prop.@type} ${prop.@name};
[/#foreach]

Nouvelle Syntaxe (Future)

[#foreach prop in bidji.entity.properties(entity)]
    private ${bidji.property.type(prop)} ${bidji.property.name(prop)};
[/#foreach]

Avantages de la nouvelle syntaxe :

  • ✅ Namespaces clairs (bidji.entity.*, bidji.property.*)
  • ✅ Validation par FreeMarker (erreurs claires)
  • ✅ Pas de preprocessing fragile
  • ✅ Auto-complétion IDE possible

Pour plus d’informations : Voir doc/Refactoring.md section “Phase 3: Nouvelle Syntaxe”


Résumé des Directives par Fréquence

Directives Essentielles (à connaître absolument)

entity?properties              [#-- Toutes les propriétés --]
entity.@name                   [#-- Nom de l'entité --]
entity.@package                [#-- Package --]
property.@type                 [#-- Type de propriété --]
property.@name                 [#-- Nom de propriété --]

Directives Courantes

entity?native_properties       [#-- Propriétés primitives --]
entity?dataform_properties     [#-- Props pour formulaires --]
entity?datatable_properties    [#-- Props pour tableaux --]
property?type_or_string        [#-- Type avec fallback --]
property?dbtype                [#-- Type SQL --]
entity?one_to_many_properties  [#-- Relations 1-N --]

Directives Avancées

nested?entity                  [#-- Entité référencée --]
entity?has_detail_tabs         [#-- UI complexe --]
widget?property                [#-- Widgets custom --]
entity?dump                    [#-- Debug --]

Support et Contribution

Problème avec une directive ?

  1. Vérifiez la syntaxe dans ce guide
  2. Consultez les exemples complets
  3. Vérifiez les pièges courants
  4. Reportez un bug dans doc/Refactoring.md

Ajouter une nouvelle directive ?

  1. Modifiez BidjicTask.freemarkerize()
  2. Mettez à jour ce document
  3. Ajoutez des tests dans BidjicPreprocessorTest
  4. Documentez dans BidjicDirectivesReference.md

Document généré le : 2026-02-06 Version Bidji : dev Auteur : Analyse automatique du code source