Using Hibernate’s ability to create a user defined type to fix clunky Oracle CLOB code

Very helpful post over here explained how to use Hibernate’s UserType to create a custom type to override the behavior of Oracle’s CLOB types.

Because no programmer can leave well enough alone, I tweaked his code, and made the Unicode related fix suggested in the comments there. Here’s the code I’m using, and it works brilliantly on Java + Hibernate + Oracle 11:

package net.bigmarv.hibernate.types;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.Reader;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

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

/**
 * Way of mapping an Oracle CLOB field as user defined type
 * in Hibernate.  Makes it easier to read these fields.
 * Borrowed from this 
 * Blog Entry
 */
public class ClobType implements UserType {
 
    @Override
	public int [] sqlTypes() {
        return new int [] { Types.CLOB };
    }
 
    /**
     * Returns the class that this Clob is converted to.
     */
    @SuppressWarnings( "rawtypes" )
	@Override
	public Class returnedClass() {
        return String.class;
    }
 
    @Override
	public boolean equals( Object left, Object right )
	throws HibernateException {
        if ( left == null || right == null ) {
            return false;
        }
        
        if ( !(left instanceof String) || !(right instanceof String) ) {
            return false;
        }
        
        return ( ( String )left ).equals( right );
    }
 
    @Override
	public int hashCode( Object o )
	throws HibernateException {
        return o.hashCode();
    }
 
    @Override
	public Object nullSafeGet( ResultSet resultSet, String [] names, Object owner )
    throws HibernateException, SQLException {
 
        StringBuilder sb = new StringBuilder();
        try {
            // First we get the stream
            //InputStream is = resultSet.getAsciiStream( names[0] );  // Should be getCharacterStream for unicode
            Reader reader = resultSet.getCharacterStream( names[ 0 ] );
        	char [] buf = new char[ 4096 ];
            int read = -1;
 
            while ( reader != null && ( read = reader.read(buf)) >= 0) {
                sb.append( buf, 0, read );
            }
            if ( reader != null ) {
                reader.close();
            }
            return sb.toString();
        }
        catch ( IOException ioException ) {
            throw new HibernateException( "Unable to read from resultset", ioException );
        }
    }
 
    @Override
	public void nullSafeSet( PreparedStatement pst, Object data, int index )
    throws HibernateException, SQLException {
        data = data == null ? new String() : data;
        String in = (String) data;
 
        byte[] buf = in.getBytes();
        int len = buf.length;
 
        ByteArrayInputStream bais = new ByteArrayInputStream(buf);
 
        pst.setAsciiStream(index, bais, len);
    }
 
    @Override
	public Object deepCopy( Object object )
	throws HibernateException {
    	if ( object == null ) {
    		object = new String();
    	}
        String in = ( String )object;
        int len = in.length();
        char [] buf = new char[ len ];
 
        for ( int i = 0; i < len; i++ ) {
            buf[ i ] = in.charAt( i );
        }
        return new String( buf );
    }
 
    @Override
	public boolean isMutable() {
        return false;
    }
 
    @Override
	public Serializable disassemble( Object arg0 )
	throws HibernateException {
        return ( String )arg0;
    }
 
    @Override
	public Object assemble( Serializable arg0, Object arg1 )
    throws HibernateException {
        return this.deepCopy( arg0 );
    }
 
    @Override
	public Object replace( Object arg0, Object arg1, Object arg2 )
    throws HibernateException {
        return this.deepCopy( arg0 );
    }
}

Once you've created this class and put it in an appropriate package, you'll need to update your .hbm.xml files to use the new type. In my case, I had columns defined as

    <property name="foo" column="foo" type="clob" />

I changed this to

    <property name="foo" column="foo" type="net.bigmarv.hibernate.types.ClobType" />

I then ran

    mvn hibernate:hbm2java

and then recompiled, and I was done. Beautiful stuff!

MYSQL: Cannot delete or update a parent row: a foreign key constraint fails

Kept getting the following error while trying to drop and recreate the schema on my little project’s database:

    ERROR 1217 (23000): Cannot delete or update a parent row: a foreign key constraint fails

When I encountered this before, I ended up dropping the entire database, recreating it, and then restoring the schema. But that seems a bit, well, rude.

Turns out you can temporarily disable foreign key checks:

    SET FOREIGN_KEY_CHECKS=0;

Just be sure to restore them once you’re done messing around:

    SET FOREIGN_KEY_CHECKS=1;

Finder and Hidden Files

In the land of Unix, files prefixed with a period (.) are hidden from view in most situations. When using ls, for instance, they won’t show by default. You can however use the -a parameter to see the hidden files.

OS X’s Finder, however, doesn’t have an option to show hidden files. And sometimes it’s easier to work with some files via a GUI navigation tool like Finder. So what do you do?

Use the defaults command, and issue the following at a command prompt:

    defaults write com.apple.Finder AppleShowAllFiles YES

Because it can make for quite a bit of clutter at times when seeing hidden files isn’t useful, you might want to turn this feature off. To do so, issue the same command with a NO option.

    defaults write com.apple.Finder AppleShowAllFiles YES

Once you’ve executed this command, be sure to restart Finder to have it pick up the change. To restart finder, hold down the option key, and hover over the finder in the dock. You’ll see a menu option to restart Finder.

No grammar constraints (DTD or XML schema) detected for the document

The link below explained what’s going on here. In short, Eclipse is trying to validate XML documents, and in my case, documents that Maven created to do its testing (I think.) To get rid of the warnings, turn off the check for “no grammar specified.”

The steps to disable this check are as follows:

  1. Open Eclipse’s Preferences
  2. Expand the entry “XML”
  3. Expand the sub-entry “XML Files”
  4. Now click on the “Validation” link
  5. Choose “Ignore” from the choice “Indicate when no grammar is specified”
  6. Apply this, then okay.

I learned this by following a link to StackOverflow to here.