我正在尝试从几个jar文件加载实体。 我设法做的是
配置hibernate
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);
}
所以实体应该从moduleFiles数组加载。在日志中我可以看到:
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
外部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.
}
persistence.xml(META-INF目录)
<persistence-unit name="ProgramInfoPersistenceUnit">
<class>com.antara.modules.programinfo.db.model.PrograminfoDataEntity</class>
</persistence-unit>
使用上述实体用法查询
Session session = openSession();
Query q = session.getNamedQuery("PrograminfoDataEntity.findByWindowInfo");
q.setParameter("pp", windowInfo.getProcessPath());
q.setParameter("wt", windowInfo.getWindowTitle());
q.setDate("d", date);
PrograminfoDataEntity result = (PrograminfoDataEntity) q.uniqueResult();
closeSession(session);
引发了例外:
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)
问题是为什么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 ....
但是当我尝试使用该实体时,我仍然会遇到异常:
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
改变是:将配置传递给每个&#34;模块&#34;这是在jar内部并添加Annotated Class(通过模块我的意思是SPI服务与启动时调用的方法)
@Override
public void configureDB(Configuration configuration) {
configuration.addAnnotatedClass(PrograminfoDataEntity.class);
}
答案 0 :(得分:3)
经过3天的试验,我找到了解决办法:Hibernate使用ContextClassLoader的反射机制来破坏类
Thread.currentThread().getContextClassLoader();
所以我将ContextClassLoader设置为PrograminfoDataEntity的ClassLoader
Thread.currentThread().setContextClassLoader(PrograminfoDataEntity.class.getClassLoader());
它解决了所有NoClassDefFound,ClassCastException和类似错误
答案 1 :(得分:2)
根据javadoc and implementation code Hibernate只在Configuration.addJar方法中读取* .hbm.xml
我认为由于JPA规范中的限制,Hibernate不会自动扫描jar文件
我已经在hibernate中对jar进行了自动扫描,扩展了扫描仪并在其上添加了jar。但你应该使用JPA api。类似的东西:
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);
}
}
}
答案 2 :(得分:0)
您正在设置 Hibernate 引导程序。以下是文档:https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#bootstrap
这里基本上有两条路线可以走。您正在以特定于 Hibernate 的方式执行此操作。我通常更喜欢 JPA,因为它是最自动和最简单的一个:您将一个 persistence.xml 文件放入一个 jar 中,该 jar 将使用适当的实体注释扫描类。然后 JPA 将注入实体管理器(和工厂),然后您可以使用以下方法将其转换为本机 Hibernate 会话:
Session s = (Session) em.getDelegate();
反过来,如果需要,您应该可以访问非 JPA 功能。