Spring : Merger des collections

Ce billet aborde la notion de "merge" (fusion) des collections dans Spring. Cette notion, présente depuis la version Spring 2.0, repose sur l'héritage des définitions des Beans de Spring que nous expliquerons brièvement.
Les exemples donnés sont créés simplement dans un projet java sous eclipse (sans recours à maven).
Un seul pré-requis : connaître la déclaration des collections dans Spring.

Héritage des définitions beans de Spring

Je pense qu'un exemple est plus parlant qu'un long discours pour comprendre cette notion.
Nous allons donc écrire un bean simple, nommé à juste titre classeParent, puis le déclarer dans le fichier de configuration de spring.

Enfin nous déclarons, dans le fichier xml de Spring, une nouvelle (définition) du nouveau bean, nommé classeChild, qui hérite de la définition de classeParent.
Ci-après, la seule classe POJO, ClasseParent.java, déclarant trois attributs avec ses setters/getters (omis ici) :

/** classe ClasseParent**/
package ch1.container.collections;
public class ClasseParent {
	private String nom;
       private String prenom;
	private float points ;
 
	public String toString(){
		return "nom="+getNom()+ " prenom="+getPrenom()+" points:"+getPoints();
	}
//*** les getters/setters sont omis....
}

Le fichier de Spring, nommé spring_collections.xml, déclare ce(s) bean(s) :

<bean id="classe1Parent" class="ch1.container.collections.ClasseParent">
	<property name="nom">
		 <value>CHINE</value>
	</property>
       <property name="prenom">
		 <value>Abderazek</value>
	</property>
	<property name="points">
		<value type="float">200</value>
	</property>
</bean>

Nous ajoutons à ce fichier xml, les lignes ci-après afin de déclarer un bean fils, avec id="classe1Child" qui hérite de toutes les propriétés de la définition du bean classe1Parent.
Notez que :

<!-- classe fille -->	
<bean id="classe1Child" parent="classe1Parent">		
 
       <property name="prenom">
		 <value>Anessem</value>
	</property>
 
	<property name="points">
		<value type="float">800</value>
	</property>
</bean>

Nous venons de voir que le bean classe1Child hérite de l'attribut "nom" et surcharge les attributs "prenom" et "points".
Évidemment, l'intérêt de tout cela saute aux yeux.
Enfin, écrivons la classe TheMain, de test.

package ch1.container;
public class TheMain {
	private static Logger logger=Logger.getLogger("ch1.container.TheMain");
public static void main(String[] args) {
/** point d entree de spring : récupérer dans le fichier xml le bean**/  
 ApplicationContext ctx=(ApplicationContext) new ClassPathXmlApplicationContext(new String[]{"resources/spring_collections.xml"});
  ClasseParent classeParent=(ClasseParent) ctx.getBean("classe1");
 logger.info(">>classeParent:"+classeParent);
 ClasseParent classeChild=(ClasseParent) ctx.getBean("classe1Child");
 logger.info(">>classeChild:"+classeChild);
}

Assurez-vous d'avoir dans le classpath les trois jars suivants : spring-2.5.x.jar; log4j-1.2.x.jar et commons-loggings-1.1.x.jar.
Exécutez la classe sous eclipse (ou encore sous dos). Vous obtenez à peu près ces lignes (extraits) :

INFO: >>classeParent:nom=CHNE prenom=Abderazek points:200.0
** juin 2009 **** ch1.container.TheMain main
INFO: ==classeChild>>nom=CHINE prenom=Anesssem points:800.0

Merger les collections dans Spring

Dans cette seconde partie, nous écrivons une nouvelle classe java que l'on nommera ClazzParent avec ces lignes de code :

package ch1.container.collections;
 
import java.util.Map;
 
public class ClazzParent {
 
	private Map<String,String> proprietes;
	private Map<String,Float> anotherMap;
	//** setters/getters omis...
	public String toString(){
		return getProprietes().toString()+"
"+getAnotherMap();
	}
}

Et le fichier spring_collections.xml doit comporter la déclaration du bean clazzParent comme suit :

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">
<!-- partie merging collections -->
	<bean id="clazzParent" class="ch1.container.collections.ClazzParent">
		<property name="proprietes">
			<props>
				<prop key="administrator">administrator@example.com</prop>
				<prop key="support">support@example.com</prop>
			</props>
		</property>		
		<property name="anotherMap" ref="chiffresMap" />
	</bean>	
	<!--  child from clazzParent with merging map/properies/list/set -->
	<bean id="clazzChild" parent="clazzParent"> <!--  note parent= -->
		<property name="proprietes">
			<props merge="true"> <!--  note merge=true -->
				<prop key="adjointAdmin">admin2@example.com</prop> <!--  new property -->
				<prop key="support">sav@example.com</prop>         <!-- surcharge valeur existante -->
			</props>
		</property>
		<property name="anotherMap" ref="chiffresMap2"/>           <!-- override	-->
	</bean>
	<util:map id="chiffresMap">
		<entry key="chiffre1" value="22.35" />
		<entry key="chiffre2" value="120.20" />
	</util:map>
	<util:map id="chiffresMap2">
		<entry key="chiffre1" value="2299.95" />
		<entry key="chiffre2" value="1299.99" />
	</util:map>
 
</beans>

Il n'y a pas grand chose à expliquer puisque les commentaires insérés sont explicites!
La classe "clazzChild", ayant comme parent "ClazzParent", et ses attributs de type collections sont "mergés" car l'attribut de la propriété "merge" est positionné à "true".
On peut surcharger les valeurs comme expliqué dans le code xml.

Reste à écrire une classe "TheMain.java" permettant de tester ces fusions et surcharges :

public class TheMain {
 
	private static Logger logger=Logger.getLogger("ch1.container.TheMain");
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		/** point d entree de spring: déclarer dans le fichier spring.xml le bean**/  
		ApplicationContext ctx=(ApplicationContext)  new ClassPathXmlApplicationContext(new String[]{"resources/spring_all.xml"});
 
                ClazzParent clazzParent=(ClazzParent) ctx.getBean("clazzParent");
                logger.info(">>clazzParent: "+clazzParent);
		ClazzParent clazzChild=(ClazzParent) ctx.getBean("clazzChild");
                logger.info(">>>>child: "+clazzChild);
	}
}

L'exécution de TheMain affiche ceci :

** juin 2009 *** ch1.container.TheMain main
INFO: >>clazzParent: {support=support@example.com, administrator=administrator@example.com}
{chiffre1=22.35, chiffre2=120.2}
** juin 2009 *** ch1.container.TheMain main
INFO: >>>>child: {support=sav@example.com, adjointAdmin=admin2@example.com, administrator=administrator@example.com}
{chiffre1=2299.95, chiffre2=1299.99}

2 commentaires

Laisser un commentaire

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

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.