Over a million developers have joined DZone.

Automatically Mapping Annotated Hibernate Classes With Spring

· Database Zone

Build fast, scale big with MongoDB Atlas, a hosted service for the leading NoSQL database. Try it now! Brought to you in partnership with MongoDB.

Doesn't it annoy you when you have to add each class individually to the Spring config when you are dealing with annotated classes? I bet it annoys you even more when you have to refactor a package and Eclipse doesn't refactor the package inside the xml file. I have your solution and it won't cost you anything.

First you need to write your XML just like mine.


<!-- add dynamic factory here --><bean id="sessionFactory"class="com.package.spring.AutomatedAnnotationSessionFactoryBean"><property name="dataSource" ref="dataSource" /><property name="automaticAnnotatedPackages"><list><value>com.package.domain</value><value>com.package.domain.view</value></list></property><property name="annotatedPackages"><list><value>com.package.domain</value><value>com.package.domain.view</value></list></property><!-- annotated source files --><!-- <property name="annotatedClasses"><list><value>example.Account</value><value>example.AccountDetail</value><value>example.Employee</value></list></property> --><property name="hibernateProperties"><props><prop key="hibernate.generate_statistics">true</prop><prop key="hibernate.dialect">${db.dialect}</prop><prop key="hibernate.cache.provider_class">${cache.provider}</prop><!-- <prop key="hibernate.cache.provider_class">org.hibernate.cache.TreeCacheProvider</prop> --><prop key="hibernate.show_sql">false</prop><!-- <prop key="hibernate.hbm2ddl.auto">create</prop> --><prop key="hibernate.validator.apply_to_ddl">true</prop><!-- <prop key="hibernate.validator.autoregister_listeners">true</prop><prop key="hibernate.validator.apply_to_ddl">true</prop><prop key="hibernate.cache.use_query_cache">true</prop> --><!-- <prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</prop> --></props></property></bean>

You'll notice really quick that you need a new class as well.


public class AutomatedAnnotationSessionFactoryBean extends      LocalSessionFactoryBean{   private Class[] annotatedClasses;   private String[] annotatedPackages;   private String[] automaticAnnotatedPackages;   private static Log log = LogFactory         .getLog(AutomatedAnnotationSessionFactoryBean.class);   public String[] getAutomaticAnnotatedPackages()   {      return automaticAnnotatedPackages;   }   public void setAutomaticAnnotatedPackages(String[] annotatedPackages)   {      automaticAnnotatedPackages = annotatedPackages;   }   public AutomatedAnnotationSessionFactoryBean()   {      setConfigurationClass(AnnotationConfiguration.class);   }   public void setConfigurationClass(Class configurationClass)   {      if (configurationClass == null            || !AnnotationConfiguration.class                  .isAssignableFrom(configurationClass))      {         throw new IllegalArgumentException(               "AnnotationSessionFactoryBean only supports AnnotationConfiguration or subclasses");      }      super.setConfigurationClass(configurationClass);   }   /**    * Specify annotated classes, for which mappings will be read from    * class-level JDK 1.5+ annotation metadata.    *     * @see org.hibernate.cfg.AnnotationConfiguration#addAnnotatedClass(Class)    */   public void setAnnotatedClasses(Class[] annotatedClasses)   {      this.annotatedClasses = annotatedClasses;   }   /**    * Specify the names of annotated packages, for which package-level JDK 1.5+    * annotation metadata will be read.    *     * @see org.hibernate.cfg.AnnotationConfiguration#addPackage(String)    */   public void setAnnotatedPackages(String[] annotatedPackages)   {      this.annotatedPackages = annotatedPackages;   }   /**    * Reads metadata from annotated classes and packages into the    * AnnotationConfiguration instance.    * <p>    * Calls <code>postProcessAnnotationConfiguration</code> afterwards, to give    * subclasses the chance to perform custom post-processing.    *     * @see #postProcessAnnotationConfiguration    */   protected final void postProcessConfiguration(Configuration config)         throws HibernateException   {      AnnotationConfiguration annConfig = (AnnotationConfiguration) config;      if (this.annotatedClasses != null)      {         for (int i = 0; i < this.annotatedClasses.length; i++)         {            annConfig.addAnnotatedClass(this.annotatedClasses[i]);         }      }      if (this.annotatedPackages != null)      {         for (int i = 0; i < this.annotatedPackages.length; i++)         {            annConfig.addPackage(this.annotatedPackages[i]);         }      }      try      {         if (this.automaticAnnotatedPackages != null)         {            for (int i = 0; i < this.automaticAnnotatedPackages.length; i++)            {               List<String> classList = ResourceLocator.getClassesInPackage(                     automaticAnnotatedPackages[i], new ArrayList<String>()                     {                     }, false);               for (String clazz : classList)               {                  log.info("Found a Class: " + clazz);                  Class thisClass = Class.forName(clazz);                  if (thisClass.isAnnotationPresent(Hibernate.class))                  {                     log.debug("Adding Mapped Package - CLASS: " + clazz);                     annConfig.addAnnotatedClass(thisClass);                     addMetaData(thisClass);                  }               }            }         }      }      catch (Exception e)      {         throw new HibernateException(e);      }      // Perform custom post-processing in subclasses.      postProcessAnnotationConfiguration(annConfig);   }   private static void addMetaData(Class clazz) throws Exception   {      EntityMetaData metaData = new EntityMetaDataImpl();      Method[] methods = clazz.getMethods();      for (int i = 0; i < methods.length; i++)      {         Method method = methods[i];         log.debug("Adding method: " + method.getName());         metaData.addMethod(method.getName(), method.getReturnType());         if (method.isAnnotationPresent(FriendlyName.class))         {            metaData.setFriendlyName(method.getName());         }      }      if (clazz.isAnnotationPresent(Table.class))      {         Table table = (Table) clazz.getAnnotation(Table.class);         metaData.setTableName(table.name());      }      if (clazz.isAnnotationPresent(Entity.class))      {         Entity entity = (Entity) clazz.getAnnotation(Entity.class);         if (entity.name() != null && !StringUtil.isEmpty(entity.name()))            metaData.setEntityName(entity.name());         else            metaData.setEntityName(clazz.getSimpleName());      }      if (clazz.isAnnotationPresent(Auditable.class))         metaData.setAuditable(true);      if (clazz.isAnnotationPresent(Cache.class))         metaData.setCache(true);      if (clazz.isAnnotationPresent(DefaultSort.class))      {         String[] fields = ((DefaultSort) clazz               .getAnnotation(DefaultSort.class)).fields();         SortDirection[] directions = ((DefaultSort) clazz               .getAnnotation(DefaultSort.class)).directions();         Set<ExtOrder> sorts = new LinkedHashSet<ExtOrder>();         for (int i = 0; i < fields.length; i++)         {            sorts.add(new ExtOrder(fields[i], directions[i], true));         }         metaData.setDefaultSort(sorts);      }      if (clazz.isAnnotationPresent(Proxy.class))      {         Proxy proxy = (Proxy) clazz.getAnnotation(Proxy.class);         metaData.setLazy(proxy.lazy());      }      log.debug("Adding meta data for Class: " + clazz);      SpringLoader.addEntityMetaData(clazz, metaData);   }   /**    * To be implemented by subclasses that want to to perform custom    * post-processing of the AnnotationConfiguration object after this    * FactoryBean performed its default initialization.    *     * @param config    *           the current AnnotationConfiguration object    * @throws HibernateException    *            in case of Hibernate initialization errors    */   protected void postProcessAnnotationConfiguration(         AnnotationConfiguration config) throws HibernateException   {   }   public SessionFactory getCurrentSessionFactory()   {      return getSessionFactory();   }   public Map<String, EntityMetaData> getEntityMetaData()   {      return SpringLoader.getEntityMetaData();   }}

The property that you want to pay attention to in the configuration file is automaticAnnotatedPackages. It does all the magic. My custom class will traverse the packages listed and look for the @Hibernate annotation. This is an annotation that you will have to create. You can name it anything, but you just have to look for it. You find it, map your classes in the class and you are off and running. No more having to list each class individually.

From http://www.jeviathon.com

Now it's easier than ever to get started with MongoDB, the database that allows startups and enterprises alike to rapidly build planet-scale apps. Introducing MongoDB Atlas, the official hosted service for the database on AWS. Try it now! Brought to you in partnership with MongoDB.


The best of DZone straight to your inbox.

Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}