I have the following JOINED inheritance root entity for geographic areas (like continents, countries, states etc.):
@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;
...
}
As you can see a geo area has a simple auto-ID as PK, a name, and a relationship to its parent (self reference). Please pay attention to the parent
geo area relationship mapped as FetchType.LAZY
. In the DB the FK's parent_id
is NOT NULL
making the relationship optional. The default for @ManyToOne
is optional = true
, so the mappings seem to be correct.
The sub classes define additional properties and aren't of interest really. The data in the DB is linked correctly as the geo areas can be listed without problems via JPQL (with a slightly different FetchType.EAGER
mapping on parent
, see end of text):
Each line is an instance of:
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!
...
}
...
}
When running the list query with parent mapped as LAZY, I get the following exception:
...
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
The println prior to the stack trace is:
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>]]
The println clearly says the parent is an instance of State, but it cannot be cast to State? I have no idea...
When changing the FetchType of GeoArea.parent to EAGER everything works fine (see image above).
What am I doing wrong? What's wrong with the LAZY hint?
Thanks
PS: I'm using Hibernate 4.0.0.Final, the mappings are all standard JPA, server is JBoss AS 7.