Hi,
I have a problem with Hibernate, one-to-many associations and lists. In my model, I have country and, for each country, I have multiple informations who describe a structure for adresses in that country. I want to access the list of these elements.
This my class Country :
Code:
public class Country {
private Long id;
private String name;
private List<AddressElement> addressElementList = null;
...
}
my class AddressElement :
Code:
public class AddressElement {
private Long id;
private int pos;
private int line;
private String name;
private String mask;
...
}
and my mappings :
Code:
<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:
<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>
This my code :
Code:
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()));
}
}
}
This my log :
Code:
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)
I can't access the informations of address elements from a country. I tried several things : I turn the lazy mode to "true" and specify a fetch mode with JOIN but it doesn't work. The most surprising is the list is alimented ( there are 4 elements ) and the following code run well ( So, informations in database, setters and getters works ) :
Code:
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()));
}
These is the result of this code :
Code:
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
I notice in my first execution that the size of my list is wrong ( 4 in place of 3 ). In my example, the value of countryName is "FRANCE". This is the content of my tables :
COUNTRY :
Code:
COUNTRY_ID CONTRY_NAME
1 "FRANCE"
2 "HYPERION"
3 "ATLANTIS"
ADDRESS_ELEMENT :
Code:
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
Where am I wrong? I don't understand why "elem" is null in the first execution. Can somebody help me?
Thanks by advance.
Have a good year. ;-)