在 GlassFish 4.1 中注入 EntityManager 时出现问题。 ClassCastException(无法转换为相同 class)

Problems injecting EntityManager in GlassFish 4.1. ClassCastException (can't cast to same class)

我正在使用:

我不知道为什么 GlassFish 不能注入 EntityManager。如果我从 EntityManagerFactory 获得 EntityManager,我没有问题:

protected EntityManager em = Persistence.createEntityManagerFactory("CustomersPU").createEntityManager();

另一方面,如果我试图说 GlassFish 注入它,得到一个异常。:

@PersistenceContext(unitName="CustomersPU")
protected EntityManager em;

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>me.localtest</groupId>
    <artifactId>customersapp</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <maven_compiler_source>1.8</maven_compiler_source>
        <maven_compiler_target>1.8</maven_compiler_target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>4.3.8.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.1.3.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.common</groupId>
            <artifactId>hibernate-commons-annotations</artifactId>
            <version>4.0.5.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.0-api</artifactId>
            <version>1.0.1.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>4.3.8.Final</version>
        </dependency>
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.1.0.Final</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

通用服务

package me.localtest.customersapp.services;

import java.io.Serializable;
import java.util.List;

public interface GenericService<T, PK extends Serializable> {
    public T save(T t) throws Throwable;
    public T update(T t) throws Throwable;
    public T remove(T t) throws Throwable;
    public T find(PK pk) throws Throwable;
    public List<T> findAll(String namedQuery) throws Throwable;
}

GenericServiceImpl

package me.localtest.customersapp.services;

import java.io.Serializable;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Persistence;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

public abstract class GenericServiceImpl<T, PK extends Serializable> implements GenericService<T, PK> {
    //@PersistenceContext(unitName="CustomersPU")
    protected EntityManager em = Persistence.createEntityManagerFactory("CustomersPU").createEntityManager();
    protected Class<T> clazz;

    public GenericServiceImpl(Class<T> clazz) {
        this.clazz = clazz;
    }
    @Override
    public T save(T t) throws Throwable {
        em.persist(t);
        em.flush();
        return t;
    }
    @Override
    public T remove(T t) throws Throwable {
        em.remove(t);
        em.flush();
        return t;
    }
    @Override
    public T update(T t) throws Throwable {
        em.merge(t);
        em.flush();
        return t;
    }
    @Override
    public T find(PK pk) throws Throwable {
        return (T) em.find(clazz, pk);
    }
    @SuppressWarnings("unchecked")
    @Override
    public List<T> findAll(String aQuery) throws Throwable {
        Query query = em.createQuery(aQuery);
        return (List<T>) query.getResultList();
    }
}

CustomerServiceBean

package me.localtest.customersapp.services;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.Query;

import me.localtest.customersapp.domain.entities.Customer;

@LocalBean
@Stateless
public class CustomerServiceBean extends GenericServiceImpl<Customer, Integer> {

    public CustomerServiceBean() {
        super(Customer.class);
    }
    public Customer findByDni(String dni) {
        Query query = em.createNamedQuery("Customer.findByDni");
        query.setParameter("dni", dni);
        return (Customer) query.getSingleResult();
    }
}

客户

package me.localtest.customersapp.domain.entities;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@Entity
@Table(name="customers")
@XmlRootElement(name="customer")
@XmlAccessorType(XmlAccessType.FIELD)
@NamedQueries({
    @NamedQuery(name="Customer.findByDni", query="SELECT c FROM Customer c WHERE c.dni = :dni")
})
@SuppressWarnings("serial")
public class Customer implements Serializable {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id")
    @XmlElement(name="id")
    private Integer id;
    @Column(name="names")
    @XmlElement(name="names")
    private String names;
    @Column(name="surnames")
    @XmlElement(name="surnames")
    private String surnames;
    @Column(name="dni")
    @XmlElement(name="dni")
    private String dni;
    @Column(name="birth_date")
    @XmlElement(name="birth-date")
    @Temporal(TemporalType.DATE)
    private Date birthDate;
    @Column(name="address")
    @XmlElement(name="address")
    private String address;
    @Column(name="email")
    @XmlElement(name="email")
    private String email;
    @Column(name="creation_date")
    @Temporal(TemporalType.DATE)
    @XmlElement(name="creation-date")
    private Date creationDate;
    @Column(name="state")
    @XmlElement(name="state")
    private Boolean state;

    public Customer() {

    }
    public Customer(Integer id, String names, String surnames, String dni,
            Date birthDate, String address, String email, Date creationDate,
            Boolean state) {
        this.id = id;
        this.names = names;
        this.surnames = surnames;
        this.dni = dni;
        this.birthDate = birthDate;
        this.address = address;
        this.email = email;
        this.creationDate = creationDate;
        this.state = state;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getNames() {
        return names;
    }
    public void setNames(String names) {
        this.names = names;
    }
    public String getSurnames() {
        return surnames;
    }
    public void setSurnames(String surnames) {
        this.surnames = surnames;
    }
    public String getDni() {
        return dni;
    }
    public void setDni(String dni) {
        this.dni = dni;
    }
    public Date getBirthDate() {
        return birthDate;
    }
    public void setBirthDate(Date birthDate) {
        this.birthDate = birthDate;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public Date getCreationDate() {
        return creationDate;
    }
    public void setCreationDate(Date creationDate) {
        this.creationDate = creationDate;
    }
    public Boolean getState() {
        return state;
    }
    public void setState(Boolean state) {
        this.state = state;
    }
}

persistence.xml

<persistence-unit name="CustomersPU" transaction-type="JTA">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <jta-data-source>jdbc/__customers</jta-data-source>
    <properties>
        <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SunOneJtaPlatform" />
    </properties>
</persistence-unit>

阶段 1

尝试使用 DNI 'A' (RESTful) 查找客户:

http://localhost:8080/customersapp/api/customers/find/A

这是一段堆栈跟踪:

2015-04-06T09:19:31.088-0500|Advertencia: A system exception occurred during an invocation on EJB CustomerServiceBean, method: public me.localtest.customersapp.domain.entities.Customer me.localtest.customersapp.services.CustomerServiceBean.findByDni(java.lang.String)
2015-04-06T09:19:31.089-0500|Advertencia: javax.ejb.TransactionRolledbackLocalException: Exception thrown from bean
    at com.sun.ejb.containers.EJBContainerTransactionManager.checkExceptionClientTx(EJBContainerTransactionManager.java:662)
    at com.sun.ejb.containers.EJBContainerTransactionManager.postInvokeTx(EJBContainerTransactionManager.java:507)
    at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4566)
    at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:2074)
    at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:2044)
    at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:220)
    at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:88)
    at com.sun.proxy.$Proxy267.findByDni(Unknown Source)
    at me.localtest.customersapp.services.__EJB31_Generated__CustomerServiceBean__Intf____Bean__.findByDni(Unknown Source)

这是原因:

Caused by: java.lang.ClassCastException: me.localtest.customersapp.domain.entities.Customer cannot be cast to me.localtest.customersapp.domain.entities.Customer

我发现这很愚蠢,怎么可能不能转换成相同的class?

谢谢。

嗯,我找不到这个问题的解决方案。我切换到 WildFly 8.2.0,没有问题。不管怎样,我希望有一天能知道为什么会这样xD。

谢谢。

似乎是 GF 4.x 在休眠版本 4.3 中遇到的类加载器问题的结果。8.Final

很可能与 HHH-9446 有关,而且它看起来像是 2 天前修复的。虽然还没有机会尝试