Is it possible to create an array with polymorphic elements within hibernate, using a <many-to-any> tag inside an <array> mapping? In other words, is it possible to persist an entity that includes a field that looks as follows:
private Object[] objectArray;
I am using the basic org.hibernate.auction example that is supplied with the hibernate libraries to test this mapping. I added a class called StringEntity.java and changed the User.hbm.xml mapping file to include the array.
The <array> mapping allows one to include <many-to-any> tags, but when I run my code, I get a NullPointerException at java.lang.reflect.Array.newArray(Native Method).
I stepped through the code and noticed in net.sf.hibernate.cfg.Binder that the method bindArray (line 743) only checks for "element", "one-to-many", "many-to-many" and "composite-element" tags when assigning the ElementClass attribute for the array Collection. No valid tag is found, and I suspect that no ElementClass is set for the net.sf.hibernate.mapping.Array class, which seems to cause the NullPointerException. Does this mean that "many-to-any" is not supported for <array> in the mapping files?
If this is not supported, is there any other way in which I can map such an object array?
Hibernate version: 2.1.8
Mapping documents:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping package="org.hibernate.auction">
<class name="User" table="AuctionUser" proxy="User"> <id name="id" column="id" type="long"> <generator class="native"/> </id> <property name="userName" not-null="true"/> <property name="password" column="`password`"/> <property name="email"/> <component name="name"> <property name="firstName"/> <property name="initial" column="`initial`"/> <property name="lastName"/> </component> <bag name="bids" lazy="true" inverse="true" cascade="save-update"> <key column="bidder"/> <one-to-many class="Bid"/> </bag> <bag name="auctions" lazy="true" inverse="true" cascade="save-update"> <key column="seller"/> <one-to-many class="AuctionItem"/> </bag> <array name="objectArray" table="objectarray" cascade="all" > <key column="id" /> <index column="object_id" type="long" /> <many-to-any id-type="long" meta-type="string" > <meta-value value="XXX" class="com.entelect.hibernate.entity.StringEntity" /> <meta-value value="N1" class="Name" /> <meta-value value="B1" class="Bid" /> <column name="class_type" /> <column name="class_id" /> </many-to-any> </array>
</class> </hibernate-mapping>
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping package="com.entelect.hibernate.entity" schema="entity" auto-import="false"> <class name="StringEntity" table="STRING_ENTITY"> <id name="id" column="STRING_ENTITY_ID" type="long" access="property"> <generator class="native"/> </id> <property name="theString" column="STRING" type="string" access="property"> </property> </class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():
Session s = factory.openSession(); Transaction tx=null; try { tx = s.beginTransaction(); } catch (Exception e) { if (tx!=null) tx.rollback(); throw e; } //Transaction tx = s.beginTransaction(); User seller = new User(); seller.setUserName("oldirty"); seller.setName( new Name("ol' dirty", null, "bastard") ); seller.setEmail("oldirty@hibernate.org"); seller.setAuctions( new ArrayList() ); Object[] x = new Object[2]; x[0] = new StringEntity("XXX one"); x[1] = new StringEntity("XXX two"); for (int i=0; i<x.length; i++) { System.out.println("x[" + i + "] = " + x[i].toString()); } seller.setObjectArray(x); s.save(seller); tx.commit(); s.close();
package com.entelect.hibernate.entity;
public class StringEntity { private Long id; private String theString; public StringEntity () {}
public StringEntity (String theString) { this.theString = theString; } public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getTheString() { return theString; } public void setTheString(String theString) { this.theString = theString; } }
//$Id: User.java,v 1.3 2004/06/04 01:27:33 steveebersole Exp $ package org.hibernate.auction;
import java.util.List;
/** * @author Gavin King */ public class User extends Persistent { private String userName; private String password; private String email; private Name name; private List bids; private List auctions; private Object[] objectArray; public String getEmail() { return email; }
public String getPassword() { return password; }
public String getUserName() { return userName; }
public void setEmail(String string) { email = string; }
public void setPassword(String string) { password = string; }
public void setUserName(String string) { userName = string; }
public List getAuctions() { return auctions; }
public List getBids() { return bids; }
public void setAuctions(List list) { auctions = list; }
public void setBids(List list) { bids = list; } public String toString() { return userName; }
public Name getName() { return name; }
public void setName(Name name) { this.name = name; } public void setObjectArray(Object[] objectArray) { this.objectArray = objectArray; } public Object[] getObjectArray() { return objectArray; } }
Full stack trace of any exception that occurs:
0 [main] INFO org.hibernate.auction.Main - org.apache.commons.logging.impl.Log4JLogger@c9ba38 50 [main] INFO net.sf.hibernate.cfg.Environment - Hibernate 2.1.8 50 [main] INFO net.sf.hibernate.cfg.Environment - hibernate.properties not found 60 [main] INFO net.sf.hibernate.cfg.Environment - using CGLIB reflection optimizer 60 [main] INFO net.sf.hibernate.cfg.Environment - using JDK 1.4 java.sql.Timestamp handling 80 [main] INFO net.sf.hibernate.cfg.Configuration - Mapping resource: org/hibernate/auction/AuctionItem.hbm.xml 781 [main] INFO net.sf.hibernate.cfg.Binder - Mapping class: org.hibernate.auction.AuctionItem -> AuctionItem 911 [main] INFO net.sf.hibernate.cfg.Configuration - Mapping resource: org/hibernate/auction/Bid.hbm.xml 951 [main] INFO net.sf.hibernate.cfg.Binder - Mapping class: org.hibernate.auction.Bid -> Bid 1001 [main] INFO net.sf.hibernate.cfg.Binder - Mapping subclass: org.hibernate.auction.BuyNow -> Bid 1001 [main] INFO net.sf.hibernate.cfg.Configuration - Mapping resource: org/hibernate/auction/User.hbm.xml 1071 [main] INFO net.sf.hibernate.cfg.Binder - Mapping class: org.hibernate.auction.User -> AuctionUser 1302 [main] INFO net.sf.hibernate.cfg.Binder - Mapping collection: org.hibernate.auction.User.objectArray -> objectarray 1312 [main] ERROR net.sf.hibernate.cfg.Configuration - Could not configure datastore from input stream java.lang.NullPointerException at java.lang.reflect.Array.newArray(Native Method) at java.lang.reflect.Array.newInstance(Unknown Source) at net.sf.hibernate.type.ArrayType.<init>(ArrayType.java:33) at net.sf.hibernate.type.TypeFactory.array(TypeFactory.java:183) at net.sf.hibernate.mapping.Array.getCollectionType(Array.java:29) at net.sf.hibernate.mapping.Collection.getType(Collection.java:275) at net.sf.hibernate.cfg.Binder.bindProperty(Binder.java:454) at net.sf.hibernate.cfg.Binder.createProperty(Binder.java:1081) at net.sf.hibernate.cfg.Binder.propertiesFromXML(Binder.java:1061) at net.sf.hibernate.cfg.Binder.bindRootClass(Binder.java:362) at net.sf.hibernate.cfg.Binder.bindRoot(Binder.java:1256) at net.sf.hibernate.cfg.Configuration.add(Configuration.java:253) at net.sf.hibernate.cfg.Configuration.addInputStream(Configuration.java:289) at net.sf.hibernate.cfg.Configuration.addClass(Configuration.java:355) at org.hibernate.auction.Main.main(Main.java:466) net.sf.hibernate.MappingException: Error reading resource: org/hibernate/auction/User.hbm.xml at net.sf.hibernate.cfg.Configuration.addClass(Configuration.java:358) at org.hibernate.auction.Main.main(Main.java:466) Caused by: net.sf.hibernate.MappingException: java.lang.NullPointerException at net.sf.hibernate.cfg.Configuration.addInputStream(Configuration.java:297) at net.sf.hibernate.cfg.Configuration.addClass(Configuration.java:355) ... 1 more Caused by: java.lang.NullPointerException at java.lang.reflect.Array.newArray(Native Method) at java.lang.reflect.Array.newInstance(Unknown Source) at net.sf.hibernate.type.ArrayType.<init>(ArrayType.java:33) at net.sf.hibernate.type.TypeFactory.array(TypeFactory.java:183) at net.sf.hibernate.mapping.Array.getCollectionType(Array.java:29) at net.sf.hibernate.mapping.Collection.getType(Collection.java:275) at net.sf.hibernate.cfg.Binder.bindProperty(Binder.java:454) at net.sf.hibernate.cfg.Binder.createProperty(Binder.java:1081) at net.sf.hibernate.cfg.Binder.propertiesFromXML(Binder.java:1061) at net.sf.hibernate.cfg.Binder.bindRootClass(Binder.java:362) at net.sf.hibernate.cfg.Binder.bindRoot(Binder.java:1256) at net.sf.hibernate.cfg.Configuration.add(Configuration.java:253) at net.sf.hibernate.cfg.Configuration.addInputStream(Configuration.java:289) ... 2 more Exception in thread "main"
Name and version of the database you are using: PostgreSQL 8.0.1
The generated SQL (show_sql=true): No sql was generated when the error was thrown.
Debug level Hibernate log excerpt:
|