问题
I have a very curious problem when I deploy my Java EE application to Glassfish. I have an Eclipse EAR project that references a web project (containing a servlet), and an EJB project (that has one EJB) and a JPA Project (that has one @Entity). In my servlet I call the EJB, which in turn performs the following query:
final CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
final CriteriaQuery<Country> criteriaQuery = criteriaBuilder.createQuery(Country.class);
final Root<Country> root = criteriaQuery.from(Country.class);
On the third line of the above code I get an exception:
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)
...
I have debugged the above mentioned Hibernate class, namely MetamodelImpl, and I see that it has registered my Entity (in the entities Map). The class name is exactly the same as the one I'm asking for (net...Country). However, this class is different from the following code which I place in the servlet:
final Class<?> countryClass = Country.class;
I say it is "different", because the 'declaredConstructors' field and the 'declaredPublicMethods' are different. In the servlet these fields are 'null' (strange, see Country.java below!), but in the MetamodelImpl class these fields contain the constructors and public methods that I have defined in the entity. Because MetamodelImpl uses a Map, it cannot find the entity amongst the registered classes because the "class" is different (i.e. stored at a different location in memory), and of course it throws the IllegalArgumentException. I have checked that what is deployed to Glassfish only ever contains one Country.class file, so this is really confusing why there are two different Class instances of the same class, and that they are different from each other!
Anyone have any idea?
For reference: Hibernate v4.3.6, EJB v3.2, Glassfish v4.1, JPA v2.1.
My Country.java entity is below. As you can see, it contains a constructor and public methods, so it astonishes me that in the servlet the class does NOT have 'declaredConstructors' or 'declaredPublicMethods'. How can this be?
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();
}
}
回答1:
Solved! This link helped, particularly the comment about the persistence.xml.
I still don't understand how you could ever have two different Class instances for one class, but it indeed seems just to be a particular way if you have separate EJB, WEB and JPA projects, which is as follows:
Add the persistence.xml NOT to the JPA project (or the project containing the @Entity instances), but rather add it to the web project (I added it to src/META-INF, although there's other possibilities, which I haven't yet tested).
In the persistence.xml, you have to mention the classes with "fqn-of-Class", EVEN though the classes should be picked up by the annotation. The setting "exclude-unlisted-classes (true) is not relevant. It works with and without this.
Doing this means the query now works without the annoying IllegalArgumentException stating the Entity is "not an Entity".
Tested on JBoss EAP 6.3, Java 7, JPA 2.1, EJB 3.1, although I assume it will also work on Glassfish with EJB 3.2.
回答2:
Have you checked your persistence.xml ? Is the entity class explicitely stated or the exclude-unlisted-classes property set to false ?
Or perhaps multiple definitions of the entity class in the classpath (what could explain the presence of an instance registered in the metamodel but not resolved) ?
来源:https://stackoverflow.com/questions/26238508/jpa-entity-class-instances