Hibernate 4 ClassCastException при загрузке LAZY, в то время как EAGER работает нормально

У меня есть следующая корневая сущность JOINED-наследования для географических областей (таких как континенты, страны, штаты и т.д.):

@Entity
@Table(name = "GeoAreas")
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class GeoArea implements Serializable
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column
    protected Integer id;

    @Column
    protected String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id", referencedColumnName = "id")
    protected GeoArea parent;

    ...
}

Как вы можете видеть, географическая область имеет простой авто-идентификатор как PK, имя и связь со своим родителем (самоссылка). Обратите внимание на отношение parent геозоны, отображенное как FetchType.LAZY. В БД parent_id FK является NOT NULL, что делает эту связь необязательной. По умолчанию для @ManyToOne стоит optional = true, поэтому сопоставления кажутся правильными.

Подклассы определяют дополнительные свойства и на самом деле не представляют интереса. Данные в БД связаны правильно, так как геозоны могут быть перечислены без проблем через JPQL (с немного другим FetchType. EAGER отображением на parent, см. конец текста):

Arena list with EAGER loading

Каждая строка является экземпляром:

public class ArenaListViewLine
{
    private final Integer arenaId;
    private final String arenaName;
    private final String arenaLabel;

    private final Boolean hasPostAddress;

    ...

    public ArenaListViewLine(Arena arena, Boolean hasPostAddress)
    {
        // init fields
        ...

        List<String> continentNames = new ArrayList<String>();
        List<String> countryNames = new ArrayList<String>();
        List<String> regionNames = new ArrayList<String>();
        List<String> stateNames = new ArrayList<String>();
        List<String> districtNames = new ArrayList<String>();
        List<String> clubShorthands = new ArrayList<String>();

        // add each geo area to list whose club is a user of an arena (an arena has several usages)
        // in border areas of states two clubs from different states might use an arena (rare!)
        // this potentially adds several states to an entry in the arena list (non in DB yet)
        for ( Usage us : usages )
        {
            Club cl = us.getClub();

            // a club is located in one district at all times (required, NOT NULL)
            District di = cl.getDistrict();

            System.out.println("arena = " + arenaName + ": using club's district parent = " + di.getParent());

            State st = (State)di.getParent(); // ClassCastException here!

            ...
    }

    ...
}

При выполнении запроса списка с отображением parent как LAZY, я получаю следующее исключение:

...
Caused by: org.hibernate.QueryException: could not instantiate class [com.kawoolutions.bbstats.view.ArenaListViewLine] from tuple
    at org.hibernate.transform.AliasToBeanConstructorResultTransformer.transformTuple(AliasToBeanConstructorResultTransformer.java:57) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
    at org.hibernate.hql.internal.HolderInstantiator.instantiate(HolderInstantiator.java:95) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
    at org.hibernate.loader.hql.QueryLoader.getResultList(QueryLoader.java:438) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
    at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2279) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
    at org.hibernate.loader.Loader.list(Loader.java:2274) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
    at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:470) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:355) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
    at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:196) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
    at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1115) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
    at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
    at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:252) [hibernate-entitymanager-4.0.0.Final.jar:4.0.0.Final]
    ... 96 more
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) [:1.7.0_02]
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) [:1.7.0_02]
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) [:1.7.0_02]
    at java.lang.reflect.Constructor.newInstance(Unknown Source) [:1.7.0_02]
    at org.hibernate.transform.AliasToBeanConstructorResultTransformer.transformTuple(AliasToBeanConstructorResultTransformer.java:54) [hibernate-core-4.0.0.Final.jar:4.0.0.Final]
    ... 106 more
Caused by: java.lang.ClassCastException: com.kawoolutions.bbstats.model.GeoArea_$$_javassist_273 cannot be cast to com.kawoolutions.bbstats.model.State
    at com.kawoolutions.bbstats.view.ArenaListViewLine.<init>(ArenaListViewLine.java:92) [classes:]
    ... 111 more

Println перед трассировкой стека:

13:57:47,245 INFO  [stdout] (http--127.0.0.1-8080-4) arena = Joachim-Schumann-Schule: using club's district parent = com.kawoolutions.bbstats.model.State@2b60693e[id=258,name=Hesse,isoCode=HE,country=com.kawoolutions.bbstats.model.Country@17f9976b[id=88,name=Germany,isoCode=DE,isoNbr=276,dialCode=<null>]]

В println ясно сказано, что parent является экземпляром State, но он не может быть приведен к State? Понятия не имею...

При изменении FetchType GeoArea.parent на EAGER все работает нормально (см. изображение выше).

Что я делаю не так? Что не так с подсказкой LAZY?

Спасибо

PS: Я использую Hibernate 4.0.0.Final, маппинги все стандартные JPA, сервер - JBoss AS 7.

8
задан Kawu 8 November 2017 в 15:07
поделиться