My team is embarking on a project using Hibernate. It's been going very well, but I've run into a problem when trying to persist a collection of InetAddresses that are mapped using a custom CompositeUserType.
We have a requirement to store IPv6 addresses in the database. Unfortunately, there is no numeric column type in MySQL large enough to hold the entire 128-bit address, so I've chosen to store the addresses using two BIGINT (64-bit) UNSIGNED columns. I've written a custom CompositeUserType that knows how to map from java.net.InetAddress to the 2 columns and vice-versa. This works great for persisting a single InetAddress property, but I'm having problems when I try to persist a Set of InetAddresses.
The online docs seems to mention that this is possible...
Quote:
5.2.4. Custom value types
It is relatively easy for developers to create their own value types. For example, you might want to persist properties of type java.lang.BigInteger to VARCHAR columns. Hibernate does not provide a built-in type for this. But custom types are not limited to mapping a property (or collection element) to a single table column. So, for example, you might have a Java property getName()/setName() of type java.lang.String that is persisted to the columns FIRST_NAME, INITIAL, SURNAME.
I've reduced the problematic class to be as simple as possible. HostGroup is the class that I'm trying to save. All it contains is an int identifier and a Set of InetAddresses.
Any help would be greatly appreciated.
Hibernate version: 2.1.7c
Class source code:
Code:
package myapp;
import java.net.InetAddress;
public class HostGroup {
private int id;
private Set<InetAddress> ips;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Set<InetAddress> getIps() {
return ips;
}
public void setIps(Set<InetAddress> ips) {
this.ips = ips;
}
}
Mapping documents: HostGroup.hbm.xml
Code:
<hibernate-mapping>
<class name="myapp.HostGroup" table="seczones">
<id name="id">
<generator class="native"/>
</id>
<set name="ips" table="seczone_ips">
<key column="seczone_id"/>
<element type="myapp.customtypes.IPv6UserType">
<column name="IP_high"/>
<column name="IP_low"/>
</element>
</set>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():Code:
session.saveOrUpdate(hostGroup);
Full stack trace of the exception that occurs:Code:
net.sf.hibernate.MappingException: Unknown entity class: java.net.Inet6Address
at net.sf.hibernate.impl.SessionFactoryImpl.getPersister(SessionFactoryImpl.java:347)
at net.sf.hibernate.impl.SessionImpl.getClassPersister(SessionImpl.java:2710)
at net.sf.hibernate.impl.SessionImpl.getPersister(SessionImpl.java:2717)
at net.sf.hibernate.impl.SessionImpl.isSaved(SessionImpl.java:2754)
at net.sf.hibernate.collection.PersistentCollection.getOrphans(PersistentCollection.java:753)
at net.sf.hibernate.collection.Set.getOrphans(Set.java:47)
at net.sf.hibernate.impl.SessionImpl.getOrphans(SessionImpl.java:3285)
at net.sf.hibernate.engine.Cascades.deleteOrphans(Cascades.java:542)
at net.sf.hibernate.engine.Cascades.cascadeCollection(Cascades.java:533)
at net.sf.hibernate.engine.Cascades.cascade(Cascades.java:452)
at net.sf.hibernate.engine.Cascades.cascade(Cascades.java:503)
at net.sf.hibernate.impl.SessionImpl.doSave(SessionImpl.java:961)
at net.sf.hibernate.impl.SessionImpl.doSave(SessionImpl.java:866)
at net.sf.hibernate.impl.SessionImpl.saveWithGeneratedIdentifier(SessionImpl.java:784)
at net.sf.hibernate.impl.SessionImpl.save(SessionImpl.java:747)
at net.sf.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:1397)
at myapp.MyServiceImpl.saveHostGroup(MyServiceImpl.java:147)
...<snip>...
Name and version of the database you are using:MySQL 4.1.7-standard
The generated SQL (show_sql=true):insert into seczones values ( )
MySQL table schema:Code:
CREATE TABLE seczones (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
) TYPE=INNODB;
CREATE TABLE seczone_ips (
seczone_id INT UNSIGNED NOT NULL,
IP_high BIGINT UNSIGNED NOT NULL, # the high 64 bits of the address
IP_low BIGINT UNSIGNED NOT NULL, # the low 64 bits of the address
INDEX(seczone_id), FOREIGN KEY(seczone_id) REFERENCES seczones(id)
) TYPE=INNODB;
Debug level Hibernate log excerpt:Code:
15:38:44,818 DEBUG SessionFactoryImpl:196 - instantiated session factory
15:38:44,876 DEBUG SessionImpl:558 - opened session
15:38:44,879 DEBUG Cascades:312 - id unsaved-value: 0
15:38:44,879 DEBUG SessionImpl:1396 - saveOrUpdate() unsaved instance
15:38:44,881 DEBUG SessionImpl:834 - saving [myapp.HostGroup#<null>]
15:38:44,882 DEBUG SessionImpl:2329 - executing insertions
15:38:44,882 DEBUG Cascades:497 - processing cascades for: myapp.HostGroup
15:38:44,886 DEBUG Cascades:506 - done processing cascades for: myapp.HostGroup
15:38:44,897 DEBUG WrapVisitor:81 - Wrapped collection in role: myapp.HostGroup.ips
15:38:44,900 DEBUG EntityPersister:486 - Inserting entity: myapp.HostGroup (native id)
15:38:44,905 DEBUG BatcherImpl:203 - about to open: 0 open PreparedStatements, 0 open ResultSets
15:38:44,906 DEBUG SQL:229 - insert into seczones values ( )
Hibernate: insert into seczones values ( )
15:38:44,906 DEBUG BatcherImpl:252 - preparing statement
15:38:44,927 DEBUG EntityPersister:384 - Dehydrating entity: [myapp.HostGroup#<null>]15:38:44,974 DEBUG AbstractEntityPersister:1235 - Natively generated identity: 13
15:38:44,975 DEBUG BatcherImpl:210 - done closing: 0 open PreparedStatements, 0 open ResultSets
15:38:44,975 DEBUG BatcherImpl:272 - closing statement
15:38:44,979 DEBUG Cascades:497 - processing cascades for: myapp.HostGroup
15:38:44,982 DEBUG Cascades:524 - cascading to collection: myapp.HostGroup.ips
** exception occurs here **