Announcement Announcement Module
Collapse
No announcement yet.
Multiple Hibernate Mapping Locations Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Multiple Hibernate Mapping Locations

    I have a project which is broken up into a number of components or subprojects. Each component has its own hibernate mappings and is built into its own jar file.

    I want the ability to be able to configure different components to be included or excluded in different applications at build time.

    I'm trying to work out how to tell Spring about the hbm.xml mapping files but am having no luck. I have considered the following:

    1. During the build/deploy extract **/*.hbm.xml to a directory 'mapping' and then configure the LocalSessionFactoryBean.mappingDirectoryLocations to use classpath:mapping. But this only works if mapping is a normal directory. It does not work if mapping directory is packaged in a JAR. Luckily it does work in a WAR file, as most app servers extract the WAR onto the filesystem. But not all of my applications are going to be webapps. For standalone apps this is going to be painful and is already making it very difficult for me to start utilising the spring integration testing framework.

    2. Have each component manage and configure it's own mapping files using a hibernate*.cfg.xml. But LocalSessionFactoryBean.configLocation only allows for one such file, and I can no way to get a hibernate config file to include other hibernate config files. This would be my preferred configuration, with the LocalSessionFactoryBean not failing if it can not find a particular configLocation. This way I could have a common configuration, but an app would only include the configurations built into it at the time.

    3. Have each app individually manage every mapping file for every component it includes. This would be a maintenance nightmare, so not really worth considering.

    Am I missing something really obvious here?

    Cheers
    James

  • #2
    Take a look at the API for LocalSessionFactoryBean. You can load from the classpath or JAR files using setMappingLocations or setMappingJarLocations respectively. For example:
    Code:
    <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
        <property name="mappingLocations">
            <value>classpath*&#58;**/*.hbm.xml</value>
        </property>
            ...
    </bean>

    Comment


    • #3
      Unfortunately that style of syntax doesn't appear to work in this context.

      This seems to be because the mapping files are loaded using a Classloader, and sophisticated searches like that would go far past the original intent of Classloaders.

      I am going to have a play around with subclassing LocalSessionFactoryBean to allow me to build my own list of mapping resources. Hopefully that will give me what I am after.

      Comment


      • #4
        Works a treat, and quite easy when once I got started. Probably needs to be a bit more refined for public consumption, but if anyone should find it useful, here it is.

        Code:
        package au.com.emia.base.web.spring;
        
        import java.io.FileNotFoundException;
        import java.io.IOException;
        
        import org.apache.commons.logging.Log;
        import org.apache.commons.logging.LogFactory;
        import org.hibernate.HibernateException;
        import org.hibernate.cfg.Configuration;
        import org.springframework.core.io.Resource;
        
        /**
         * Extension of the spring LocalSessionFactoryBean that allows for multiple
         * hibernate config locations to be set, allowing modular mapping configuration.
         * 
         * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean
         * 
         * <P>
         * Copyright &#40;c&#41; Employers Mutual Limited
         * </P>
         * 
         * @author jw2&#58; May 18, 2005
         */
        public class LocalSessionFactoryBean extends
                org.springframework.orm.hibernate3.LocalSessionFactoryBean &#123;
            private static final Log LOG = LogFactory.getLog&#40;LocalSessionFactoryBean.class&#41;;
        
            private boolean mCheckConfigLocations = true;
        
            private Resource&#91;&#93; mConfigLocations;
        
            public LocalSessionFactoryBean&#40;&#41; &#123;
                super&#40;&#41;;
            &#125;
        
            /**
             * Set the location of a list of Hibernate XML config files, for example as
             * classpath resource "classpath&#58;hibernate.cfg.xml".
             * <p>
             * Note&#58; Can be omitted when all necessary properties and mapping resources
             * are specified locally via this bean.
             * <p>
             * Note&#58; If configLocation is also set, this will be treated as if it is at
             * the beginning of the list.
             * <p>
             * Note&#58; For each configuration item, the first one appears to take
             * precedence. So configLocation takes precedence over configLocations which
             * takes precedence over properties in the spring configuation. But all
             * mapping directives are processed irrespective of where they occur and in
             * what order. So configurations added here should <b>only </b> contain
             * <mapping&gt; elements to avoid unexpected behaviour.
             * 
             * @see org.hibernate.cfg.Configuration#configure&#40;java.net.URL&#41;
             */
            public void setConfigLocations&#40;Resource&#91;&#93; pConfigLocations&#41; &#123;
                mCheckConfigLocations = true;
                mConfigLocations = pConfigLocations;
            &#125;
        
            /**
             * Set the location of a list of Hibernate XML config files, for example as
             * classpath resource "classpath&#58;hibernate.cfg.xml". If a config location is
             * not found no exception is thrown, but an INFO message is logged.
             * <p>
             * Note&#58; Can be omitted when all necessary properties and mapping resources
             * are specified locally via this bean.
             * <p>
             * Note&#58; If configLocation is also set, this will be treated as if it is at
             * the beginning of the list.
             * <p>
             * Note&#58; For each configuration item, the first one appears to take
             * precedence. So configLocation takes precedence over configLocations which
             * takes precedence over properties in the spring configuation. But all
             * mapping directives are processed irrespective of where they occur and in
             * what order. So configurations added here should <b>only </b> contain
             * <mapping&gt; elements to avoid unexpected behaviour.
             * 
             * @see org.hibernate.cfg.Configuration#configure&#40;java.net.URL&#41;
             */
            public void setConfigOptionalLocations&#40;Resource&#91;&#93; pConfigLocations&#41; &#123;
                mCheckConfigLocations = false;
                mConfigLocations = pConfigLocations;
            &#125;
        
            /** @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#postProcessConfiguration&#40;org.hibernate.cfg.Configuration&#41; */
            protected void postProcessConfiguration&#40;Configuration pConfig&#41; throws HibernateException &#123;
                super.postProcessConfiguration&#40;pConfig&#41;;
        
                if &#40;mConfigLocations != null&#41; &#123;
                    for &#40;int i = 0; i < mConfigLocations.length; i++&#41; &#123;
                        try &#123;
                            // Load Hibernate configurations from given location.
                            pConfig.configure&#40;mConfigLocations&#91;i&#93;.getURL&#40;&#41;&#41;;
                        &#125; catch &#40;FileNotFoundException e&#41; &#123;
                            if &#40;mCheckConfigLocations&#41;
                                throw new HibernateException&#40;"Could not configure from resource&#58; "
                                        + mConfigLocations&#91;i&#93;.getDescription&#40;&#41;, e&#41;;
                            else
                                LOG.info&#40;"A hibernate configuration resource does not exist&#58; "
                                        + mConfigLocations&#91;i&#93;.getDescription&#40;&#41;&#41;;
        
                        &#125; catch &#40;IOException e&#41; &#123;
                            throw new HibernateException&#40;"Could not configure from resource&#58; "
                                    + mConfigLocations&#91;i&#93;.getDescription&#40;&#41;, e&#41;;
                        &#125;
                    &#125;
                &#125;
            &#125;
        &#125;

        Comment


        • #5
          hello,
          i tried the code but i didnt work for me..
          my configuration is as follows

          Code:
          <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
          	    <property name="dataSource">
          			<ref bean="dataSource"/>
          	    </property>
          		<property name="mappingLocations">
          	    	<list>
          	    		<value>classpath*:**/*.hbm.xml</value>
          	    	</list>
          	    </property>
          		  
          		<property name="hibernateProperties">
          		 <ref bean="exampleHibernateProperties" />
          	    </property>
          	</bean>
          i have a webapp which is calling hibernate code residing in another jar..
          ...

          anyone has any idea?

          thanks and regards
          marco

          Comment


          • #6
            Hi,

            I am trying to solve similiar issue as your. I am curious to know if and how you resolved it. You can look at my posting http://forum.springframework.org/sho...ferrerid=14239

            Comment


            • #7
              Came across the post with no solution but found an answer after looking through the LocalSessionFactoryBean class API


              <property name="mappingDirectoryLocations">
              <value>WEB-INF/classes/database</value>
              </property>

              works for me!

              <!--<property name="mappingResources">
              <value>classpath:database/*.hbm.xml</value>
              </property>-->

              Comment


              • #8
                WebApp load mappings from utility jar in a EAR?

                Can anyone suggest a solution for this?

                I have an EAR with utility jars that contain the hibernate mappings. When my webapp starts up, unable to find the mappings.

                I have tried the below setting with classpath and without. When using without classpath, a exception is thrown because it is attempting to find the jar under the absolute path of the "WebContent" folder

                <property name="mappingJarLocations">
                <list>
                <value>classpath:Common.jar</value>
                </list>
                </property>
                With classpath complains:
                Caused by: java.io.FileNotFoundException: class path resource [Common.jar] cannot be resolved to URL because it does not exist
                at org.springframework.core.io.ClassPathResource.getU RL(ClassPathResource.java:162)
                at org.springframework.core.io.ClassPathResource.getF ile(ClassPathResource.java:174)
                at org.springframework.orm.hibernate3.LocalSessionFac toryBean.buildSessionFactory(LocalSessionFactoryBe an.java:653)
                at org.springframework.orm.hibernate3.AbstractSession FactoryBean.afterPropertiesSet(AbstractSessionFact oryBean.java:211)
                at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.invokeInitMethods(Abstr actAutowireCapableBeanFactory.java:1367)
                at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.initializeBean(Abstract AutowireCapableBeanFactory.java:1333)
                ... 50 more
                Any suggestions?

                Comment


                • #9
                  to answer my own question.

                  use mappingLocations with explicit reference to mappings which can reside inside the utility jars.

                  <property name="mappingLocations">
                  <list>
                  <value>classpath:/ca/Employee.hbm.xml</value>
                  <value>classpath:/ca/EmployeeRole.hbm.xml</value>
                  </list>
                  </property>

                  Comment

                  Working...
                  X