2014-10-07 101 views
0

当我将Java EE应用程序部署到Glassfish时,我有一个非常好奇的问题。我有一个Eclipse EAR项目,它引用了一个Web项目(包含一个Servlet)和一个EJB项目(拥有一个EJB)和一个JPA项目(拥有一个@Entity)。在我的servlet我调用EJB,又执行下面的查询:JPA实体类实例

final CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder(); 
final CriteriaQuery<Country> criteriaQuery = criteriaBuilder.createQuery(Country.class); 
final Root<Country> root = criteriaQuery.from(Country.class); 

在上面的代码中的第三行我得到一个异常:

Severe: java.lang.IllegalArgumentException: Not an entity: class <package>.entity.Country 
at org.hibernate.jpa.internal.metamodel.MetamodelImpl.entity(MetamodelImpl.java:203) 
at org.hibernate.jpa.criteria.QueryStructure.from(QueryStructure.java:139) 
at org.hibernate.jpa.criteria.CriteriaQueryImpl.from(CriteriaQueryImpl.java:173) 
at <package>.CountrySessionBean.getCountries(CountrySessionBean.java:35) 
... 

我已经调试上述休眠类,即MetamodelImpl,并且我看到它已经注册了我的实体(在实体Map中)。类名与我所要求的一样(净...国家)完全相同。然而,这个类是从下面的代码,我在servlet中放置不同:

final Class<?> countryClass = Country.class; 

我说这是“不同”,因为“declaredConstructors”字段和“declaredPublicMethods”是不同的。在servlet中,这些字段为'null'(奇怪,请参阅下面的Country.java!),但在MetamodelImpl类中,这些字段包含我在实体中定义的构造函数和公共方法。由于MetamodelImpl使用Map,因为“class”不同(即存储在内存中的不同位置),所以它无法在注册的类中找到实体,当然它会抛出IllegalArgumentException。我已经检查过,部署到Glassfish的东西只包含一个Country.class文件,所以这真的令人困惑,为什么同一个类有两个不同的Class实例,并且它们彼此不同!

任何人有什么想法?

仅供参考:Hibernate v4.3.6,EJB v3.2,Glassfish v4.1,JPA v2.1。

My Country.java实体在下面。正如你所看到的,它包含一个构造函数和公共方法,所以令我惊讶的是,在servlet中,类没有“declaredConstructors”或“declaredPublicMethods”。怎么会这样?

import java.io.Serializable; 

import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.GenerationType; 
import javax.persistence.Id; 
import javax.validation.constraints.NotNull; 
import javax.validation.constraints.Pattern; 

@Entity 
public class Country implements Serializable { 
private static final long serialVersionUID = -3119088680575312729L; 

@Id 
@GeneratedValue(strategy = GenerationType.AUTO) 
private Integer id; 

@Pattern(regexp = ".[\\p{L} \\.\\[\\]\\?\\-\\(\\)]{1,30}+") 
@NotNull 
private String name; 

public Country() { 
    super(); 
} 

public String getName() { 
    return this.name; 
} 

public void setName(final String name) { 
    this.name = name; 
} 

public Integer getId() { 
    return this.id; 
} 

public void setId(final Integer id) { 
    this.id = id; 
} 

@Override 
public String toString() { 
    final StringBuilder builder = new StringBuilder(); 

    builder.append(this.name); 
    builder.append(" ("); 
    builder.append(this.id); 
    builder.append(")"); 

    return builder.toString(); 
} 
} 
+0

JPA有时是一个烂摊子。1.声明的实体persistence.xml,或者2.确保它们和ejb – maress 2014-10-07 15:04:13

+0

在同一个jar里谢谢,我也试过了,t无法在EJB项目中创建最简单的实体,只需一个空的公共构造函数就可以创建一个id和一个getter/setter。然后在EJB代码中,我检查这个类,它与MetamodelImpl中注册的类不同。在我用MyEntity.class引用它的时候,我在构造函数中定义的类以及运行时的getters和setter类没有任何构造函数或方法,这没有任何意义。这些声明哪里去了? – Raoul 2014-10-08 06:53:15

回答

0

你检查了你的persistence.xml吗?实体类是否明确声明或exclude-unlisted-classes属性设置为false?

或者也许在类路径中的实体类的多个定义(什么可以解释在元模型中注册但未解决的实例的存在)?

+0

谢谢,但我已经试过了也: 'code' <持久性单元名称= “试JPA”> org.hibernate.jpa.HibernatePersistenceProvider MySQLResource net。 .ejb.MyEntity <排除,非流通类>真 'code' 是的,有在部署的应用程序只有一个myEntity所的类文件。我也认为会有两个,但事实并非如此。我查看了所有文件夹和罐子。它只是没有意义,有同一类的两个类实例。 – Raoul 2014-10-08 06:55:14

+0

您是否试图显式调用[Metamodel#entity(...)](http://docs.oracle.com/javaee/6/api/javax/persistence/metamodel/Metamodel.html#entity(java.lang .Class))]方法与你的类对象,以检查Hibernate解决它的方式? – bdulac 2014-10-08 08:21:55

+0

我试过了,但它是相同的结果。 MyEntity不是一个实体。 MetamodelImpl.entity(...)只是在地图中查找实体,并将MyEntity类用作关键字。然而,正如我上面提到的,实体注册MetamodelImpl(在实体映射)是正确的(它有一个构造函数和公共方法),但如果我在调试器中检查MyEntity.class,我看到它是一个“不同的”MyEntity类没有构造函数,也没有公共方法。就好像Hibernate已经注册了正确的实体,但是在运行时(在EJB中),MyEntity.class是一个没有方法的错误类!奇怪! – Raoul 2014-10-08 08:51:34

1

解决!这link帮助,特别是关于persistence.xml的评论。

我仍然不明白如何为一个类创建两个不同的Class实例,但如果您有单独的EJB,WEB和JPA项目,它似乎只是一种特殊的方式,如下所示:

  1. 不添加的persistence.xml到JPA项目(或项目包含@Entity实例 ),而是将其添加到Web 项目(我把它添加到的src/META-INF,虽然有其他 的可能性,我还没有测试)。

  2. 在persistence.xml中,您必须提及类“fqn-of-Class”即EVEN的类 ,尽管这些类应由注释拾取。设置 “排除-非流通类(真正的)是不相关的 。它与没有这个。

这样做就意味着查询现在没有恼人抛出:IllegalArgumentException说明实体是作品”不是一个实体”

测试在JBoss EAP 6.3,Java 7中,JPA 2.1,EJB 3.1,但我相信它也将在Glassfish与EJB 3.2的工作。