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 bloc synchronized ;
  • @SneakyThrows qui nous permet de ne pas écrire de try catch ou de throws dans/sur notre méthode. L’exemple décrit ci-après est l’UnsupportedEncodingException du constructeur String 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éthode close sur des Stream dans différents try 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’interface Iterable<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’objet listDelegate et n’a ainsi absolument plus besoin de définir toutes les méthodes de l’interface Iterable<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 de MyClass 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

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Nous recrutons

Être un Sapient, c'est faire partie d'un groupe de passionnés ; C'est l'opportunité de travailler et de partager avec des pairs parmi les plus talentueux.