Il y a 13 ans -
Temps de lecture 5 minutes
Devoxx – Jour 5 – Projet Lombok
Parce que toutes les bonnes choses ont une fin, voici venir pour moi la dernière session de ce Devoxx 2009 avec le Projet Lombok présenté par les développeurs de l’outil (Roel Spilker et Reinier Zwitserloot).
L’objectif de ce produit est de nous faire gagner du temps et d’améliorer la lisibilité de nos classes. Comment ? Et bien, moyennant quelques annotations, l’outil va par exemple générer pour nous les méthodes toString
, equals
et hashcode
mais aussi les getters et setters de notre POJO. Certes, nos IDEs nous proposent déjà ce travail mais il subsiste 2 différences de taille :
- ce n’est plus au développeur d’appeler les Generate xxx d’eclipse, la génération de ces méthodes se fera à l’import des annotations ou à la sauvegarde du fichier ;
- mais surtout, la génération de ces méthodes ne se fait pas dans le code source Java mais directement dans le Bytecode, nos POJOs restent donc clean.
Côté IDE
Prenons par exemple une classe standard avec une propriété firstname
et une propriété lastname
. En y ajoutant simplement l’annotation @Data (décrite ci-après dans l’article), nous pouvons constater que la vue Outline d’eclipse s’est bien mise à jour avec les méthodes getFirstName
, setFirstName
, toString
etc… . Bien que non implémentées, ces méthodes existent et sont totalement fonctionnelles au sein du projet dans eclipse :

Côté code
Plusieurs annotations nous sont proposées. Chacune possède sa spécificité / spécialité :
@Getter
et@Setter
avec prochainement@Property
qui fera les 2 ;@ToString
;@EqualsAndHashCode
;@Data
qui regroupe les 4 annotations précédentes ;@Synchronized
qui nous permet de simplifier l’écriture de blocsynchronized
;@SneakyThrows
qui nous permet de ne pas écrire detry catch
ou dethrows
dans/sur notre méthode. L’exemple décrit ci-après est l’UnsupportedEncodingException
du constructeurString
avec par exemple UTF-8 comme Charset : cette exception ne pourra jamais être levée car la JVM doit fournir UTF-8 ;@Cleanup
qui nous enlève le lourd poids de devoir appeler la méthodeclose
sur desStream
dans différentstry finally
.
Toutes ces annotations sont bien sûr paramétrables (AccessLevel, exclude, of, staticConstructor…) ce qui nous permet entre autres d’inclure ou d’exclure certains champs du processus de génération (idéal pour un equals
ou un toString
).
Ces annotations paramétrables (voir AccessLevel, exclude, of, staticConstructor etc…) influent directement sur le code généré. Ainsi on peut régler à sa guise, portée, visibilité, ou utilisation des attributs de la classe. Cela peut être très pratique pour des méthodes telles que equals
ou hashcode
.
Voici un exemple de code d’une classe Java lombok-ifée :
// @Data does @Getter, @Setter, @ToString and @EqualsAndHashCode @ToString @EqualsAndHashCode public class MyPojo { private @Getter @Setter(AccessLevel.PUBLIC) String firstname; private @Getter(AccessLevel.PROTECTED) @Setter(AccessLevel.PRIVATE) String lastname; @Synchronized @SneakyThrows({UnsupportedEncodingException.class, IOException.class}) public void init() { setFirstname("foobar"); @Cleanup InputStream in = new FileInputStream("c:/input.txt"); @Cleanup OutputStream out = new FileOutputStream("c:/output.txt"); byte[] bytes = new byte[10000]; while (true) { int r = in.read(bytes); if (r == -1) break; out.write(bytes, 0, r); } setLastname(new String("abc".getBytes(), "UTF-8")); } public static void main(String[] args) { MyPojo myPojo = new MyPojo(); myPojo.init(); System.out.println(myPojo.toString()); System.out.println(myPojo.equals(new MyPojo())); } }
Incubation
L’équipe travaille actuellement sur d’autres annotations et plus globalement sur des améliorations de syntaxe Java :
@Delegate
sur une propriété d’une classe faisant que cette classe hériterait des méthodes de cette propriété. On pourrait donc avoir une classe qui implémente l’interfaceIterable<Something>
et qui aurait une propriété@Delegate Iterable<Something> listDelegate = new ArrayList<Something>()
: la classe récupère ainsi toutes les méthodes de l’objetlistDelegate
et n’a ainsi absolument plus besoin de définir toutes les méthodes de l’interfaceIterable<Something>
côté Java (par contre côté Bytecode tout est là !) ;@Mixin(MyClass.class)
qui permet de rajouter dynamiquement du comportement à une classe, en l’occurrence les méthodes deMyClass
dans la classe qui aurait définit cette annotation ;- Le
String
multi-lignes avec les 3 guillemets d’ouverture et les 3 autres de fermeture avec au milieu autant de retours à la ligne que vous le souhaitez ; - La création de liste simplifiée à partir d’une autre liste avec une syntaxe très particulière :
Mountain m : mountainList where (m.getAltitude() > 1000) select (m.getName())
qui ferait qu’en une ligne on passe d’une liste de montagne à une liste de nom de montagne.
Limitations
Malgré les avancées notables de cette solution, des difficultés subsistent. L’intégration avec les IDEs, notamment pour les fonctions de refactoring, est à compléter. Car dans ce cas, le code n’existant pas (dans le fichier java), il est ardu de faire du refactoring.
Pour l’instant, seul Eclipse est supporté par Lombok. Cependant l’équipe travaille au support pour Netbeans et depuis peu pour IntelliJ IDEA Community Edition.
Les fonctionnalités sont charmantes, mais on peut constater que la route est encore longue. D’ailleurs, les speakers le reconnaissent volontiers quand ils annoncent avec humour que : « la montagne est haute mais pas insurmontable » :)

Conclusion
Un outil à surveiller donc, et qui pourrait bien finir dans notre classpath une fois stabilisé, compatible avec les IDEs du marché et production-ready.
En attendant, vous pouvez jouer avec en le récupérant à cette url. Et n’oubliez pas d’exécuter le JAR afin de patcher votre eclipse.
Commentaire