Entity class cannot be cast to java.lang.Number

2019-08-30 09:57发布

问题:

This issue is a continuation of this problem: Foreign key as a part of composite primary key and ManyToOne relationship in OpenJPA

OpenJPA is tring to cast my entity class (TableB) to type of its key (long). Why?

Persisting of TableB object without any elements in field rows works fine. The problem begins when 'm adding elements to rows.

TableA.class:

package org.model;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

@Entity
@IdClass(TableA_PK.class)
public class TableA implements Serializable {
    @Id
    private int fId;
    @Id
    private String item;
    @Id
    private String release;
    @Id
    @ManyToOne
    @JoinColumn(name = "b_id")
    private TableB tableB;
    @Column
    private String field1;
    @Column
    private String field2;

    public TableA() {

    }

    public int getfId() {
        return fId;
    }

    public void setfId(int fId) {
        this.fId = fId;
    }

    public String getItem() {
        return item;
    }

    public void setItem(String item) {
        this.item = item;
    }

    public String getRelease() {
        return release;
    }

    public void setRelease(String release) {
        this.release = release;
    }

    public TableB getTableB() {
        return tableB;
    }

    public void setTableB(TableB tableB) {
        this.tableB = tableB;
    }

    public String getField1() {
        return field1;
    }

    public void setField1(String field1) {
        this.field1 = field1;
    }

    public String getField2() {
        return field2;
    }

    public void setField2(String field2) {
        this.field2 = field2;
    }

}

TableA_PK.class:

package org.model;

import java.io.Serializable;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

public class TableA_PK implements Serializable {
    private int fId;
    private String item;
    private String release;
    private long tableB;

    public TableA_PK() {
    }

    public int getfId() {
        return fId;
    }

    public void setfId(int fId) {
        this.fId = fId;
    }

    public String getItem() {
        return item;
    }

    public void setItem(String item) {
        this.item = item;
    }

    public String getRelease() {
        return release;
    }

    public void setRelease(String release) {
        this.release = release;
    }

    public long getTableB() {
        return tableB;
    }

    public void setTableB(long tableB) {
        this.tableB = tableB;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (obj == this) {
            return true;
        }
        if (obj.getClass() != getClass()) {
            return false;
        }
        TableA_PK rhs = (TableA_PK) obj;
        return new EqualsBuilder().append(fId, rhs.fId).append(item, rhs.item)
                .append(release, rhs.release).append(tableB, rhs.tableB)
                .isEquals();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(fId).append(item).append(release)
                .append(tableB).toHashCode();
    }
}

TableB.class:

package org.model;

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

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

@Entity
public class TableB implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    @Column
    private String name;
    @Column
    private Date date;

    @OneToMany(mappedBy = "tableB", cascade = CascadeType.PERSIST)
    private List<TableA> rows;

    public TableB() {
    }

    public long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public List<TableA> getRows() {
        return rows;
    }

    public void setRows(List<TableA> rows) {
        this.rows = rows;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (obj == this) {
            return true;
        }
        if (obj.getClass() != getClass()) {
            return false;
        }
        TableB rhs = (TableB) obj;
        return new EqualsBuilder().append(id, rhs.id).append(name, rhs.name)
                .append(date, rhs.date).isEquals();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(id).append(name).append(date)
                .toHashCode();
    }

}

JpaTest.class:

package org.model;

import java.util.ArrayList;
import java.util.Date;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

import org.junit.Test;

public class JpaTest {

    @Test
    public void test() {
        EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("rd-jpa");
        EntityManager em = entityManagerFactory.createEntityManager();
        EntityTransaction userTransaction = em.getTransaction();
        userTransaction.begin();//BEGIN TRANSACTION 1.
        TableB tableb = new TableB();
        tableb.setDate(new Date());
        tableb.setName("tableb2");
        em.persist(tableb);  // fills tableb id
        userTransaction.commit(); //COMMIT 1
        userTransaction = em.getTransaction();
        userTransaction.begin();//BEGIN TRANSACTION 2.
        TableA tableA = new TableA();
        tableA.setfId(665);
        tableA.setField1("field1");
        tableA.setField2("field2");
        tableA.setItem("item2");
        tableA.setRelease("1");
        tableA.setTableB(tableb);
        ArrayList<TableA> rows = new ArrayList<TableA>();
        rows.add(tableA);
        tableb.setRows(rows);
        em.persist(tableb);
        userTransaction.commit();
        em.clear();
        em.close();
    }
}

Stack Trace after running JpaTest:

<openjpa-2.3.0-r422266:1540826 nonfatal general error> org.apache.openjpa.persistence.PersistenceException: org.model.TableB cannot be cast to java.lang.Number
    at org.apache.openjpa.kernel.BrokerImpl.persistAll(BrokerImpl.java:2526)
    at org.apache.openjpa.kernel.SingleFieldManager.persist(SingleFieldManager.java:279)
    at org.apache.openjpa.kernel.StateManagerImpl.cascadePersist(StateManagerImpl.java:3081)
    at org.apache.openjpa.kernel.BrokerImpl.persistInternal(BrokerImpl.java:2648)
    at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2604)
    at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2587)
    at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2491)
    at org.apache.openjpa.kernel.DelegatingBroker.persist(DelegatingBroker.java:1077)
    at org.apache.openjpa.persistence.EntityManagerImpl.persist(EntityManagerImpl.java:716)
    at org.model.JpaTest.test(JpaTest.java:37)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.ClassCastException: org.model.TableB cannot be cast to java.lang.Number
    at org.apache.openjpa.util.ApplicationIds$PrimaryKeyFieldManager.fetchLongField(ApplicationIds.java:669)
    at org.apache.openjpa.enhance.org$model$TableA$pcsubclass.pcCopyKeyFieldsToObjectId(Unknown Source)
    at org.apache.openjpa.enhance.PCRegistry.copyKeyFieldsToObjectId(PCRegistry.java:169)
    at org.apache.openjpa.util.ApplicationIds.fromPKValues(ApplicationIds.java:224)
    at org.apache.openjpa.enhance.ReflectingPersistenceCapable.pcNewObjectIdInstance(ReflectingPersistenceCapable.java:277)
    at org.apache.openjpa.util.ApplicationIds.create(ApplicationIds.java:427)
    at org.apache.openjpa.kernel.BrokerImpl.persistInternal(BrokerImpl.java:2675)
    at org.apache.openjpa.kernel.BrokerImpl.persistAll(BrokerImpl.java:2521)
    ... 32 more

persistence.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
    <persistence-unit name="rd-jpa" transaction-type="RESOURCE_LOCAL">
        <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
        <class>org.model.TableA</class>
        <class>org.model.TableB</class>
        <properties>
            <property name="openjpa.ConnectionURL"
                value="jdbc:postgresql://localhost:5432/mydb" />
            <property name="openjpa.ConnectionDriverName" value="org.postgresql.Driver" />
            <property name="openjpa.ConnectionUserName" value="postgres" />
            <property name="openjpa.ConnectionPassword" value="postgres" />
            <property name="openjpa.DynamicEnhancementAgent" value="true" />
            <property name="openjpa.RuntimeUnenhancedClasses" value="supported" />
            <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)" />
        </properties>
    </persistence-unit>
</persistence>

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>jpa</groupId>
    <artifactId>jpa</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <build>
        <sourceDirectory>src</sourceDirectory>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source />
                    <target />
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.apache.openjpa</groupId>
            <artifactId>openjpa-maven-plugin</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.3-1102-jdbc41</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
        </dependency>
    </dependencies>
</project>

回答1:

Try to get rid of the openjpa.RuntimeUnenhancedClasses property and enhance your Entities properly.