Any ideas, looks ok to me
Code:
Mapping documents:
<class name="edina.clive.domain.Layer" table="layers">
<meta attribute="class-description">
A layer object which holds a list of layer sub-objects and a list of Style names in place of a style object
</meta>
<!-- also db column layerbbox -->
<composite-id>
<key-property name="layerName" />
<key-property name="productName"/>
</composite-id>
<property name="subLayers" column="subLayers" type="edina.clive.domain.hibernate.SubLayerUserType"/>
<!-- TODO: Envelope -->
<!-- Initial version of style in which there was no style table,
only a comma separated list in a layer field, may be going
back to this method once I figure out how to do it in Hibernate
<property name="styles" type="edina.clive.domain.hibernate.StyleUserType">
<column name="styleNames"/>
<column name="styleTitles"/>
URL?
</property>
-->
<property name="layerTitle" />
<property name="srs" column="layerSRS" />
<property name="minimumScale" column="layerscalemin"/>
<property name="maximumScale" column="layerscalemax"/>
</class>
Code:
Full stack trace of any exception that occurs:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactoryOrder' defined in URL [file:src/main/webapp/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is org.hibernate.MappingException: property mapping has wrong number of columns: edina.clive.domain.Layer.subLayers type: edina.clive.domain.hibernate.SubLayerUserType
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1338)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
at java.security.AccessController.doPrivileged(Native Method)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:423)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:728)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:380)
at org.springframework.test.AbstractSingleSpringContextTests.createApplicationContext(AbstractSingleSpringContextTests.java:199)
at org.springframework.test.AbstractSingleSpringContextTests.loadContextLocations(AbstractSingleSpringContextTests.java:179)
at org.springframework.test.AbstractSingleSpringContextTests.loadContext(AbstractSingleSpringContextTests.java:158)
at org.springframework.test.AbstractSpringContextTests.getContext(AbstractSpringContextTests.java:105)
at org.springframework.test.AbstractSingleSpringContextTests.setUp(AbstractSingleSpringContextTests.java:87)
at junit.framework.TestCase.runBare(TestCase.java:128)
at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:69)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:120)
at junit.framework.TestSuite.runTest(TestSuite.java:230)
at junit.framework.TestSuite.run(TestSuite.java:225)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: org.hibernate.MappingException: property mapping has wrong number of columns: edina.clive.domain.Layer.subLayers type: edina.clive.domain.hibernate.SubLayerUserType
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:441)
at org.hibernate.mapping.RootClass.validate(RootClass.java:192)
at org.hibernate.cfg.Configuration.validate(Configuration.java:1108)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1293)
at org.springframework.orm.hibernate3.LocalSessionFactoryBean.newSessionFactory(LocalSessionFactoryBean.java:814)
at org.springframework.orm.hibernate3.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:732)
at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.afterPropertiesSet(AbstractSessionFactoryBean.java:211)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1369)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1335)
... 31 more
Code:
Custom UserType:
package edina.clive.domain.hibernate;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.type.Type;
import org.hibernate.usertype.CompositeUserType;
import edina.clive.domain.Layer;
/**
* @author Ross Drew
*
* Custom domain object user type for list of sub layers inside a layer
*/
public class SubLayerUserType implements CompositeUserType {
@Override
public Object assemble(Serializable cached, SessionImplementor session,
Object owner) throws HibernateException {
// TODO Auto-generated method stub
return null;
}
@Override
public Object deepCopy(Object value) throws HibernateException {
// TODO Auto-generated method stub
return null;
}
@Override
public Serializable disassemble(Object value, SessionImplementor session)
throws HibernateException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean equals(Object x, Object y) throws HibernateException {
return (x == null) ? (y == null) : x.equals(y);
}
@Override
public String[] getPropertyNames() {
return new String[] {"layerName","productName","subLayers","layerTitle","srs","minimumScale","maximumScale"};
}
@Override
public Type[] getPropertyTypes() {
return new Type[] {Hibernate.STRING, Hibernate.STRING, Hibernate.STRING, Hibernate.STRING, Hibernate.STRING,Hibernate.DOUBLE,Hibernate.DOUBLE};
}
@Override
public int hashCode(Object x) throws HibernateException {
// TODO Auto-generated method stub
return 0;
}
@Override
public boolean isMutable() {
return false;
}
@Override
public Object nullSafeGet(ResultSet rs, String[] names,
SessionImplementor session, Object owner) throws HibernateException,
SQLException {
String rSubLayers = (String)Hibernate.STRING.nullSafeGet(rs, names[0]);
/*DEBUG*///System.out.println("Returned: "+rSubLayers);
/*DEBUG*///System.out.println("Owner: "+owner.toString());
HashSet<Layer> returnedLayers = new HashSet<Layer>();
for (String lyrName : rSubLayers.split(",")){
Layer lyr = (Layer) session.getFactory().getCurrentSession().get(Layer.class, lyrName.trim()); //TODO: second argument??
returnedLayers.add(lyr);
}
/*DEBUG*///System.out.println("Retrieved: "+returnedLayers.getClass());
return returnedLayers;
}
@Override
public void nullSafeSet(PreparedStatement st, Object value, int index,
SessionImplementor session) throws HibernateException, SQLException {
if (value == null)
throw new IllegalArgumentException( "Received object in nullSafeSet was null - " + returnedClass() );
if (!(value instanceof Set
&& (((Set)value).iterator().next()) instanceof Layer)){
throw new IllegalArgumentException( "Received object in nullSafeSet was " + value.getClass().getName() + " in " + returnedClass() );
}
StringBuilder subLayers = new StringBuilder("");
if (value == null) {
st.setString(index, "");
} else {
//Build the comma separated lists for database
for (Layer lyr : (Set<Layer>)value){//if this is not a set of layers, the exception would have been thrown already
//Insert layer into layer table
session.getFactory().getCurrentSession().save(lyr);
subLayers.append(lyr.getLayerName()+",");
}
//Remove additional comma
subLayers = subLayers.deleteCharAt(subLayers.length()-1);
}
Hibernate.STRING.nullSafeSet(st, subLayers.toString(), index);
}
@Override
public Object replace(Object original, Object target,
SessionImplementor session, Object owner) throws HibernateException {
// TODO Auto-generated method stub
return null;
}
@Override
public Class returnedClass() {
return Layer[].class;
}
@Override
public Object getPropertyValue(Object component, int property)
throws HibernateException {
if (!(component instanceof Layer)){
throw new IllegalArgumentException("Unknown component: "+component);
}
Layer layer = (Layer)component;
String result;
switch(property){
case 0:
result = layer.getLayerName();
break;
case 1:
result = layer.getProductName();
break;
case 2:
//Build layer list string
StringBuilder layerList = new StringBuilder("");
for (Layer l : layer.getLayers()){
layerList.append(l.getLayerName()+",");
}
//Remove additional comma
result = layerList.substring(0, layerList.length()-1);
case 3:
result = layer.getTitle();
break;
case 4:
result = layer.getSrs();
break;
case 5:
return layer.getMinimumScale();
case 6:
return layer.getMaximumScale();
default:
throw new IllegalArgumentException("Unknown property: "+property);
}
return result;
}
@Override
public void setPropertyValue(Object component, int property, Object value){
if (!(component instanceof Layer)){
throw new IllegalArgumentException( "Received object in setPropertyValue was " + component.getClass().getName() + " in " + returnedClass() );
}
Layer layer = (Layer)component;
//XXX: Add some type checking here?
switch(property){
case 0:
layer.setLayerName((String)value);
break;
case 1:
layer.setProductName((String)value);
break;
case 2:
//TODO: what to do with this?
System.out.println("Case 2, component:"+component.getClass()+", value:"+value.getClass());
case 3:
layer.setTitle((String)value);
break;
case 4:
layer.setSrs((String)value);
break;
case 5:
layer.setMinimumScale((Double)value);
break;
case 6:
layer.setMaximumScale((Double)value);
break;
default:
throw new IllegalArgumentException("Unknown property: "+property);
}
}
}