-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: NullSafeNumericUserType for use with <NULL> values
PostPosted: Tue Aug 08, 2006 2:20 pm 
Newbie

Joined: Wed Jul 26, 2006 8:00 am
Posts: 3
Location: Cary, NC
If your database schema was designed properly you'll never need this. But, if you happen to be working with a legacy database schema where a numeric type database column could possibly be <NULL> you'll get a hibernate error if you try mapping to primative data types.

I encountered this problem. The database column was a type 'int'. The POJO property I was mapping to was an 'int'. When I attempted to fetch a row that contained <NULL> in this column, hibernate threw an exception.

14:13:28,339 INFO DefaultLoadEventListener:95 - Error performing load command
org.hibernate.PropertyAccessException: exception setting property value with CGLIB (set hibernate.cglib.use_reflection_optimizer=false for more info) setter of com.perse.onestaff.wsm.domain.concurrency.LockInfo.setPositionId
at ...
Caused by: net.sf.cglib.beans.BulkBeanException
at com.perse.onestaff.wsm.domain.concurrency.LockInfo$$BulkBeanByCGLIB$$32df94d6.setPropertyValues(<generated>)
at org.hibernate.tuple.PojoEntityTuplizer.setPropertyValuesWithOptimizer(PojoEntityTuplizer.java:212)
... 46 more
Caused by: java.lang.NullPointerException
... 48 more

So, to get around this problem I created a custom UserType that checks for null when getting the value from the resultset and defaults to 0 (zero).

This only works if you don't need to know that the value was actually <NULL> and defaulting to 0 is ok.

------------------------------------------------------------------


package com.mycompany.hibernate;

import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
import org.hibernate.usertype.ParameterizedType;

import java.sql.*;
import java.util.Properties;
import java.io.Serializable;

/**
* Hibernate UserType for numeric database values that could have <NULL> values.
* POJO property data type can be any Java Primitive Data Type (see below).
*
*
* Java's Primitive Data Types
*
* boolean: 1-bit. May take on the values true and false only.
* byte: 1 signed byte (two's complement). Covers values from -128 to 127.
* short: 2 bytes, signed (two's complement), -32,768 to 32,767
* int: 4 bytes, signed (two's complement). -2,147,483,648 to 2,147,483,647. Like all numeric types ints may be cast into other numeric types (byte, short, long, float, double). When lossy casts are done (e.g. int to byte) the conversion is done modulo the length of the smaller type.
* long: 8 bytes signed (two's complement). Ranges from -9,223,372,036,854,775,808 to +9,223,372,036,854,775,807.
* float: 4 bytes, IEEE 754. Covers a range from 1.40129846432481707e-45 to 3.40282346638528860e+38 (positive or negative).
* double: 8 bytes IEEE 754. Covers a range from 4.94065645841246544e-324d to 1.79769313486231570e+308d (positive or negative).
*/
public class NullSafeNumericUserType implements UserType, ParameterizedType {

public static final String DATA_TYPE_PROPERTY = "dataType";

private int[] SQL_TYPES = {Types.NUMERIC};

private enum DataType {

booleanDT,byteDT,shortDT,intDT,longDT,floatDT,doubleDT }

private DataType dataType;

public int[] sqlTypes() {
return SQL_TYPES;
}

public void setParameterValues(Properties parameters) {
String sType = parameters.getProperty(DATA_TYPE_PROPERTY) + "DT";
try {
dataType = DataType.valueOf(sType);
}
catch (Exception e) {
dataType = DataType.intDT;
}
}

public Class returnedClass() {
Class dataTypeClass = Integer.class;
switch (dataType) {
case booleanDT:
dataTypeClass = Boolean.class;
break;
case byteDT:
dataTypeClass = Byte.class;
break;
case shortDT:
dataTypeClass = Short.class;
break;
case intDT:
dataTypeClass = Integer.class;
break;
case longDT:
dataTypeClass = Long.class;
break;
case floatDT:
dataTypeClass = Float.class;
break;
case doubleDT:
dataTypeClass = Double.class;
break;
}
return dataTypeClass;
}

public boolean equals(Object x, Object y) throws HibernateException {
if (x == y) {
return true;
}
else if (x == null || y == null) {
return false;
}
else {
return x.equals(y);
}
}

public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner)
throws HibernateException, SQLException {
Object result = null;
switch (dataType) {
case booleanDT:
result = new Boolean(false);
boolean booleanValue = resultSet.getBoolean(names[0]);
if (!resultSet.wasNull()) {
result = booleanValue ==
false ? result : new Boolean(booleanValue);
}
break;
case byteDT:
result = new Byte((byte) 0);
byte byteValue = resultSet.getByte(names[0]);
if (!resultSet.wasNull()) {
result = byteValue ==
0 ? result : new Byte(byteValue);
}
break;
case shortDT:
result = new Short((short) 0);
short shortValue = resultSet.getShort(names[0]);
if (!resultSet.wasNull()) {
result = shortValue ==
0 ? result : new Integer(shortValue);
}
break;
case intDT:
result = new Integer(0);
int intValue = resultSet.getInt(names[0]);
if (!resultSet.wasNull()) {
result = intValue ==
0 ? result : new Integer(intValue);
}
break;
case longDT:
result = new Long((long) 0);
long longValue = resultSet.getLong(names[0]);
if (!resultSet.wasNull()) {
result = longValue ==
(long) 0 ? result : new Long(longValue);
}
break;
case floatDT:
result = new Float((float) 0);
float floatValue = resultSet.getFloat(names[0]);
if (!resultSet.wasNull()) {
result = floatValue ==
(float) 0 ? result : new Float(floatValue);
}
break;
case doubleDT:
result = new Double((double) 0);
double doubleValue = resultSet.getDouble(names[0]);
if (!resultSet.wasNull()) {
result = doubleValue ==
(double) 0 ? result : new Double(doubleValue);
}
break;
}
return result;
}

public void nullSafeSet(
PreparedStatement statement, Object value, int index)
throws HibernateException, SQLException {
switch (dataType) {
case booleanDT:
if (value == null) statement.setBoolean(index, false);
else statement.setBoolean(
index, ((Boolean) value).booleanValue());
break;
case byteDT:
if (value == null) statement.setByte(index, (byte) 0);
else statement.setByte(index, ((Byte) value).byteValue());
break;
case shortDT:
if (value == null) statement.setShort(index, (short) 0);
else statement.setShort(index, ((Short) value).shortValue());
break;
case intDT:
if (value == null) statement.setInt(index, 0);
else statement.setInt(index, ((Integer) value).intValue());
break;
case longDT:
if (value == null) statement.setLong(index, (long) 0);
else statement.setLong(index, ((Long) value).longValue());
break;
case floatDT:
if (value == null) statement.setFloat(index, (float) 0);
else statement.setFloat(index, ((Float) value).floatValue());
break;
case doubleDT:
if (value == null) statement.setDouble(index, (double) 0);
else statement.setDouble(index, ((Double) value).doubleValue());
break;
}
}

public Object deepCopy(Object value) throws HibernateException {
return value;
}

public boolean isMutable() {
return false;
}

public Object assemble(Serializable cached, Object owner)
throws HibernateException {
return cached;
}

public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value;
}

public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}

public Object replace(Object original, Object target, Object owner)
throws HibernateException {
return original;
}

}

-------------------------------------------------------------------

I'd like to hear if this makes sense or if there is a better way.

Thanks,
Scott


Top
 Profile  
 
 Post subject: Re: NullSafeNumericUserType for use with <NULL> values
PostPosted: Tue Aug 08, 2006 2:33 pm 
Newbie

Joined: Wed Jul 26, 2006 8:00 am
Posts: 3
Location: Cary, NC
And to use it my LockInfo.cfg.xml file looks like this:

<hibernate-mapping>

<typedef name="NullSafeInt" class="com.mycompany.hibernate.NullSafeNumericUserType">
<param name="dataType">int</param>
</typedef>

<class name="com.mycompany.domain.LockInfo"
table="LOCKINFO">

...

<property name="positionId" column="POSITION_ID" type="NullSafeInt" />

</class>

</hibernate-mapping>


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.