2015-10-23 20 views
19

我有模塊A和模塊B,它們都具有JPA註釋類。模塊B有一個單元測試,在一對夫婦這些實體的拉動從A 兩個模塊編譯優良,運行時依賴都設置好了,但我得到以下錯誤,當我嘗試運行單元測試:如何配置休眠以掃描不同模塊中的實體

java.lang.IllegalArgumentException: Unknown entity: MyClassHere 
Caused by: org.hibernate.MappingException: Unknown entity: MyClassHere 

這發生在EntityManager.merge調用中。

由於模塊B具有所有的休眠配置文件等,我猜測它根本沒有提到我的A類是一個實體。

我嘗試添加下列到persistence.xml中

<exclude-unlisted-classes>false</exclude-unlisted-classes> 

在hibernate.cfg.xml我說:

<property name="packagesToScan">myNamespace.*</property> 

然後:

<property name="packagesToScan"> 
       <array> 
        <value>myNamespace.*</value> 
       </array> 
</property> 

這給了我一個錯誤「財產」的內容必須爲空。 然後我試過:

<mapping class="myNamespace.*" /> 

我在想什麼?

編輯︰有一件事我忘了提到可能是重要的是,這兩個模塊設置爲單獨的項目(我使用eclipse),所以目錄結構是不同的。運行時依賴關係都設置正確,但由於.class文件最終在不同的目錄中,我認爲休眠可能不會掃描它們。

+2

查看示例源代碼?我有一個類似的設置,它正在使用[setPackagesToScan](http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.html# setPackagesToScan-java.lang.String ...-)覆蓋[LocalContainerEntityManagerFactoryBean]中提供(http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean的.html)。 –

+2

你可以用' myNamespace'(即沒有'。*')來嘗試:這個屬性應該指向要掃描的類的父包。例如。如果'MyEntity'類在'my.package包中。MyEntity',你會寫' my.package' – Tunaki

+0

試過了,它沒有工作... – ventsyv

回答

1

如果將項目配置爲自動檢測實體,它將僅掃描META-INF/persistence.xml所在的路徑(默認情況下)。

除了:

<exclude-unlisted-classes>false</exclude-unlisted-classes> 

您設置一個額外的休眠選項:

<property name="hibernate.archive.autodetection" value="class, hbm" /> 

它決定哪些元素是自動由Hibernate實體管理器發現。

對於額外的實體(在別人罐),你可以設置JAR文件部分在主persistence.xml文件:

<persistence> 
    <persistence-unit name="myUnit"> 
     ... 
     <class>foo.bar.Entity1</class> 
     <class>foo.bar.Entity2</class> 
     <jar-file>moduleB.jar</jar-file> 
     ... 
    </persistence-unit> 
</persistence> 

的JAR文件元素指定可見JAR文件包含託管持久性類的打包持久單元,而類元素顯式命名託管持久性類。

其META-INF目錄包含persistence.xml的JAR文件或目錄稱爲持久性單元的根。持久單元的範圍由持久單元的根確定。每個持久性單元必須標識一個持久性單元範圍唯一的名稱。

問候,安德烈

+1

根據文檔,class,hbm是這個設置的默認值。無論如何,我嘗試過,沒有任何改變。 – ventsyv

0

persistence.xml中可以含有<jar-file>....jar</jar-file>元件:指定將要搜索的類的一個或多個JAR文件。

0

我們通過使用Spring來檢測實體,從而解決了我正在處理的項目中的類似問題。例如。使用帶註釋的Spring配置:

@Configuration 
@ComponentScan("com.org.prj.myNamespace1", "com.org.prj.myNamespace2") 
public class MyDatabaseConfig { 
    @Bean 
    public EntityManagerFactory entityManagerFactory() { 
     final LocalContainerEntityManagerFactoryBean factory = 
      new LocalContainerEntityManagerFactoryBean(); 

     // ...JPA properties, vendor adaptor, dialect, data source, persistence unit etc... 

     factory.setPackagesToScan("com.org.prj.myNamespace1", "com.org.prj.myNamespace2"); 

     factory.afterPropertiesSet(); 
     return factory.getObject(); 
    } 

    // ...Data source beans etc... 
} 
0

我最近解決了類似的問題,添加JAR文件路徑的persistence.xml

<jar-file>file:///C:/yourpath/yourJar.jar</jar-file>

希望它能幫助。  

2
  • 如果您正在使用休眠/春天,我們可以延長 LocalSessionFactoryBean的對象,並通過項目掃描以確定 項目中的實體類。
  • 既然你說兩個不同的項目,然後嘗試編寫 一些編譯時間實用程序來解析這兩個項目,並創建一個 實體XML文件,解決您的問題。
-1
  • 的src/main /資源:applicationContext.xml的
  • 的src /測試/資源:測試的applicationContext.xml

確保在測試範圍也爲你打造你的應用程序 - 上下文來掃描這些實體。您的test-applicationContext.xml可能不會像運行時一樣設置整個應用程序上下文,但也應該包含測試時需要的一些東西,例如包掃描。

可以ofcourse在這兩個applicationContext.xml中和測試的applicationContext.xml

0

最簡單的方法創建的src /主/資源persistence.xml中,包括它做

configuration.addAnnotatedClass(Contact.class) 

如果您想使用掃描包,請首先使用ClassLoader加載所有類。你是否使用Spring從Hibernate-orm LocalSessionFactoryBuilder.class

@Bean 
public SessionFactory sessionFactory(){ 

    HibernateConfig configuration = new HibernateConfig(); 

    Properties properties = hibernateProperties(); 

    configuration.setProperties(properties); 

    configuration.scanPackages("com.atcc.stom.model.entity"); 

    return configuration.buildSessionFactory(); 
} 

HibernateConfig.class

import org.hibernate.HibernateException; 
import org.hibernate.MappingException; 
import org.hibernate.cfg.Configuration; 
import org.springframework.core.io.Resource; 
import org.springframework.core.io.ResourceLoader; 
import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 
import org.springframework.core.io.support.ResourcePatternResolver; 
import org.springframework.core.io.support.ResourcePatternUtils; 
import org.springframework.core.type.classreading.CachingMetadataReaderFactory; 
import org.springframework.core.type.classreading.MetadataReader; 
import org.springframework.core.type.classreading.MetadataReaderFactory; 
import org.springframework.core.type.filter.AnnotationTypeFilter; 
import org.springframework.core.type.filter.TypeFilter; 
import org.springframework.util.ClassUtils; 

import javax.persistence.AttributeConverter; 
import javax.persistence.Embeddable; 
import javax.persistence.Entity; 
import javax.persistence.MappedSuperclass; 
import java.io.IOException; 
import java.lang.annotation.Annotation; 
import java.util.Set; 
import java.util.TreeSet; 

public class HibernateConfig extends Configuration { 

    private static final TypeFilter[] DEFAULT_ENTITY_TYPE_FILTERS = new TypeFilter[] { 
      new AnnotationTypeFilter(Entity.class, false), 
      new AnnotationTypeFilter(Embeddable.class, false), 
      new AnnotationTypeFilter(MappedSuperclass.class, false)}; 

    private static final String RESOURCE_PATTERN = "/**/*.class"; 

    private static final String PACKAGE_INFO_SUFFIX = ".package-info"; 

    private final ResourcePatternResolver resourcePatternResolver; 

    private static TypeFilter converterTypeFilter; 

    static { 
     try { 
      @SuppressWarnings("unchecked") 
      Class<? extends Annotation> converterAnnotation = (Class<? extends Annotation>) 
        ClassUtils.forName("javax.persistence.Converter", Configuration.class.getClassLoader()); 
      converterTypeFilter = new AnnotationTypeFilter(converterAnnotation, false); 
     } 
     catch (ClassNotFoundException ex) { 
      // JPA 2.1 API not available - Hibernate <4.3 
     } 
    } 

    public HibernateConfig() { 
     this(new PathMatchingResourcePatternResolver()); 
    } 

    public HibernateConfig(ClassLoader classLoader) { 
     this(new PathMatchingResourcePatternResolver(classLoader)); 
    } 

    public HibernateConfig(ResourceLoader resourceLoader) { 
     this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader); 
    } 

    public void scanPackages(String... packagesToScan) throws HibernateException { 
     Set<String> entityClassNames = new TreeSet<String>(); 
     Set<String> converterClassNames = new TreeSet<String>(); 
     Set<String> packageNames = new TreeSet<String>(); 
     try { 
      for (String pkg : packagesToScan) { 
       String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + 
         ClassUtils.convertClassNameToResourcePath(pkg) + RESOURCE_PATTERN; 

       Resource[] resources = this.resourcePatternResolver.getResources(pattern); 
       MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver); 
       for (Resource resource : resources) { 
        if (resource.isReadable()) { 
         MetadataReader reader = readerFactory.getMetadataReader(resource); 
         String className = reader.getClassMetadata().getClassName(); 
         if (matchesEntityTypeFilter(reader, readerFactory)) { 
          entityClassNames.add(className); 
         } 
         else if (converterTypeFilter != null && converterTypeFilter.match(reader, readerFactory)) { 
          converterClassNames.add(className); 
         } 
         else if (className.endsWith(PACKAGE_INFO_SUFFIX)) { 
          packageNames.add(className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length())); 
         } 
        } 
       } 
      } 
     } 
     catch (IOException ex) { 
      throw new MappingException("Failed to scan classpath for unlisted classes", ex); 
     } 
     try { 
      ClassLoader cl = this.resourcePatternResolver.getClassLoader(); 
      for (String className : entityClassNames) { 
       addAnnotatedClass(cl.loadClass(className)); 
      } 
      for (String className : converterClassNames) { 
       ConverterRegistrationDelegate.registerConverter(this, cl.loadClass(className)); 
      } 
      for (String packageName : packageNames) { 
       addPackage(packageName); 
      } 
     } 
     catch (ClassNotFoundException ex) { 
      throw new MappingException("Failed to load annotated classes from classpath", ex); 
     } 
    } 

    private boolean matchesEntityTypeFilter(MetadataReader reader, MetadataReaderFactory readerFactory) throws IOException { 
     for (TypeFilter filter : DEFAULT_ENTITY_TYPE_FILTERS) { 
      if (filter.match(reader, readerFactory)) { 
       return true; 
      } 
     } 
     return false; 
    } 

    /** 
    * Inner class to avoid hard dependency on JPA 2.1/Hibernate 4.3. 
    */ 
    private static class ConverterRegistrationDelegate { 

     @SuppressWarnings("unchecked") 
     public static void registerConverter(Configuration config, Class<?> converterClass) { 
      config.addAttributeConverter((Class<? extends AttributeConverter<?, ?>>) converterClass); 
     } 
    } 

}