I tried to write custom UserType; couldn't find an example to base it on, so went with trial and error. I'm getting an exception with my "CollectionUserType". The intent is to serialize a Collection member variable to a VARCHAR column. Could somebody tell me what I'm doing wrong?
Here is my o/r mapping file:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping.dtd">
<hibernate-mapping>
<class name="com.teradata.tap.component.system.resultset.ResultSetVO" table="TapResultset">
<id name="id" column="ID" type="long">
<generator class="assigned"/>
</id>
<property name="label" column="Label"/>
<property name="columnValueTypes" column="ColumnTypeVector" type="net.sf.hibernate.CollectionUserType" />
<many-to-one name="query" class="com.teradata.tap.component.system.query.QueryVO" column="QueryId" />
</class>
</hibernate-mapping>
Here is the exeption I'm getting when it tries to get a value using the conversion:
Code:
14:28:32,880 ERROR [PersistenceManagerBean] PersistenceManager.getVector(klass,
namespace, acl) failed
java.lang.NullPointerException
at net.sf.hibernate.CollectionUserType.nullSafeGet(CollectionUserType.ja
va:126)
at net.sf.hibernate.type.CustomType.nullSafeGet(CustomType.java:97)
at net.sf.hibernate.type.AbstractType.hydrate(AbstractType.java:66)
at net.sf.hibernate.loader.Loader.hydrate(Loader.java:419)
at net.sf.hibernate.loader.Loader.loadFromResultSet(Loader.java:373)
at net.sf.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:342)
at net.sf.hibernate.loader.Loader.getRow(Loader.java:281)
at net.sf.hibernate.loader.Loader.doFind(Loader.java:159)
at net.sf.hibernate.loader.Loader.find(Loader.java:620)
at net.sf.hibernate.loader.CriteriaLoader.list(CriteriaLoader.java:81)
at net.sf.hibernate.impl.SessionImpl.find(SessionImpl.java:3157)
at net.sf.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:65)
at com.teradata.tap.system.persistence.ejb.PersistenceManagerBean.getVec
tor(PersistenceManagerBean.java:982)
Here is the code for the "CollectionUserType" I wrote:
Code:
package net.sf.hibernate;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.PreparedStatement;
import java.sql.Types;
import java.util.Vector;
import java.util.Collection;
import java.util.Iterator;
/**
* Created by IntelliJ IDEA.
* User: ab210009
* Date: Dec 9, 2003
* Time: 2:00:16 PM
* To change this template use Options | File Templates.
*/
public class CollectionUserType implements UserType {
private static final String NULLVALUE = "#NULL#";
private static final String EMPTYCOLLEC = "#EMTPY#";
private static final String SEPARATOR = "#";
protected Class objectClass = Collection.class;
public static final int[] SQL_TYPES = {Types.VARCHAR};
public CollectionUserType() {
}
/**
* Return the SQL type codes for the columns mapped by this type. The
* codes are defined on <tt>java.sql.Types</tt>.
* @see java.sql.Types
* @return int[] the typecodes
*/
public int[] sqlTypes() {
return SQL_TYPES;
}
/**
* The class returned by <tt>nullSafeGet()</tt>.
*
* @param session
* @return Class
*/
public Class returnedClass() {
return objectClass;
}
/**
* Compare two instances of the class mapped by this type for persistence
* "equality", ie. equality of persistent state.
*
* @param x
* @param y
* @return boolean
*/
public boolean equals(Object x, Object y) throws HibernateException {
if (x == null && y == null)
return true;
else if (x == null)
return false;
else if (y == null)
return false;
else {
// Check if non-null Collections are equal
Collection xx = (Collection)x;
Collection yy = (Collection)y;
if (xx.size() != yy.size())
return false;
Iterator ix = xx.iterator();
Iterator iy = yy.iterator();
// If any elements don't match return false
while (ix.hasNext()) {
if (ix.next() != iy.next())
return false;
}
return true;
}
}
/**
* Retrieve an instance of the mapped class from a JDBC resultset. Implementors
* should handle possibility of null values.
*
* @param rs a JDBC result set
* @param names the column names
* @param owner the containing entity
* @return Object
* @throws HibernateException
* @throws java.sql.SQLException
*/
public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
// Only 1 column
Object obj = rs.getObject(names[0]);
if (obj != null && obj.toString().length() > 0 && !obj.toString().equalsIgnoreCase(NULLVALUE)) {
Vector v = new Vector();
String input = obj.toString();
int pos = input.indexOf(SEPARATOR);
while (pos >= 0)
{
if (pos == 0)
{
v.add("");
}
else
{
v.add(input.substring(0, pos));
}
if (pos + 1 > input.length()) //# at end causes outof bounds
{
break;
}
input = input.substring(pos + 1, input.length());
pos = input.indexOf(SEPARATOR);
}
return v;
} else if (obj.toString().equalsIgnoreCase(EMPTYCOLLEC)) {
return new Vector();
} else {
return null;
}
}
/**
* Write an instance of the mapped class to a prepared statement. Implementors
* should handle possibility of null values. A multi-column type should be written
* to parameters starting from <tt>index</tt>.
*
* @param st a JDBC prepared statement
* @param obj the object to write
* @param index statement parameter index
* @throws HibernateException
* @throws java.sql.SQLException
*/
public void nullSafeSet(PreparedStatement st, Object obj, int index) throws HibernateException, SQLException {
if (obj == null)
{
// Set null string symbol in PreparedStatement and return
st.setString(index, NULLVALUE);
return;
}
if (!(obj instanceof Collection))
{
throw new HibernateException(
"Object is not a Collection it is a" + obj.getClass().getName());
}
Vector v = (Vector) obj;
if (v.size() == 0)
{
// Set null string symbol in PreparedStatement and return
st.setString(index, NULLVALUE);
return;
}
StringBuffer result = new StringBuffer();
for (int i = 0; i < v.size(); i++)
{
String newSt = v.get(i).toString();
if (newSt.indexOf(SEPARATOR) >= 0)
{
throw new HibernateException(
"An entry in the Vector contains the forbidden "
+ SEPARATOR
+ " character used to separate the strings on the DB");
}
result.append(newSt);
result.append(SEPARATOR);
}
// Set string in PreparedStatement
st.setString(index, result.toString());
}
/**
* Return a deep copy of the persistent state, stopping at entities and at
* collections.
*
* @return Object a copy
*/
public Object deepCopy(Object value) throws HibernateException {
if (value == null)
return null;
Vector copy = null;
try {
copy = new Vector();
Vector orig = (Vector)value;
for (int i=0; i<orig.size(); i++) {
copy.add( orig.get(i) );
}
} catch (ClassCastException ex) {
ex.printStackTrace();
}
return copy;
}
/**
* Are objects of this type mutable?
*
* @return boolean
*/
public boolean isMutable() {
return true;
}
}
[/quote]