Hello,
I use JADE library which provides ready classes for lots of physical quantities. I want to store the physical quantity in the database. To do this I implemented the CompositeUserType interface.
But there must be an error in my mapping file or CompositeUserType implementation. When Hibernate runs the Configuration, a MappingException is thrown, which says "property mapping has wrong number of columns".
The Hibernate version is: 2.1
Trace of exception:
Code:
net.sf.hibernate.MappingException: property mapping has wrong number of columns: testJADE.SimpleQuantity.quantity type: com.dautelle.units.CustomQuantity
at net.sf.hibernate.mapping.PersistentClass.validate(PersistentClass.java:269)
at net.sf.hibernate.mapping.RootClass.validate(RootClass.java:199)
at net.sf.hibernate.cfg.Configuration.validate(Configuration.java:587)
at net.sf.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:744)
at testJADE.Main.configure(Main.java:16)
The exception is thrown on this line:
Code:
sf = new Configuration()
.addClass(SimpleQuantity.class)
.buildSessionFactory();
SimpleQuantity is a very simple Hibernate persistable class:
Code:
public class SimpleQuantity {
Long id;
Quantity quantity;
// getter/setters
Quantity is a class from JADE library. It stores the amount inside a range of max and min amounts. It also stores the physical unit of the amount. Since it doesn't provide the accessors needed to map it as a component, I defined my own custom type.
Code:
public class CustomQuantity implements CompositeUserType{
public String[] getPropertyNames() {
return new String[]{"minimum","systemUnit"};
}
public Type[] getPropertyTypes() {
return new Type[]{ Hibernate.DOUBLE, Hibernate.OBJECT };
}
public Object getPropertyValue(Object component, int property) {
Quantity q = ((Quantity) component);
if( property == 0 ){
return new Double((q.getMinimum() + q.getMaximum())/2.0);
}
if( property == 1 ){
return q.getSystemUnit();
}
return null;
}
public void setPropertyValue(Object component, int property, Object value) throws HibernateException {
}
public Class returnedClass() {
return Quantity.class;
}
public boolean equals(Object x, Object y) throws HibernateException {
return x.equals(y);
}
public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException {
Double amount = (Double) Hibernate.DOUBLE.nullSafeGet(rs, names[0]);
String symbol = (String) Hibernate.STRING.nullSafeGet(rs, names[1]);
return ( amount==null && symbol==null ) ? null :
Quantity.valueOf(amount.doubleValue(),BaseUnit.getInstance(symbol)) ;
}
public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException {
double min = ((Quantity) value).getMinimum();
double max = ((Quantity) value).getMaximum();
Double result = new Double((min+max)/2.0);
String symbol = ((Quantity) value).getSystemUnit().getSystemUnit()._symbol;
Hibernate.DOUBLE.nullSafeSet(st, result, index);
Hibernate.STRING.nullSafeSet(st, symbol, index+1);
}
public Object deepCopy(Object value) throws HibernateException {
if ( value == null) return null;
Quantity q = (Quantity) value;
return Quantity.valueOf((q.getMinimum()+q.getMaximum())/2.0,q.getSystemUnit());
}
public boolean isMutable() {
return false;
}
public Serializable disassemble(Object value, SessionImplementor session) throws HibernateException {
return (Serializable) deepCopy(value);
}
public Object assemble(Serializable cached, SessionImplementor session, Object owner) throws HibernateException {
return (Serializable) deepCopy(cached);
}
}
I debugged the code. The cause of the exception lies in SimpleValue.isValid().
Code:
public boolean isValid(Mapping mapping) throws MappingException {
return getColumnSpan()==getType().getColumnSpan(mapping);
}
Here getColumnSpan() returns 2. Whereas getType().getColumnSpan(mapping) returns 3.
What I didn't understand is the value 3. Actually I defined only 2 columns in my mapping file for CustomQuantity.
Code:
<hibernate-mapping>
<!-- testJADE.SimpleQuantity root -->
<class name="testJADE.SimpleQuantity" table="SimpleQuantity">
<id name="id" type="long" column="id">
<generator class="native"/>
</id>
<property name="quantity" type="com.dautelle.units.CustomQuantity">
<column name="minimum"/>
<column name="unit"/>
</property>
</class>
</hibernate-mapping>
May you guess, where might be the problem? Where should I look?
If you may send me some simple CompositeUserType examples, I would appreciate. I reviewed DoubleStringType and MultiplicityType examples in Hibernate test package, although I couldn't run MultiplicityType example.
Thanks for your interest.