Bonjour,

J'ai un problème avec Hibernate, une association one-to-many et les listes associées. Dans mon modèle, j'ai une classe Country et, pour chaque instance de Country, j'ai plusieurs informations qui décrivent une structure pour les adresses associées à cette instance.

Voici ma classe Country :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
 
    public class Country {
 
    private Long id;
    private String name;
    private List<AddressElement> addressElementList = null;
    ...
    }
ma classe AddressElement :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
 
    public class AddressElement {
 
    private Long id;
    private int pos;
    private int line;
    private String name;
    private String mask;
    ...
    }
et le mapping hibernate :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    <hibernate-mapping  package="org.devtutos.tuto5.domaine">								
    <class  name="Country" table="tuto.COUNTRY" >
		<id name="id" type="java.lang.Long" column="COUNTRY_ID" unsaved-value="null">		
			<generator class="native">	
				<param name="sequence">tuto.SEQ_COUNTRY</param>
			</generator>
        </id>
        <natural-id mutable="true">
       		<property 	name="name"  column="COUNTRY_NAME" type="java.lang.String"/>      
        </natural-id>
    	<list name="addressElementList" table="tuto.ADDRESS_ELEMENT" lazy="false">
          <key  foreign-key="country_address_element_fk">
          	<column name="COUNTRY_ID" not-null="true"/>	
          </key>
          <list-index>
               <column name="ADDRESS_ELEMENT_POS" not-null="true" />
          </list-index>
          <one-to-many class="AddressElement"/>   
    	</list>
    </class>
    </hibernate-mapping>
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
    <hibernate-mapping  package="org.devtutos.tuto5.domaine">								
    <class  name="AddressElement" table="tuto.ADDRESS_ELEMENT" >
		<id name="id" type="java.lang.Long" column="ADDRESS_ELEMENT_ID" unsaved-value="null">		
          <generator class="native">	
          		<param name="sequence">tuto.SEQ_ADDRESS_ELEMENT</param>
          </generator>
        </id>
        <property name="line" column="ADDRESS_ELEMENT_LINE" not-null="true" type="java.lang.Integer" />
        <property name="name" column="ADDRESS_ELEMENT_NAME" not-null="true" type="java.lang.String" />
        <property name="mask" column="ADDRESS_ELEMENT_TYPE_MASK" not-null="true" type="java.lang.String" />
        <property name="pos" column="ADDRESS_ELEMENT_POS" not-null="true" type="java.lang.Integer" />
    </class>
    </hibernate-mapping>
Voici mon code :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    criteria = getSessionFactory().getCurrentSession().createCriteria(Country.class);
    criteria.add(Restrictions.eq("name", countryName));
    criteria.setFetchMode("addressElementList",FetchMode.JOIN);
 
    Country country = (Country) criteria.list().get(0);
 
    if (country == null) {
 
    	logger.log(Level.INFO, "ERREUR DE COHERENCE INTERNE : Pays '".concat(countryName).concat("'non trouvé:"));
    }
    else {
    	logger.log(Level.INFO, "Pays trouvé.");
    	logger.log(Level.INFO, "Nom du Pays :".concat(country.getName()));
    	logger.log(Level.INFO, "Code du Pays :".concat(String.valueOf(country.getId())));
    	liste = country.getAddressElementList();
    	logger.log(Level.INFO, "Taille de la liste des éléments d'adresse :".concat(String.valueOf(liste.size())));
    	for (AddressElement elem : liste){
    		if (elem == null) {logger.log(Level.INFO, "L'élément d'adresse est null.");}
    			logger.log(Level.INFO, "Element de la liste : ID = ".concat(String.valueOf(elem.getId())));    **** Line of the error
    			logger.log(Level.INFO, "Element de la liste : POS = ".concat(String.valueOf(elem.getPos())));
    			logger.log(Level.INFO, "Element de la liste : NOM = ".concat(elem.getName()));
    		}
    	}
    }
Et voici ma log :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
    Hibernate: 
    select 
    this_.COUNTRY_ID as COUNTRY1_2_1_, 
    this_.COUNTRY_NAME as COUNTRY2_2_1_, 
    addressele2_.COUNTRY_ID as COUNTRY6_2_3_, 
    addressele2_.ADDRESS_ELEMENT_ID as ADDRESS1_3_, 
    addressele2_.ADDRESS_ELEMENT_POS as ADDRESS5_3_, 
    addressele2_.ADDRESS_ELEMENT_ID as ADDRESS1_0_0_, 
    addressele2_.ADDRESS_ELEMENT_LINE as ADDRESS2_0_0_, 
    addressele2_.ADDRESS_ELEMENT_NAME as ADDRESS3_0_0_, 
    addressele2_.ADDRESS_ELEMENT_TYPE_MASK as ADDRESS4_0_0_, 
    addressele2_.ADDRESS_ELEMENT_POS as ADDRESS5_0_0_ 
    from 
    tuto.COUNTRY this_ left outer join tuto.ADDRESS_ELEMENT addressele2_ 
    on this_.COUNTRY_ID=addressele2_.COUNTRY_ID 
    where 
    this_.COUNTRY_NAME=?
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Pays trouvé.
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Nom du Pays :FRANCE
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Code du Pays :1
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Taille de la liste des éléments d'adresse :4
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: L'élément d'adresse est null.
    27 déc. 2012 16:19:09 org.apache.catalina.core.StandardWrapperValve invoke
    GRAVE: Servlet.service() for servlet [tuto5] in context with path [/tuto-5] threw exception [Request processing failed; nested exception is org.springframework.webflow.execution.ActionExecutionException: Exception thrown executing [AnnotatedAction@3f610944 targetAction org.devtutos.tuto5.mvc.webflow.action.receptionAction@4dc6bbd3, attributes = map['method' -> 'enregistrerLUtilisateur']] in state 'enregistrerLUtilisateur' of flow 'reception' -- action execution attributes were 'map[[empty]]'] with root cause
    java.lang.NullPointerException
    at org.devtutos.tuto5.dao.CountryHibernate.getCountryByName(CountryHibernate.java:103)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:319)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    ...
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:395)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:250)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:166)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
Je ne peux pas accéder aux informations des éléments d'adresse pour mon instance de Country. J'ai essayé plusieurs choses : J'ai positionné le "lazy mode" à "true" et spécifié le "fetch mode" à "JOIN" mais cela ne marche pas. Le plus surprenant est que la liste est alimentée ( Il y a quatre éléments ) et le code suivant fonctionne correctement (Ainsi, les informations dans la base de données et les accesseurs sont corrects ) :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
    logger.log(Level.INFO, "Lecture de tous les éléments d'adresse.");
    criteria = getSessionFactory().getCurrentSession().createCriteria(AddressElement.class);
    liste = criteria.list();
    logger.log(Level.INFO, "Taille de la liste des éléments d'adresse : ".concat(String.valueOf(liste.size())));
    for (AddressElement elem : liste){
    	if (elem == null) {logger.log(Level.INFO, "L'élément d'adresse est null.");}
    	logger.log(Level.INFO, "Element de la liste : ID = ".concat(String.valueOf(elem.getId())));
    	logger.log(Level.INFO, "Element de la liste : POS = ".concat(String.valueOf(elem.getPos())));
    	logger.log(Level.INFO, "Element de la liste : NOM = ".concat(elem.getName()));
    }
Voici le résultat de ce code :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
    INFO: Lecture de tous les éléments d'adresse.
    Hibernate: select this_.ADDRESS_ELEMENT_ID as ADDRESS1_0_0_, this_.ADDRESS_ELEMENT_LINE as ADDRESS2_0_0_, this_.ADDRESS_ELEMENT_NAME as ADDRESS3_0_0_, this_.ADDRESS_ELEMENT_TYPE_MASK as ADDRESS4_0_0_, this_.ADDRESS_ELEMENT_POS as ADDRESS5_0_0_ from tuto.ADDRESS_ELEMENT this_
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Taille de la liste des éléments d'adresse : 6
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Element de la liste : ID = 1
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Element de la liste : POS = 1
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Element de la liste : NOM = Code Postal
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Element de la liste : ID = 2
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Element de la liste : POS = 2
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Element de la liste : NOM = Ville
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Element de la liste : ID = 3
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Element de la liste : POS = 3
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Element de la liste : NOM = Batiment
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Element de la liste : ID = 4
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Element de la liste : POS = 1
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Element de la liste : NOM = District
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Element de la liste : ID = 5
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Element de la liste : POS = 2
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Element de la liste : NOM = Zone
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Element de la liste : ID = 6
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Element de la liste : POS = 1
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
    INFO: Element de la liste : NOM = City
    27 déc. 2012 16:19:09 org.devtutos.tuto5.dao.CountryHibernate getCountryByName
J'ai remarqué dans la première exécution que la taille de liste n'est pas bonne ( 4 au lieu de 3 ). Dans mon exemple, la valeur de "countryName" est "FRANCE". Voici le contenu de mes tables pour le test :

COUNTRY :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
    COUNTRY_ID		CONTRY_NAME 
    1			"FRANCE"
    2			"HYPERION"
    3			"ATLANTIS"
ADDRESS_ELEMENT :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
 
    ADDRESS_ELEMENT_ID		COUNTRY_ID		ADDRESS_ELEMENT_POS    	ADDRESS_ELEMENT_NAME    ADDRESS_ELEMENT_MASK	       ADDRESS_ELEMENT_LINE
    1				1			1		        "Code Postal"           "\d{5}"				1
    2				1			2		        "Ville"			"[A-Z\-]{1,50}"			1
    3				1			3		        "Batiment"		"[A-F]"				1
    4				2			1		        "District"		"[A-Z]{1,20}"			1 
    5				2			2		        "Zone"		        "[A-5]{1,5}"			2
    6				3			1		        "City"			"[A-Z]{1,9}"			1
Qu'est-ce que je fais de mal ? Je ne comprends pas pourquoi "elem" est null dans la première exécution. J'ai besoin d'aide.

Je vous remercie par avance.

Bonne année à tous. ;-)