05 octobre 2010

@Properties

Comme de bons petit soldats, nous avons appris à définir nos attributs de classe en private et à générer des getter/setter pour y accéder. Nos classes se trouvent ainsi encombrées de ces méthodes sans grand intérêt. Après tout, pourquoi ne pas laisser nos attributs publics ? Pour l'encapsulation vous répondra maître Yoda, en ayant la possibilité (s'il le faut un jour) d'intervenir lors d'un accès aux données de la classe. OK, mais c'est bien dommage de polluer ainsi notre code :'(

On peut bien sûr utiliser exceptionnellement une syntaxe compacte, mais encore faut-il que le formateur de code et les règles Checkstyle de votre Q&A soient réglées en conséquence.

Des langages comme Groovy ou Scala disposent nativement du concept de propriété, qui permet d'intercepter les accès aux données de la classe via un getter/setter, mais seulement quand c'est nécessaire. Pour Java 7, le projet Coin proposait d'ajouter le concept de propriété dans le langage Java. Le sujet a fait débat et je ne suis même pas sur du statut de cette proposition.

Cependant, pour ceux qui aiment bien cette idée, il y a une alternative à attendre cette fonctionnalité dans Java 7 (ou 8 ? ou 9 ?) : lombok

Lombok utilise un hack de l'annotation processor de Java 6 : il vient modifier la structure du code source (la structure AST, pas le fichier .java) pour ajouter des getter et setter à chaque attribut annoté en conséquence. Votre .class comporte donc bien ces méthodes et votre IDE vous laissera les utiliser, mais elles resteront absentes du code source, tant que vous n'avez pas besoin de les définir vous même. Lombok peut faire même beaucoup plus, comme générer equals(), hashcode() et toString(), ou gérer les exceptions ou la synchronisation par simple apposition d'une annotation (dites "méta-programmation", ça fait plus classe). Si cette dernière option peut faire peur - mais rappeler vous la première fois que vous avez fait du spring-aop avec @Transactional - l'utilisation sur les getter/setter justifie l'outil à elle seule.

A tester d'urgence : http://projectlombok.org

11 commentaires:

Antonio Goncalves a dit…

Un jour j'ai eu une révélation. Je débuggai le code de JBoss Messaging et je suis tombé sur des attributs publics (pas de getters ni setters). En questionnant les développeurs, ils m'ont répondu que ce qui les intéressaient c'était de livrer une API claire à l'utilisateur. Leur tambouille interne, c'est leur pb.

Avec la future modularisation de Java, on pourra peut-être ne rendre visible que certaines parties de notre code. Si c'est le cas (ex. je fournit uniquement une interface à mon utilisateur et tout le reste est invisible), alors, sans vergogne, je mettrai par défaut mes attributs en public ! (et j'encapsulerai si besoin)

olamy a dit…

franchement pour des beans de données/transfert tout mettre en public suffit IMHO et ce serait plus lisible !
Mais le problèmes reste les frameworks web (ie struts) ou autres (digester par exemple) qui s'attendent aux sacro saint getX/setX.
Qui ne font qu'une affectation ou une simple lecture.
Je suis bien d'accord à part obscurcir le code pas beaucoup d'intérêt !

Unknown a dit…

Pour avoir tenté le coup des attributs publics sur un projet, j'ai malheureusement fini par être stoppé net par Hibernate, qui ne pouvait plus faire de lazy loading correctememt.

Il m'a donc fallu arrêter d'être fainéant, pour pouvoir permettre à Hibernate de l'être !

Colin Hebert a dit…

Pour le côté pratique et facilité, c'est okay il n'y a aucun soucis, le problème c'est que c'est basé sur une grosse bidouille et que tous les IDE (IntelliJ entre autres) ne gère pas cette fameuse bidouille.

Il serait peut-être interessant de voir cette approche intégrée un peu plus officiellement (soit dans le JDK, soit dans un framework conséquent) pour la populariser et que ça ne soit plus "la bidouille du développeur qui à trouvé que coder les getters/setters ça polluait le code".

Olivier Croisier a dit…

Personnellement je fuis Lombok comme la peste.

Le gain est nul, il n'apporte aucune fonctionnalité que n'offre pas un IDE. Par exemple, Eclipse génère très bien les getters/setters, toString, etc. en 2 raccourcis clavier (alt-shift-S R et alt-shift-S S respectivement...). Lombok me fait gagner du temps", c'est donc juste de la mauvaise foi.

Par contre, il utilise les classes internes des compilateurs pour faire du hors-piste total (hors-spec je devrais dire), et pour moi c'est dangereux. Si Lombok ne supporte pas votre prochaine version de compilateur, vous pouvez jeter votre code : il coûtera aussi cher à réadapter qu'à recoder. Build-breaker en puissance.

Bref, pour moi, Lombok c'est NON.

Anonyme a dit…

Aores un an d'utilisation, pour moi Lombok c'est OUI ! C'est sûr qu'il y a des gros point noir déjà évoqués, mais pour un ensemble de projets sous Eclipse, moi et tout mes collegues ne pouvons plus nous en passer. de mon point de vue, c'est surtout la clarté du code qui est le principal avantage. pas les 2 secondes 1/2 gagnées à éviter de coder/générer un getter.

@Getter private String toto; => montre bien que 'toto' est une donnée connue par la classe et exposée
@Setter private String titi; => montre que 'titi' n'est connu qu'en interne.
La différence est claire, nette, précise, pas la peine d'aller chercher dans l'overview des methodes s'il y a un eventuel getter ou setter.
Du code concit qui est expressif, ca n'a pas de prix.
Bon, bien sûr, l'idéal serait de ne pas avoir besoin de Lombok et d'avoir l'équivalent au niveau du langage. or on ne l'a pas... Pour rien au monde je ne quitterai Lombok apres y avoir gouté ;)
Surtout qu'on peut toujours "délomboker" facilement un projet si le besoin se fait sentir de passer sous un autre IDE que Eclipse.

Nicolas De Loof a dit…

@Olivier tu n'as pas saisi : l'intérêt n'est pas d'économiser trois secondes dans l'IDE mais de ne pas polluer le code source de choses inutiles. Le code métier est déjà largement trop lourd avec nos itérateurs et autres constructions techniques, je ne sais pas si tu a déjà comparé avec l'équivalent Groovy.

Par ailleurs, non standard ok, mais dans ce sens AspectJ aussi est un compilo non standard et pourtant apporte une grande plus-value.

coutant a dit…

En plus de Groovy, c'est intéressant de voir l'approche d'un autre langage couramment utilisé, mine de rien.

En AS3, le langage des appli Flash/Flex, une classe cliente accède à une propriété/accesseur avec l'unique syntaxe ".xxx".

Coté implémentation, on peut choisir de mettre en oeuvre une simple propriété publique. Si par la suite on a besoin d'insérer un traitement lors de l'accès il suffit de remplacer la propriété par une méthode de même nom en utilisant le qualifieur "get" ou "set".

Aucun changement coté classe cliente: code lisible avec .xxx, sans avoir à ce soucier de la dualité .xxx vs .getxxx() ou .setXxx(.).

Dominique De Vito a dit…

Je crois qu'il doit être possible de gérer les méthodes get/set à la Lombox, avec rétro-compatibilité, dans une prochaine version de Java.

Il suffit de penser à une méthode get comme une forme de boxing (cf. auto-boxing des valeurs primitives) = vu/présenté comme cela, il me semble que l'introduction de cette fonctionnalité serait plus facilement comprise et donc, acceptée.

Donc, dans ce cas de figure, si l'on utilise A.xxx (ici, en mode lecture) et que getXxx() existe, on devrait appeler le méthode getXxx(), sinon utiliser le champ xxx directement. Idem pour la méthode set.
Et inversement, si l'on utilise getXxx() et que le champ xxx n'est pas associé à une méthode get, alors pas grave : on utilise le champ directement.

L'idéal serait que Oracle utilise le JDK 7 pour fournir en test, nombre de fonctionnalités (comme celle indiquée plus haut), activables par propriété du compilo et de la JVM, de manière à ce que l'on puisse se faire la main et donner notre avis.

Unknown a dit…

Je crois qu'il y a eu des annonces pour le support des properties en Java (peut etre pour JDK 8?) à Devoxx, tu as plus de détails là dessus?

Loïc

Nicolas De Loof a dit…

Des suggestions, des rumeurs, mais rien de sur... Les ValueObject devraient introduire quelque chose qui va dans ce sens, sans être généralisé. Wait & See (de toute façon, Java 8 ce n'est pas avant fin 2012...)