From: <hib...@li...> - 2006-06-10 03:24:14
|
Author: epbernard Date: 2006-06-09 23:24:05 -0400 (Fri, 09 Jun 2006) New Revision: 10009 Added: trunk/Hibernate3/src/org/hibernate/type/AbstractBynaryType.java trunk/Hibernate3/src/org/hibernate/type/AbstractCharArrayType.java trunk/Hibernate3/src/org/hibernate/type/CharArrayType.java trunk/Hibernate3/src/org/hibernate/type/CharacterArrayType.java trunk/Hibernate3/src/org/hibernate/type/WrapperBinaryType.java Modified: trunk/Hibernate3/etc/log4j.properties trunk/Hibernate3/src/org/hibernate/Hibernate.java trunk/Hibernate3/src/org/hibernate/type/BinaryType.java trunk/Hibernate3/src/org/hibernate/type/TypeFactory.java Log: HHH-1826 built in support for Byte[] Character[] char[] Modified: trunk/Hibernate3/etc/log4j.properties =================================================================== --- trunk/Hibernate3/etc/log4j.properties 2006-06-09 17:46:51 UTC (rev 10008) +++ trunk/Hibernate3/etc/log4j.properties 2006-06-10 03:24:05 UTC (rev 10009) @@ -14,8 +14,8 @@ log4j.rootLogger=warn, stdout -log4j.logger.org.hibernate=info -#log4j.logger.org.hibernate=debug +#log4j.logger.org.hibernate=info +log4j.logger.org.hibernate=debug ### log HQL query parser activity #log4j.logger.org.hibernate.hql.ast.AST=debug Modified: trunk/Hibernate3/src/org/hibernate/Hibernate.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/Hibernate.java 2006-06-09 17:46:51 UTC (rev 10008) +++ trunk/Hibernate3/src/org/hibernate/Hibernate.java 2006-06-10 03:24:05 UTC (rev 10009) @@ -53,6 +53,9 @@ import org.hibernate.type.TrueFalseType; import org.hibernate.type.Type; import org.hibernate.type.YesNoType; +import org.hibernate.type.CharArrayType; +import org.hibernate.type.WrapperBinaryType; +import org.hibernate.type.CharacterArrayType; import org.hibernate.usertype.CompositeUserType; /** @@ -140,6 +143,18 @@ */ public static final NullableType BINARY = new BinaryType(); /** + * Hibernate <tt>wrapper-binary</tt> type. + */ + public static final NullableType WRAPPER_BINARY = new WrapperBinaryType(); + /** + * Hibernate char[] type. + */ + public static final NullableType CHAR_ARRAY = new CharArrayType(); + /** + * Hibernate Character[] type. + */ + public static final NullableType CHARACTER_ARRAY = new CharacterArrayType(); + /** * Hibernate <tt>text</tt> type. */ public static final NullableType TEXT = new TextType(); Added: trunk/Hibernate3/src/org/hibernate/type/AbstractBynaryType.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/type/AbstractBynaryType.java 2006-06-09 17:46:51 UTC (rev 10008) +++ trunk/Hibernate3/src/org/hibernate/type/AbstractBynaryType.java 2006-06-10 03:24:05 UTC (rev 10009) @@ -0,0 +1,166 @@ +//$Id: $ +package org.hibernate.type; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.ResultSet; +import java.sql.Types; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Comparator; + +import org.hibernate.HibernateException; +import org.hibernate.EntityMode; +import org.hibernate.engine.SessionImplementor; +import org.hibernate.cfg.Environment; + +/** + * Logic to bind stream of byte into a VARBINARY + * + * @author Gavin King + * @author Emmanuel Bernard + */ +public abstract class AbstractBynaryType extends MutableType implements VersionType, Comparator { + + /** + * Convert the byte[] into the expected object type + */ + abstract protected Object toExternalFormat(byte[] bytes); + + /** + * Convert the object into the internal byte[] representation + */ + abstract protected byte[] toInternalFormat(Object bytes); + + public void set(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { + byte[] internalValue = toInternalFormat( value ); + if ( Environment.useStreamsForBinary() ) { + st.setBinaryStream( index, new ByteArrayInputStream( internalValue ), internalValue.length ); + } + else { + st.setBytes( index, internalValue ); + } + } + + public Object get(ResultSet rs, String name) throws HibernateException, SQLException { + + if ( Environment.useStreamsForBinary() ) { + + InputStream inputStream = rs.getBinaryStream(name); + + if (inputStream==null) return toExternalFormat( null ); // is this really necessary? + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(2048); + byte[] buffer = new byte[2048]; + + try { + while (true) { + int amountRead = inputStream.read(buffer); + if (amountRead == -1) { + break; + } + outputStream.write(buffer, 0, amountRead); + } + + inputStream.close(); + outputStream.close(); + } + catch (IOException ioe) { + throw new HibernateException( "IOException occurred reading a binary value", ioe ); + } + + return toExternalFormat( outputStream.toByteArray() ); + + } + else { + return toExternalFormat( rs.getBytes(name) ); + } + } + + public int sqlType() { + return Types.VARBINARY; + } + + // VersionType impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Note : simply returns null for seed() and next() as the only known + // application of binary types for versioning is for use with the + // TIMESTAMP datatype supported by Sybase and SQL Server, which + // are completely db-generated values... + public Object seed(SessionImplementor session) { + return null; + } + + public Object next(Object current, SessionImplementor session) { + return current; + } + + public Comparator getComparator() { + return this; + } + + public int compare(Object o1, Object o2) { + return compare( o1, o2, null ); + } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + public boolean isEqual(Object x, Object y) { + return x==y || ( x!=null && y!=null && java.util.Arrays.equals( toInternalFormat(x), toInternalFormat(y) ) ); + } + + public int getHashCode(Object x, EntityMode entityMode) { + byte[] bytes = toInternalFormat(x); + int hashCode = 1; + for ( int j=0; j<bytes.length; j++ ) { + hashCode = 31 * hashCode + bytes[j]; + } + return hashCode; + } + + public int compare(Object x, Object y, EntityMode entityMode) { + byte[] xbytes = toInternalFormat(x); + byte[] ybytes = toInternalFormat(y); + if ( xbytes.length < ybytes.length ) return -1; + if ( xbytes.length > ybytes.length ) return 1; + for ( int i=0; i<xbytes.length; i++ ) { + if ( xbytes[i] < ybytes[i] ) return -1; + if ( xbytes[i] > ybytes[i] ) return 1; + } + return 0; + } + + public abstract String getName(); + + public String toString(Object val) { + byte[] bytes = toInternalFormat(val); + StringBuffer buf = new StringBuffer(); + for ( int i=0; i<bytes.length; i++ ) { + String hexStr = Integer.toHexString( bytes[i] - Byte.MIN_VALUE ); + if ( hexStr.length()==1 ) buf.append('0'); + buf.append(hexStr); + } + return buf.toString(); + } + + public Object deepCopyNotNull(Object value) { + byte[] bytes = toInternalFormat(value); + byte[] result = new byte[bytes.length]; + System.arraycopy(bytes, 0, result, 0, bytes.length); + return toExternalFormat(result); + } + + public Object fromStringValue(String xml) throws HibernateException { + if (xml == null) + return null; + if (xml.length() % 2 != 0) + throw new IllegalArgumentException("The string is not a valid xml representation of a binary content."); + byte[] bytes = new byte[xml.length() / 2]; + for (int i = 0; i < bytes.length; i++) { + String hexStr = xml.substring(i * 2, (i + 1) * 2); + bytes[i] = (byte) (Integer.parseInt(hexStr, 16) + Byte.MIN_VALUE); + } + return toExternalFormat(bytes); + } + +} Added: trunk/Hibernate3/src/org/hibernate/type/AbstractCharArrayType.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/type/AbstractCharArrayType.java 2006-06-09 17:46:51 UTC (rev 10008) +++ trunk/Hibernate3/src/org/hibernate/type/AbstractCharArrayType.java 2006-06-10 03:24:05 UTC (rev 10009) @@ -0,0 +1,96 @@ +//$Id: $ +package org.hibernate.type; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.PreparedStatement; +import java.sql.Types; +import java.io.Reader; +import java.io.CharArrayWriter; +import java.io.IOException; +import java.io.CharArrayReader; + +import org.hibernate.HibernateException; +import org.hibernate.dialect.Dialect; + +/** + * Logic to bind stream of char into a VARCHAR + * + * @author Emmanuel Bernard + */ +public abstract class AbstractCharArrayType extends MutableType { + + /** + * Convert the char[] into the expected object type + */ + abstract protected Object toExternalFormat(char[] chars); + + /** + * Convert the object into the internal char[] representation + */ + abstract protected char[] toInternalFormat(Object chars); + + public Object get(ResultSet rs, String name) throws SQLException { + Reader stream = rs.getCharacterStream(name); + if ( stream == null ) return toExternalFormat( null ); + CharArrayWriter writer = new CharArrayWriter(); + for(;;) { + try { + int c = stream.read(); + if ( c == -1) return toExternalFormat( writer.toCharArray() ); + writer.write( c ); + } + catch (IOException e) { + throw new HibernateException("Unable to read character stream from rs"); + } + } + } + + public abstract Class getReturnedClass(); + + public void set(PreparedStatement st, Object value, int index) throws SQLException { + char[] chars = toInternalFormat( value ); + st.setCharacterStream(index, new CharArrayReader(chars), chars.length); + } + + public int sqlType() { + return Types.VARCHAR; + } + + public String objectToSQLString(Object value, Dialect dialect) throws Exception { + + return '\'' + new String( toInternalFormat( value ) ) + '\''; + } + + public Object stringToObject(String xml) throws Exception { + if (xml == null) return toExternalFormat( null ); + int length = xml.length(); + char[] chars = new char[length]; + for (int index = 0 ; index < length ; index++ ) { + chars[index] = xml.charAt( index ); + } + return toExternalFormat( chars ); + } + + public String toString(Object value) { + if (value == null) return null; + return new String( toInternalFormat( value ) ); + } + + public Object fromStringValue(String xml) { + if (xml == null) return null; + int length = xml.length(); + char[] chars = new char[length]; + for (int index = 0 ; index < length ; index++ ) { + chars[index] = xml.charAt( index ); + } + return toExternalFormat( chars ); + } + + protected Object deepCopyNotNull(Object value) throws HibernateException { + char[] chars = toInternalFormat(value); + char[] result = new char[chars.length]; + System.arraycopy(chars, 0, result, 0, chars.length); + return toExternalFormat(result); + } +} Modified: trunk/Hibernate3/src/org/hibernate/type/BinaryType.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/type/BinaryType.java 2006-06-09 17:46:51 UTC (rev 10008) +++ trunk/Hibernate3/src/org/hibernate/type/BinaryType.java 2006-06-10 03:24:05 UTC (rev 10009) @@ -1,157 +1,24 @@ //$Id$ package org.hibernate.type; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Types; -import java.util.Comparator; - -import org.hibernate.EntityMode; -import org.hibernate.HibernateException; -import org.hibernate.engine.SessionImplementor; -import org.hibernate.cfg.Environment; - /** * <tt>binary</tt>: A type that maps an SQL VARBINARY to a Java byte[]. * @author Gavin King */ -public class BinaryType extends MutableType implements VersionType, Comparator { +public class BinaryType extends AbstractBynaryType { - public void set(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { - - if ( Environment.useStreamsForBinary() ) { - st.setBinaryStream( index, new ByteArrayInputStream( (byte[]) value ), ( (byte[]) value ).length ); - } - else { - st.setBytes( index, (byte[]) value ); - } + protected Object toExternalFormat(byte[] bytes) { + return bytes; } - public Object get(ResultSet rs, String name) throws HibernateException, SQLException { - - if ( Environment.useStreamsForBinary() ) { - - InputStream inputStream = rs.getBinaryStream(name); - - if (inputStream==null) return null; // is this really necessary? - - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(2048); - byte[] buffer = new byte[2048]; - - try { - while (true) { - int amountRead = inputStream.read(buffer); - if (amountRead == -1) { - break; - } - outputStream.write(buffer, 0, amountRead); - } - - inputStream.close(); - outputStream.close(); - } - catch (IOException ioe) { - throw new HibernateException( "IOException occurred reading a binary value", ioe ); - } - - return outputStream.toByteArray(); - - } - else { - return rs.getBytes(name); - } + protected byte[] toInternalFormat(Object bytes) { + return (byte[]) bytes; } - public int sqlType() { - return Types.VARBINARY; - } - public Class getReturnedClass() { return byte[].class; } - // VersionType impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // Note : simply returns null for seed() and next() as the only known - // application of binary types for versioning is for use with the - // TIMESTAMP datatype supported by Sybase and SQL Server, which - // are completely db-generated values... - public Object seed(SessionImplementor session) { - return null; - } - - public Object next(Object current, SessionImplementor session) { - return current; - } - - public Comparator getComparator() { - return this; - } - - public int compare(Object o1, Object o2) { - return compare( o1, o2, null ); - } - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - public boolean isEqual(Object x, Object y) { - return x==y || ( x!=null && y!=null && java.util.Arrays.equals( (byte[]) x, (byte[]) y ) ); - } - - public int getHashCode(Object x, EntityMode entityMode) { - byte[] bytes = (byte[]) x; - int hashCode = 1; - for ( int j=0; j<bytes.length; j++ ) { - hashCode = 31 * hashCode + bytes[j]; - } - return hashCode; - } - - public int compare(Object x, Object y, EntityMode entityMode) { - byte[] xbytes = (byte[]) x; - byte[] ybytes = (byte[]) y; - if ( xbytes.length < ybytes.length ) return -1; - if ( xbytes.length > ybytes.length ) return 1; - for ( int i=0; i<xbytes.length; i++ ) { - if ( xbytes[i] < ybytes[i] ) return -1; - if ( xbytes[i] > ybytes[i] ) return 1; - } - return 0; - } - public String getName() { return "binary"; } - public String toString(Object val) { - byte[] bytes = ( byte[] ) val; - StringBuffer buf = new StringBuffer(); - for ( int i=0; i<bytes.length; i++ ) { - String hexStr = Integer.toHexString( bytes[i] - Byte.MIN_VALUE ); - if ( hexStr.length()==1 ) buf.append('0'); - buf.append(hexStr); - } - return buf.toString(); - } - - public Object deepCopyNotNull(Object value) { - byte[] bytes = (byte[]) value; - byte[] result = new byte[bytes.length]; - System.arraycopy(bytes, 0, result, 0, bytes.length); - return result; - } - - public Object fromStringValue(String xml) throws HibernateException { - if (xml == null) - return null; - if (xml.length() % 2 != 0) - throw new IllegalArgumentException("The string is not a valid xml representation of a binary content."); - byte[] bytes = new byte[xml.length() / 2]; - for (int i = 0; i < bytes.length; i++) { - String hexStr = xml.substring(i * 2, (i + 1) * 2); - bytes[i] = (byte) (Integer.parseInt(hexStr, 16) + Byte.MIN_VALUE); - } - return bytes; - } } Added: trunk/Hibernate3/src/org/hibernate/type/CharArrayType.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/type/CharArrayType.java 2006-06-09 17:46:51 UTC (rev 10008) +++ trunk/Hibernate3/src/org/hibernate/type/CharArrayType.java 2006-06-10 03:24:05 UTC (rev 10009) @@ -0,0 +1,23 @@ +//$Id: $ +package org.hibernate.type; + +/** + * put char[] into VARCHAR + * @author Emmanuel Bernard + */ +public class CharArrayType extends AbstractCharArrayType { + + protected Object toExternalFormat(char[] chars) { + return chars; + } + + protected char[] toInternalFormat(Object chars) { + return (char[]) chars; + } + + public Class getReturnedClass() { + return char[].class; + } + + public String getName() { return "characters"; } +} Added: trunk/Hibernate3/src/org/hibernate/type/CharacterArrayType.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/type/CharacterArrayType.java 2006-06-09 17:46:51 UTC (rev 10008) +++ trunk/Hibernate3/src/org/hibernate/type/CharacterArrayType.java 2006-06-10 03:24:05 UTC (rev 10009) @@ -0,0 +1,37 @@ +//$Id: $ +package org.hibernate.type; + +import org.hibernate.HibernateException; + +/** + * Bridge Character[] and VARCHAR + * @author Emmanuel Bernard + */ +public class CharacterArrayType extends AbstractCharArrayType { + protected Object toExternalFormat(char[] chars) { + if (chars == null) return null; + Character[] characters = new Character[chars.length]; + for (int i = 0 ; i < chars.length ; i++) { + characters[i] = new Character( chars[i] ); + } + return characters; + } + + protected char[] toInternalFormat(Object value) { + if (value == null) return null; + Character[] characters = (Character[]) value; + char[] chars = new char[characters.length]; + for (int i = 0 ; i < characters.length ; i++) { + if (characters[i] == null) + throw new HibernateException("Unable to store an Character[] when one of its element is null"); + chars[i] = characters[i].charValue(); + } + return chars; + } + + public Class getReturnedClass() { + return Character[].class; + } + + public String getName() { return "wrapper-characters"; } +} Modified: trunk/Hibernate3/src/org/hibernate/type/TypeFactory.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/type/TypeFactory.java 2006-06-09 17:46:51 UTC (rev 10008) +++ trunk/Hibernate3/src/org/hibernate/type/TypeFactory.java 2006-06-10 03:24:05 UTC (rev 10009) @@ -101,6 +101,12 @@ basics.put( Class.class.getName(), Hibernate.CLASS ); basics.put( byte[].class.getName(), Hibernate.BINARY ); basics.put( "byte[]", Hibernate.BINARY ); + basics.put( Byte[].class.getName(), Hibernate.WRAPPER_BINARY ); + basics.put( "Byte[]", Hibernate.WRAPPER_BINARY ); + basics.put( char[].class.getName(), Hibernate.CHAR_ARRAY ); + basics.put( "char[]", Hibernate.CHAR_ARRAY ); + basics.put( Character[].class.getName(), Hibernate.CHARACTER_ARRAY ); + basics.put( "Character[]", Hibernate.CHARACTER_ARRAY ); basics.put( Blob.class.getName(), Hibernate.BLOB ); basics.put( Clob.class.getName(), Hibernate.CLOB ); basics.put( Serializable.class.getName(), Hibernate.SERIALIZABLE ); Added: trunk/Hibernate3/src/org/hibernate/type/WrapperBinaryType.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/type/WrapperBinaryType.java 2006-06-09 17:46:51 UTC (rev 10008) +++ trunk/Hibernate3/src/org/hibernate/type/WrapperBinaryType.java 2006-06-10 03:24:05 UTC (rev 10009) @@ -0,0 +1,41 @@ +//$Id: $ +package org.hibernate.type; + +import org.hibernate.HibernateException; + +/** + * @author Emmanuel Bernard + */ +public class WrapperBinaryType extends AbstractBynaryType { + protected Object toExternalFormat(byte[] bytes) { + if (bytes == null) return null; + int length = bytes.length; + Byte[] result = new Byte[length]; + for ( int index = 0; index < length ; index++ ) { + result[index] = new Byte( bytes[index] ); + } + return result; + } + + protected byte[] toInternalFormat(Object val) { + if (val == null) return null; + Byte[] bytes = (Byte[]) val; + int length = bytes.length; + byte[] result = new byte[length]; + for ( int i = 0; i < length ; i++ ) { + if (bytes[i] == null) + throw new HibernateException("Unable to store an Byte[] when one of its element is null"); + result[i] = bytes[i].byteValue(); + } + return result; + } + + public Class getReturnedClass() { + return Byte[].class; + } + + public String getName() { + //TODO find a decent name before documenting + return "wrapper-binary"; + } +} |