In case anyone's interested, here is the current form of my solution to a datatype that is over 4000 characters and works seamlessly between Oracle and MySQL:
Code:
import java.io.*;
import java.sql.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import org.apache.commons.lang.ObjectUtils;
import net.sf.hibernate.type.ImmutableType;
import net.sf.hibernate.HibernateException;
public class TextType extends ImmutableType {
/** Name of the oracle driver -- used to support Oracle clobs as a special case */
private static final String ORACLE_DRIVER_NAME = "Oracle JDBC driver";
/** Version of the oracle driver being supported with clob. */
private static final int ORACLE_DRIVER_MAJOR_VERSION = 9;
private static final int ORACLE_DRIVER_MINOR_VERSION = 0;
public Object get(ResultSet rs, String name) throws HibernateException, SQLException {
Reader reader = null;
try {
reader = rs.getCharacterStream(name);
} catch (SQLException e) {
// This means we're on mysql and we should treat this like a string
return rs.getString(name);
}
if (reader == null) {
return null;
}
StringBuffer sb = new StringBuffer();
try {
char[] charbuf = new char[4096];
for (int i = reader.read(charbuf); i > 0; i = reader.read(charbuf)) {
sb.append(charbuf, 0, i);
}
} catch (IOException e) {
throw new SQLException(e.getMessage());
}
return sb.toString();
}
public Class returnedClass() {
return String.class;
}
public void set(PreparedStatement st, Object value, int index)
throws SQLException {
try {
//StringReader r = new StringReader((String) value);
//st.setCharacterStream(index, r, ((String) value).length());
clobSet(st, value, index);
} catch (SQLException e) {
st.setString(index, (String) value);
} catch (HibernateException he) {
System.out.println(he);
}
}
public void clobSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException {
DatabaseMetaData dbMetaData = st.getConnection().getMetaData();
if (value == null) {
st.setNull(index, sqlType());
} else if (ORACLE_DRIVER_NAME.equals(dbMetaData.getDriverName())) {
if ((dbMetaData.getDriverMajorVersion() >= ORACLE_DRIVER_MAJOR_VERSION) &&
(dbMetaData.getDriverMinorVersion() >= ORACLE_DRIVER_MINOR_VERSION)) {
try {
// Code compliments of Scott Miller
// support oracle clobs without requiring oracle libraries
// at compile time
// Note this assumes that if you are using the Oracle Driver.
// then you have access to the oracle.sql.CLOB class
// First get the oracle clob class
Class oracleClobClass = Class.forName("oracle.sql.CLOB");
// Get the oracle connection class for checking
Class oracleConnectionClass = Class.forName("oracle.jdbc.OracleConnection");
// now get the static factory method
Class partypes[] = new Class[3];
partypes[0] = Connection.class;
partypes[1] = Boolean.TYPE;
partypes[2] = Integer.TYPE;
Method createTemporaryMethod = oracleClobClass.getDeclaredMethod("createTemporary", partypes);
// now get ready to call the factory method
Field durationSessionField = oracleClobClass.getField("DURATION_SESSION");
Object arglist[] = new Object[3];
Connection conn = st.getConnection();
// Make sure connection object is right type
if (!oracleConnectionClass.isAssignableFrom(conn.getClass())) {
throw new HibernateException("JDBC connection object must be a oracle.jdbc.OracleConnection. " +
"Connection class is " + conn.getClass().getName());
}
arglist[0] = conn;
arglist[1] = Boolean.TRUE;
arglist[2] = durationSessionField.get(null); //null is valid because of static field
// Create our CLOB
Object tempClob = createTemporaryMethod.invoke(null, arglist); //null is valid because of static method
// get the open method
partypes = new Class[1];
partypes[0] = Integer.TYPE;
Method openMethod = oracleClobClass.getDeclaredMethod("open", partypes);
// prepare to call the method
Field modeReadWriteField = oracleClobClass.getField("MODE_READWRITE");
arglist = new Object[1];
arglist[0] = modeReadWriteField.get(null); //null is valid because of static field
// call open(CLOB.MODE_READWRITE);
openMethod.invoke(tempClob, arglist);
// get the getCharacterOutputStream method
Method getCharacterOutputStreamMethod = oracleClobClass.getDeclaredMethod("getCharacterOutputStream", null);
// call the getCharacterOutpitStream method
Writer tempClobWriter = (Writer) getCharacterOutputStreamMethod.invoke(tempClob, null);
// write the string to the clob
tempClobWriter.write((String) value);
tempClobWriter.flush();
tempClobWriter.close();
// get the close method
Method closeMethod = oracleClobClass.getDeclaredMethod("close", null);
// call the close method
closeMethod.invoke(tempClob, null);
// add the clob to the statement
st.setClob(index, (Clob) tempClob);
} catch (ClassNotFoundException e) {
// could not find the class with reflection
throw new HibernateException("Unable to find a required class.\n" + e.getMessage());
} catch (NoSuchMethodException e) {
// could not find the metho with reflection
throw new HibernateException("Unable to find a required method.\n" + e.getMessage());
} catch (NoSuchFieldException e) {
// could not find the field with reflection
throw new HibernateException("Unable to find a required field.\n" + e.getMessage());
} catch (IllegalAccessException e) {
throw new HibernateException("Unable to access a required method or field.\n" + e.getMessage());
} catch (InvocationTargetException e) {
throw new HibernateException(e.getMessage());
} catch (IOException e) {
throw new HibernateException(e.getMessage());
}
} else {
throw new HibernateException("No CLOBS support. Use driver version " + ORACLE_DRIVER_MAJOR_VERSION +
", minor " + ORACLE_DRIVER_MINOR_VERSION);
}
} else {
String str = (String) value;
StringReader r = new StringReader(str);
st.setCharacterStream(index, r, str.length());
}
}
public int sqlType() {
return Types.CLOB;
}
public Class getReturnedClass() {
return String.class;
}
public String getName() {
return "string";
}
public boolean hasNiceEquals() {
return false;
}
public boolean equals(Object x, Object y) {
return ObjectUtils.equals(x, y);
}
public String toXML(Object value) {
return (String) value;
}
}