Manipulation des propriétés JavaBeans avec Apache Commons BeanUtils

Apache Commons BeanUtils est une bibliothèque conçue pour simplifier l’accès dynamique aux propriétés des objets Java conformes au standard JavaBeans. Elle s’appuie sur les mécanismes de réflexion fournis par le JDK, tout en offrant une API plus intuitive que le paquet java.beans natif.

Prérequis : ce qu’est un JavaBean

Pour fonctionner correctement, BeanUtils suppose que les classes respectent les conventions JavaBeans :

  • Classe publique avec constructeur par défaut sans paramètre ;
  • Propriétés privées accessibles via des méthodes getXXX() / setXXX(), ou isXXX() pour les types booléens ;
  • Aucune obligation de fournir à la fois getter et setter — une propriété peut être en lecture seule.

Exemple minimal d’un bean :

public class StaffMember {
    private String givenName;
    private String familyName;
    private LocalDate startDate;
    private boolean isPermanent;

    public String getGivenName() { return givenName; }
    public void setGivenName(String givenName) { this.givenName = givenName; }

    public String getFamilyName() { return familyName; }
    public void setFamilyName(String familyName) { this.familyName = familyName; }

    public LocalDate getStartDate() { return startDate; }
    public void setStartDate(LocalDate startDate) { this.startDate = startDate; }

    public boolean isPermanent() { return isPermanent; }
    public void setPermanent(boolean permanent) { isPermanent = permanent; }

    public String getFullName() {
        return givenName + " " + familyName;
    }
}

Accès aux propriétés simples

Pour les types primitifs, leurs wrappers (Integer, Boolean, etc.) et String, utilisez les méthodes dédiées :

  • PropertyUtils.getSimpleProperty(obj, "propertyName")
  • PropertyUtils.setSimpleProperty(obj, "propertyName", value)

Exemple d’utilisation :

StaffMember staff = new StaffMember();
PropertyUtils.setSimpleProperty(staff, "givenName", "Alex");
PropertyUtils.setSimpleProperty(staff, "familyName", "Dubois");

String fullName = (String) PropertyUtils.getSimpleProperty(staff, "fullName");
System.out.println(fullName); // Affiche "Alex Dubois"

Gestion des propriétés indexées

Les collections comme List, ArrayList ou les tableaux peuvent être manipulées via des indices numériques :

  • PropertyUtils.getIndexedProperty(obj, "listProperty[0]")
  • PropertyUtils.getIndexedProperty(obj, "listProperty", 0)
  • PropertyUtils.setIndexedProperty(obj, "intArray", 2, 42)

Classe supportant une liste :

public class Team {
    private List<StaffMember> members;
    private int[] scores;

    public List<StaffMember> getMembers() { return members; }
    public void setMembers(List<StaffMember> members) { this.members = members; }

    public int[] getScores() { return scores; }
    public void setScores(int[] scores) { this.scores = scores; }
}

Utilisation :

Team team = new Team();
team.setMembers(Arrays.asList(new StaffMember(), new StaffMember()));
team.setScores(new int[]{10, 20, 30});

// Accès direct par indice
StaffMember first = (StaffMember) PropertyUtils.getIndexedProperty(team, "members[0]");
PropertyUtils.setIndexedProperty(team, "scores", 1, 99);

System.out.println(team.getScores()[1]); // Affiche 99

Accès aux propriétés mappées

Pour les structures clé-valeur comme Map<String, Object>, on utilise des clés littérales :

  • PropertyUtils.getMappedProperty(obj, "mapProperty(key)")
  • PropertyUtils.getMappedProperty(obj, "mapProperty", "key")
  • PropertyUtils.setMappedProperty(obj, "mapProperty", "key", value)

Exemple :

public class Configuration {
    private Map<String, Object> settings;

    public Map<String, Object> getSettings() { return settings; }
    public void setSettings(Map<String, Object> settings) { this.settings = settings; }
}

Configuration cfg = new Configuration();
cfg.setSettings(new HashMap<>());

PropertyUtils.setMappedProperty(cfg, "settings", "timeout", 3000);
PropertyUtils.setMappedProperty(cfg, "settings", "debugMode", true);

Object timeout = PropertyUtils.getMappedProperty(cfg, "settings", "timeout");

Navigation dans les structures imbriquées

BeanUtils permet de parcourir des chaînes de propriétés complexes en combinant plusieurs notations :

  • "employee.department.manager.name" → accès à un champ profondément imbriqué ;
  • "employees[2].skills[0].level" → combinaison d’indexaiton et d’imbrication ;
  • "config.settings(timeout)" → mélange de mapping et d’imrbication.

Exemple complet :

public class Organization {
    private List<StaffMember> staff;
    private Map<String, Department> departments;

    // Getters/setters omis pour concision
}

public class Department {
    private String name;
    private StaffMember head;

    // Getters/setters omis
}

Organization org = new Organization();
Department dept = new Department();
dept.setName("Engineering");
dept.setHead(new StaffMember());
dept.getHead().setFamilyName("Martinez");

Map<String, Department> deps = new HashMap<>();
deps.put("eng", dept);
org.setDepartments(deps);

String headLastName = (String) PropertyUtils.getNestedProperty(
    org, "departments(eng).head.familyName"
);
System.out.println(headLastName); // Affiche "Martinez"

Méthode uinverselle : getProperty / setProperty

La méthode générique PropertyUtils.getProperty() reconnaît automatiquement le type de propriété (simple, indexée, mappée ou imbriquée) à partir de la syntaxe du chemin fourni. Elle élimine le besoin de choisir manuellement entre les variantes spécialisées.

Exemple unifié :

Object value = PropertyUtils.getProperty(org, "departments(eng).head.givenName");
PropertyUtils.setProperty(org, "departments(eng).head.givenName", "Carlos");

// Fonctionne aussi pour :
// - "staff[0].startDate"
// - "config.settings(debugMode)"
// - "metadata.tags[1]"

Étiquettes: apache-commons-beanutils java-reflection javabeans property-access java-library

Publié le 4 août à 21h56