Java 如何从外部JAR加载Hibernate实体
我正在尝试从几个jar文件加载实体。 我设法做到的是Java 如何从外部JAR加载Hibernate实体,java,hibernate,Java,Hibernate,我正在尝试从几个jar文件加载实体。 我设法做到的是 配置休眠 private void configure(File[] moduleFiles) { Configuration configuration = new Configuration() .setProperty("hibernate.connection.url", getConnectionString()) .setProperty("hibernate.connection.username", "user
private void configure(File[] moduleFiles)
{
Configuration configuration = new Configuration()
.setProperty("hibernate.connection.url", getConnectionString())
.setProperty("hibernate.connection.username", "user")
.setProperty("hibernate.connection.password", "pass")
.setProperty("hibernate.connection.driver_class", "org.hsqldb.jdbc.JDBCDriver")
.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect")
.setProperty("hibernate.archive.autodetection", "class,hbm")
.setProperty("exclude-unlisted-classes", "false")
.setProperty("hibernate.hbm2ddl.auto", "update");
if (moduleFiles != null) {
for (File f : moduleFiles) {
configuration.addJar(f);
}
}
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
this.sessionFactory = configuration.buildSessionFactory(serviceRegistry);
}
2015-08-25 20:52:12 INFO Configuration:837 - HHH000235: Searching for mapping documents in jar: ProgramInfo.jar
2015-08-25 20:52:12 INFO Configuration:837 - HHH000235: Searching for mapping documents in jar: SampleModule.jar
@Entity
@Table(name = "PROGRAMINFO_DATA", schema = "PUBLIC", catalog = "PUBLIC")
@NamedQueries({@NamedQuery(name = "PrograminfoDataEntity.findByWindowInfo", query = "FROM PrograminfoDataEntity WHERE PROCESSPATH = :pp AND WINDOWTITLE = :wt AND DAY = :d")})
public class PrograminfoDataEntity implements SVEntity {
private long id;
private Date day;
private String processname;
private String processpath;
private String programname;
private String windowtitle;
// getters setters etc.
}
org.hibernate.MappingException: Named query not known: PrograminfoDataEntity.findByWindowInfo
at org.hibernate.internal.AbstractSessionImpl.getNamedQuery(AbstractSessionImpl.java:177)
at org.hibernate.internal.SessionImpl.getNamedQuery(SessionImpl.java:1372)
at com.antara.modules.programinfo.db.dao.PrograminfoDao.findByWindowInfo(PrograminfoDao.java:26)
at com.antara.modules.programinfo.ProgramInfoImpl.run(ProgramInfoImpl.java:84)
ERROR AssertionFailure:61 - HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): java.lang.ClassNotFoundException: com.antara.modules.programinfo.db.model.PrograminfoDataEntity
ERROR Main:114 - PersistentClass name cannot be converted into a Class
...
Caused by: java.lang.ClassNotFoundException: com.antara.modules.programinfo.db.model.PrograminfoDataEntity
问题是为什么hibernate没有从jar加载带注释的实体?异常不仅由命名查询引发,而且由实体的任何其他操作引发。使用此实体之前没有错误。本地实体已正确加载
编辑:
经过一些更改后,我设法通过Hibernate识别实体
DEBUG AnnotationBinder:601 - Binding entity from annotated class: com.antara.modules.programinfo.db.model.PrograminfoDataEntity
DEBUG QueryBinder:93 - Binding named query: PrograminfoDataEntity.findByWindowInfo => FROM PrograminfoDataEntity ....
但当我尝试使用实体时,仍然会出现异常:
org.hibernate.MappingException: Named query not known: PrograminfoDataEntity.findByWindowInfo
at org.hibernate.internal.AbstractSessionImpl.getNamedQuery(AbstractSessionImpl.java:177)
at org.hibernate.internal.SessionImpl.getNamedQuery(SessionImpl.java:1372)
at com.antara.modules.programinfo.db.dao.PrograminfoDao.findByWindowInfo(PrograminfoDao.java:26)
at com.antara.modules.programinfo.ProgramInfoImpl.run(ProgramInfoImpl.java:84)
ERROR AssertionFailure:61 - HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): java.lang.ClassNotFoundException: com.antara.modules.programinfo.db.model.PrograminfoDataEntity
ERROR Main:114 - PersistentClass name cannot be converted into a Class
...
Caused by: java.lang.ClassNotFoundException: com.antara.modules.programinfo.db.model.PrograminfoDataEntity
更改是:将配置传递给jar中的每个“模块”,并添加带注释的类(所谓模块,我指的是启动时调用方法的SPI服务)
根据Hibernate only read*.hbm.xml at Configuration.addJar方法
我猜Hibernate不会自动扫描JAR,因为JPA规范中有限制
我已经在hibernate中完成了JAR的自动扫描,扩展了扫描仪并在其上添加了JAR。但您应该使用JPAAPI来实现这一点。比如:
Map<String, Object> map = new HashMap<>();
map.put("hibernate.connection.url", getConnectionString());
map.put("hibernate.connection.username", "user");
map.put("hibernate.connection.password", "pass");
map.put("hibernate.connection.driver_class", "org.hsqldb.jdbc.JDBCDriver");
map.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
map.put("hibernate.archive.autodetection", "class,hbm");
map.put("exclude-unlisted-classes", "false");
map.put("hibernate.hbm2ddl.auto", "update");
//Property to change scanner
map.put("hibernate.ejb.resource_scanner", "me.janario.MyScanner");
EntityManagerFactory emf = Persistence.createEntityManagerFactory("ProgramInfoPersistenceUnit", map);
SessionFactory sessionFactory = ((HibernateEntityManagerFactory) emf).getSessionFactory();
public class MyScanner extends StandardScanner {
@Override
public ScanResult scan(PersistenceUnitDescriptor persistenceUnit, ScanOptions scanOptions) {
try {
persistenceUnit.getJarFileUrls()
.add(new URL("file:/path/my.jar"));
return super.scan(persistenceUnit, scanOptions);
} catch (MalformedURLException e) {
throw new IllegalStateException(e);
}
}
}
经过3天的试验,我找到了解决方案:Hibernate使用ContextClassLoader的反射机制加载类
Thread.currentThread().getContextClassLoader();
所以我将ContextClassLoader设置为PrograminfoDataEntity的ClassLoader
Thread.currentThread().setContextClassLoader(PrograminfoDataEntity.class.getClassLoader());
它解决了所有NoClassDefFound、ClassCastException和类似错误您正在设置Hibernate引导过程。以下是文件: 这里基本上有两条路线。您正在以特定于Hibernate的方式进行操作。我通常更喜欢JPA,因为它是最自动、最简单的一个:将persistence.xml文件放入jar中,jar将被扫描以查找具有适当实体注释的类。JPA随后将注入实体管理器(和工厂),然后您可以使用以下方法将其转换为本机Hibernate会话:
Session s = (Session) em.getDelegate();
反过来,如果需要的话,应该允许您访问非JPA功能。不幸的是,它不起作用:无法构建实体管理器工厂org.hibernate.boot.registry.classloading.spi.ClassLoadingException:无法加载类[com.antara.modules.programinfo.db.model.PrograminfoDataEntity]您是作为java se应用程序还是在jee容器中?(Wildfly中还有一个conf来代替scanner)标准JavaSE应用程序。我认为您的解决方案的问题在于ProgramInfoPersistenceUnit位于JAR中,因此在创建EntityManagerFactory时无法访问它。方法configure(File[]moduleFiles)是加载包含实体的JAR的“父级”,该实体可能与
Session s = (Session) em.getDelegate();