Статьи

Автоматически отображать аннотированные спящие классы с помощью Spring

Разве это не раздражает, когда вам приходится добавлять каждый класс отдельно в конфигурацию Spring, когда вы имеете дело с аннотированными классами? Бьюсь об заклад, это раздражает вас еще больше, когда вам нужно реорганизовать пакет, а Eclipse не реорганизует пакет внутри XML-файла. У меня есть ваше решение, и оно вам ничего не будет стоить.

Сначала вам нужно написать свой XML так же, как мой.

 

<!-- 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>

Вы очень быстро заметите, что вам также нужен новый класс.

 

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();   }}

Свойство, на которое вы хотите обратить внимание в файле конфигурации, — AutomaticAnnotatedPackages. Это делает всю магию. Мой пользовательский класс будет проходить через перечисленные пакеты и искать аннотацию @Hibernate. Это аннотация, которую вы должны будете создать. Вы можете назвать это как угодно, но вам просто нужно это найти. Вы найдете его, отобразите свои классы в классе, и вы уже в работе. Больше не нужно перечислять каждый класс в отдельности.

С http://www.jeviathon.com