Maven affiche son classpath

Depuis que ce blog existe, je n’ai encore rien écrit sur l’outil qui m’a fait le plus pester dans ma tumultueuse vie de développeur : Maven.

Il semble qu’il y ait un sport national sur la planète Java : déverser des seaux d’insultes sur cet outil, devenu en quelques années incontournable. C’est d’ailleurs peut-être là la raison de cette haine : Maven est un outil que tout le monde devrait adorer, mais tellement mal fichu que l’on en vient à le haïr.

Entre les approximations et les zones d’ombre de la documentation, l’intelligence supposée de Maven, qui sait mieux que moi ce que je veux faire et comment je veux le faire, les bugs du produit lui-même, de sa conception, et encore plus de ses interactions avec les autres outils que l’on utilise au quotidien (Eclipse pour ne citer que lui), le nombre d’heures perdues à tenter de comprendre, débugger, parcourir les innombrables blogs à la recherche de l’élément qui a fait que le build de nuit s’est glorieusement vautré dès la première compilation, alors que la nuit précédente tout s’était bien passé, et qu’aucun commit n’a eu lieu entre les deux, vu qu’on est lundi matin, les raisons de cette haine sont nombreuses.

Et là, précieux lecteur, toi qui es un expert Ant, Ivy, Groovy et Gradle (oui, tout ça réuni), je t’entends bondir à la lecture de ces lignes, tu vas te ruer sur les commentaires de cet article pour m’expliquer combien j’ai raison, et combien je ferais mieux de passer à l’outil que toi, tu utilises avec succès depuis des mois (voire plus), sans aucun problème. Merci, je sais. Que cela ne t’empêche pas de faire dans ces commentaires le prosélytisme auquel tu es habitué, sur l’autre précieux lecteur de ce blog. Car ce n’est pas pour me vanter, mais l’audience de Java le soir est en augmentation, et je suis en mesure d’annoncer qu’aujourd’hui, vous êtes au moins deux à lire ce blog.

Donc aujourd’hui, comme suite à un blog de Brice Dutheil, commiter actif de l’excellent Mockito, et avec lequel j’ai régulièrement le plaisir de discuter autour d’une bonne bière, je publie un pauvre code à deux balles (j’en ai presque honte), que j’utilise depuis des années pour afficher le contenu du classpath de Maven. Le genre d’outil inutile dans une situation où tout marche sans problème, donc indispensable dans Maven.

Dans Maven

Son intégration dans Maven donne ce genre de choses, la méthode consiste à utiliser le plugin Ant. Premier tour de ce numéro, afficher le classpath Maven, dans Maven.

<build>
	<plugins>
		<plugin>
			<artifactId>maven-antrun-plugin</artifactId>
			<version>1.6</version>

			<configuration>
				<target>
					 <pathconvert pathsep="${line.separator}|   |-- "
					              property="compile_fileset"
					              refid="maven.compile.classpath">
					</pathconvert>
					<echo message="|-- compile classpath"/>
					<echo message="|   |"/>
					<echo message="|   |-- ${compile_fileset}"/>
				</target>
			</configuration>
		</plugin>
	</plugins>
<build>

Quand Ant utilise Maven

Plus difficile maintenant : je suis dans une tâche Ant, qui utilise la définition du classpath Maven. Cette tâche Ant peut être appelée d’un goal Maven, ou directement par Ant.

Voici le build.xml. Il doit se trouver à côté du fichier de configuration de Maven, défini ligne 19.

<project name="Mon projet"
         xmlns:artifact="antlib:org.apache.maven.artifact.ant">

	<!-- lien vers mon repository local -->
	<property name="repository.home" value="D:/maven/repository"/>

	<!-- chemin vers le JAR maven-ant-tasks
	     (ça ne doit pas être la dernière version) -->
	<path id="maven-ant-tasks.classpath" path=".../maven-ant-tasks-2.1.1.jar" />

	<!-- définition du prefixe artifact -->
	<typedef resource="org/apache/maven/artifact/ant/antlib.xml"
	         uri="urn:maven-artifact-ant"
		 classpathref="maven-ant-tasks.classpath" />

	<!-- configuration des références à Maven -->
	<artifact:localRepository id="local.repository"
	                          path="${repository.home}" layout="default"/>
	<artifact:pom file="pom.xml" id="maven.project"/>

	<!-- tâches de définition des classpath Maven, ils n'y sont pas tous -->
	<target name="resolve.dependencies">
		<artifact:dependencies pathId="compile.classpath"
		                       filesetId="compile.fileset"
		                       useScope="compile">
			<pom refid="maven.project"/>
		</artifact:dependencies>

		<artifact:dependencies pathId="runtime.classpath"
		                       filesetId="runtime.fileset"
		                       useScope="runtime">
			<pom refid="maven.project"/>
		</artifact:dependencies>

		<artifact:dependencies pathId="test.classpath"
		                       filesetId="test.fileset"
		                       useScope="test">
			<pom refid="maven.project"/>
		</artifact:dependencies>
	</target>

	<!-- affichage du classpath de compilation,
	     doit appeler resolve.dependencies -->
	<target name="debug" depends="resolve.dependencies">
		<pathconvert pathsep="${line.separator}|   |-- "
		             property="compile_fileset"
		             refid="compile.classpath">
		</pathconvert>
		<echo message="|-- compile classpath"/>
		<echo message="|   |"/>
		<echo message="|   |-- ${compile_fileset}"/>
	</target>
</project>

Comme tu peux le constater, précieux lecteur, utiliser Maven en dehors de Maven, ça se mérite…

Quand Maven appelle Ant

Encore plus difficile : je suis dans une tâche Ant définie dans un build.xml, appelée d’un goal Maven (ne reculons devant rien). Voici le pom.xml qui permet de faire le lien entre les deux, avec en prime un passage de paramètre, sans les mains !

<build>
	<plugins>
		<plugin>
			<artifactId>maven-antrun-plugin</artifactId>
			<version>1.6</version>

			<configuration>
				<tasks>
					<!-- build.xml se trouve à la racine du projet -->
					<ant antfile="${basedir}/build.xml">
						<target name="target-in-ant-file"/>
						<!-- my.property est définie ailleurs -->
						<property name="my.property"
						          value="${my.property}"/>
					</ant>
				</tasks>
			</configuration>
		</plugin>
	</plugins>
<build>

On peut même récupérer la valeur de la propriété my.property dans le build.xml de la façon suivante.

<project name="Mon projet">

	<!-- On récupère la propriété -->
	<property name="my.property" value="${my.property}"/>

	<target name="target-in-ant-file">
		<echo>my.property = ${my.property}</echo>
	</target>
</project>

Étonnant, non ?

Autres classpath

Maven expose plusieurs classpath :

  • le classpath de compilation : maven.compile.classpath ;
  • le classpath de test : maven.test.classpath ;
  • le classpath d’exécution : maven.runtime.classpath ;
  • et le classpath des plugins : maven.plugin.classpath.

Pour les afficher, il suffit de changer l’attribut refid de l’élément pathconvert de la tâche Ant (à peu de choses près).

Référence

Afficher les classpath de Maven (doc officielle, version illisible) : http://maven.apache.org/plugins/maven-antrun-plugin/examples/classpaths.html
Afficher un classpath depuis Ant (version lisible) : http://blog.andrewbeacock.com/2005/08/pretty-printing-java-classpaths-using.html

2 réflexions au sujet de « Maven affiche son classpath »

  1. Sinon, on peut aussi faire simple pour afficher le classpath:

    mvn dependency:build-classpath -DincludeScope=test

    Remplacer test par le scope que l’on souhaite.

  2. Je te trouve dur avec Maven. Ce n’est pas parfait non plus, mais il a permis de structurer les projets Java (ceux qui ont passé quelques heures à comprendre ou à intégrer un build Ant me comprendront).
    De plus, les problèmes que tu cites avec Eclipse viennent plus d’Eclipse (plus précisément, du plugin m2e) que de maven lui-même.

    Très bon blog au passage!

Les commentaires sont fermés.