From bbfd960bc896344e8bfbca8e5a7697aa73a606aa Mon Sep 17 00:00:00 2001 From: Brett Meyer Date: Thu, 14 Feb 2013 16:53:37 -0500 Subject: [PATCH] HHH-7889 Cleanup inconsistencies in Blob, Clob, and NClob type descriptors --- .../descriptor/java/ClobTypeDescriptor.java | 55 ++++--- .../descriptor/java/NClobTypeDescriptor.java | 51 ++++--- .../descriptor/sql/BlobTypeDescriptor.java | 14 +- .../descriptor/sql/ClobTypeDescriptor.java | 82 +++++++---- .../descriptor/sql/NClobTypeDescriptor.java | 138 +++++++++++++----- 5 files changed, 229 insertions(+), 111 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/ClobTypeDescriptor.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/ClobTypeDescriptor.java index 97a46c4e91..486a729a1b 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/ClobTypeDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/ClobTypeDescriptor.java @@ -23,14 +23,19 @@ */ package org.hibernate.type.descriptor.java; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; import java.io.Serializable; import java.sql.Clob; +import java.sql.SQLException; import java.util.Comparator; +import org.hibernate.HibernateException; +import org.hibernate.engine.jdbc.CharacterStream; import org.hibernate.engine.jdbc.ClobImplementer; import org.hibernate.engine.jdbc.ClobProxy; import org.hibernate.engine.jdbc.WrappedClob; -import org.hibernate.engine.jdbc.CharacterStream; import org.hibernate.engine.jdbc.internal.CharacterStreamImpl; import org.hibernate.type.descriptor.WrapperOptions; @@ -95,29 +100,33 @@ public class ClobTypeDescriptor extends AbstractTypeDescriptor { @SuppressWarnings({ "unchecked" }) public X unwrap(final Clob value, Class type, WrapperOptions options) { - if ( ! ( Clob.class.isAssignableFrom( type ) || CharacterStream.class.isAssignableFrom( type ) ) ) { - throw unknownUnwrap( type ); - } - if ( value == null ) { return null; } - if ( CharacterStream.class.isAssignableFrom( type ) ) { - if ( ClobImplementer.class.isInstance( value ) ) { - // if the incoming Clob is a wrapper, just pass along its CharacterStream - return (X) ( (ClobImplementer) value ).getUnderlyingStream(); + try { + if ( CharacterStream.class.isAssignableFrom( type ) ) { + if ( ClobImplementer.class.isInstance( value ) ) { + // if the incoming Clob is a wrapper, just pass along its BinaryStream + return (X) ( (ClobImplementer) value ).getUnderlyingStream(); + } + else { + // otherwise we need to build a BinaryStream... + return (X) new CharacterStreamImpl( DataHelper.extractString( value.getCharacterStream() ) ); + } } - else { - // otherwise we need to build one... - return (X) new CharacterStreamImpl( DataHelper.extractString( value ) ); + else if (Clob.class.isAssignableFrom( type )) { + final Clob clob = WrappedClob.class.isInstance( value ) + ? ( (WrappedClob) value ).getWrappedClob() + : value; + return (X) clob; } } - - final Clob clob = WrappedClob.class.isInstance( value ) - ? ( (WrappedClob) value ).getWrappedClob() - : value; - return (X) clob; + catch ( SQLException e ) { + throw new HibernateException( "Unable to access clob stream", e ); + } + + throw unknownUnwrap( type ); } public Clob wrap(X value, WrapperOptions options) { @@ -125,10 +134,16 @@ public class ClobTypeDescriptor extends AbstractTypeDescriptor { return null; } - if ( ! Clob.class.isAssignableFrom( value.getClass() ) ) { - throw unknownWrap( value.getClass() ); + // Support multiple return types from + // org.hibernate.type.descriptor.sql.ClobTypeDescriptor + if ( Clob.class.isAssignableFrom( value.getClass() ) ) { + return options.getLobCreator().wrap( (Clob) value ); + } + else if ( Reader.class.isAssignableFrom( value.getClass() ) ) { + Reader reader = (Reader) value; + return options.getLobCreator().createClob( DataHelper.extractString( reader ) ); } - return options.getLobCreator().wrap( (Clob) value ); + throw unknownWrap( value.getClass() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/NClobTypeDescriptor.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/NClobTypeDescriptor.java index f1a9fcd283..2e587e9c9a 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/NClobTypeDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/NClobTypeDescriptor.java @@ -23,10 +23,13 @@ */ package org.hibernate.type.descriptor.java; +import java.io.Reader; import java.io.Serializable; import java.sql.NClob; +import java.sql.SQLException; import java.util.Comparator; +import org.hibernate.HibernateException; import org.hibernate.engine.jdbc.CharacterStream; import org.hibernate.engine.jdbc.NClobImplementer; import org.hibernate.engine.jdbc.NClobProxy; @@ -95,29 +98,33 @@ public class NClobTypeDescriptor extends AbstractTypeDescriptor { @SuppressWarnings({ "unchecked" }) public X unwrap(final NClob value, Class type, WrapperOptions options) { - if ( ! ( NClob.class.isAssignableFrom( type ) || CharacterStream.class.isAssignableFrom( type ) ) ) { - throw unknownUnwrap( type ); - } - if ( value == null ) { return null; } - if ( CharacterStream.class.isAssignableFrom( type ) ) { - if ( NClobImplementer.class.isInstance( value ) ) { - // if the incoming Clob is a wrapper, just pass along its CharacterStream - return (X) ( (NClobImplementer) value ).getUnderlyingStream(); + try { + if ( CharacterStream.class.isAssignableFrom( type ) ) { + if ( NClobImplementer.class.isInstance( value ) ) { + // if the incoming NClob is a wrapper, just pass along its BinaryStream + return (X) ( (NClobImplementer) value ).getUnderlyingStream(); + } + else { + // otherwise we need to build a BinaryStream... + return (X) new CharacterStreamImpl( DataHelper.extractString( value.getCharacterStream() ) ); + } } - else { - // otherwise we need to build one... - return (X) new CharacterStreamImpl( DataHelper.extractString( value ) ); + else if (NClob.class.isAssignableFrom( type )) { + final NClob nclob = WrappedNClob.class.isInstance( value ) + ? ( (WrappedNClob) value ).getWrappedNClob() + : value; + return (X) nclob; } } - - final NClob clob = WrappedNClob.class.isInstance( value ) - ? ( (WrappedNClob) value ).getWrappedNClob() - : value; - return (X) clob; + catch ( SQLException e ) { + throw new HibernateException( "Unable to access nclob stream", e ); + } + + throw unknownUnwrap( type ); } public NClob wrap(X value, WrapperOptions options) { @@ -125,10 +132,16 @@ public class NClobTypeDescriptor extends AbstractTypeDescriptor { return null; } - if ( ! NClob.class.isAssignableFrom( value.getClass() ) ) { - throw unknownWrap( value.getClass() ); + // Support multiple return types from + // org.hibernate.type.descriptor.sql.ClobTypeDescriptor + if ( NClob.class.isAssignableFrom( value.getClass() ) ) { + return options.getLobCreator().wrap( (NClob) value ); + } + else if ( Reader.class.isAssignableFrom( value.getClass() ) ) { + Reader reader = (Reader) value; + return options.getLobCreator().createNClob( DataHelper.extractString( reader ) ); } - return options.getLobCreator().wrap( (NClob) value ); + throw unknownWrap( value.getClass() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/BlobTypeDescriptor.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/BlobTypeDescriptor.java index 23b38ad56f..ae804f568b 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/BlobTypeDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/BlobTypeDescriptor.java @@ -96,27 +96,27 @@ public abstract class BlobTypeDescriptor implements SqlTypeDescriptor { @Override public BasicExtractor getBlobExtractor(final JavaTypeDescriptor javaTypeDescriptor) { return new BasicExtractor( javaTypeDescriptor, this ) { - // For now, default to using getBlob. If extraction - // should also check useStreamForLobBinding, add - // checks here and use STREAM_BINDING. - @Override protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { - return BLOB_BINDING.getExtractor( javaTypeDescriptor ).doExtract( rs, name, options ); + return getBinding( options ).getExtractor( javaTypeDescriptor ).doExtract( rs, name, options ); } @Override protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { - return BLOB_BINDING.getExtractor( javaTypeDescriptor ).doExtract( statement, index, options ); + return getBinding( options ).getExtractor( javaTypeDescriptor ).doExtract( statement, index, options ); } @Override protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException { - return BLOB_BINDING.getExtractor( javaTypeDescriptor ).doExtract( statement, name, options ); + return getBinding( options ).getExtractor( javaTypeDescriptor ).doExtract( statement, name, options ); } }; } }; + + private static final BlobTypeDescriptor getBinding( WrapperOptions options ) { + return options.useStreamForLobBinding() ? STREAM_BINDING : BLOB_BINDING; + } public static final BlobTypeDescriptor PRIMITIVE_ARRAY_BINDING = new BlobTypeDescriptor() { diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/ClobTypeDescriptor.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/ClobTypeDescriptor.java index 2b54104018..aac063ee77 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/ClobTypeDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/ClobTypeDescriptor.java @@ -52,6 +52,20 @@ public abstract class ClobTypeDescriptor implements SqlTypeDescriptor { public boolean canBeRemapped() { return true; } + + protected abstract BasicExtractor getClobExtractor(JavaTypeDescriptor javaTypeDescriptor); + + @Override + public ValueExtractor getExtractor(JavaTypeDescriptor javaTypeDescriptor) { + return getClobExtractor( javaTypeDescriptor ); + } + + protected abstract BasicBinder getClobBinder(JavaTypeDescriptor javaTypeDescriptor); + + @Override + public ValueBinder getBinder(JavaTypeDescriptor javaTypeDescriptor) { + return getClobBinder( javaTypeDescriptor ); + } public static final ClobTypeDescriptor DEFAULT = @@ -65,12 +79,7 @@ public abstract class ClobTypeDescriptor implements SqlTypeDescriptor { return new BasicBinder( javaTypeDescriptor, this ) { @Override protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException { - if ( options.useStreamForLobBinding() ) { - STREAM_BINDING.getClobBinder( javaTypeDescriptor ).doBind( st, value, index, options ); - } - else { - CLOB_BINDING.getClobBinder( javaTypeDescriptor ).doBind( st, value, index, options ); - } + getBinding( options ).getClobBinder( javaTypeDescriptor ).doBind( st, value, index, options ); } }; } @@ -80,16 +89,27 @@ public abstract class ClobTypeDescriptor implements SqlTypeDescriptor { return new BasicExtractor( javaTypeDescriptor, this ) { @Override protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { - if ( options.useStreamForLobBinding() ) { - return STREAM_BINDING.getClobExtractor( javaTypeDescriptor ).doExtract( rs, name, options ); - } - else { - return CLOB_BINDING.getClobExtractor( javaTypeDescriptor ).doExtract( rs, name, options ); - } + return getBinding( options ).getClobExtractor( javaTypeDescriptor ).doExtract( rs, name, options ); } + + @Override + protected X doExtract(CallableStatement statement, int index, WrapperOptions options) + throws SQLException { + return getBinding( options ).getClobExtractor( javaTypeDescriptor ).doExtract( statement, index, options ); + } + + @Override + protected X doExtract(CallableStatement statement, String name, WrapperOptions options) + throws SQLException { + return getBinding( options ).getClobExtractor( javaTypeDescriptor ).doExtract( statement, name, options ); + } }; } }; + + private static final ClobTypeDescriptor getBinding( WrapperOptions options ) { + return options.useStreamForLobBinding() ? STREAM_BINDING : CLOB_BINDING; + } public static final ClobTypeDescriptor CLOB_BINDING = new ClobTypeDescriptor() { @@ -112,6 +132,18 @@ public abstract class ClobTypeDescriptor implements SqlTypeDescriptor { protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { return javaTypeDescriptor.wrap( rs.getClob( name ), options ); } + + @Override + protected X doExtract(CallableStatement statement, int index, WrapperOptions options) + throws SQLException { + return javaTypeDescriptor.wrap( statement.getClob( index ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, String name, WrapperOptions options) + throws SQLException { + return javaTypeDescriptor.wrap( statement.getClob( name ), options ); + } }; }; @@ -139,23 +171,21 @@ public abstract class ClobTypeDescriptor implements SqlTypeDescriptor { protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { return javaTypeDescriptor.wrap( rs.getCharacterStream( name ), options ); } + + @Override + protected X doExtract(CallableStatement statement, int index, WrapperOptions options) + throws SQLException { + return javaTypeDescriptor.wrap( statement.getCharacterStream( index ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, String name, WrapperOptions options) + throws SQLException { + return javaTypeDescriptor.wrap( statement.getCharacterStream( name ), options ); + } }; }; }; - protected abstract BasicBinder getClobBinder(JavaTypeDescriptor javaTypeDescriptor); - - protected abstract BasicExtractor getClobExtractor(JavaTypeDescriptor javaTypeDescriptor); - - @Override - public ValueBinder getBinder(JavaTypeDescriptor javaTypeDescriptor) { - return getClobBinder( javaTypeDescriptor ); - } - - @Override - public ValueExtractor getExtractor(JavaTypeDescriptor javaTypeDescriptor) { - return getClobExtractor( javaTypeDescriptor ); - } - } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/NClobTypeDescriptor.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/NClobTypeDescriptor.java index 588e0fc80b..c1c690c6cf 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/NClobTypeDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/NClobTypeDescriptor.java @@ -52,58 +52,69 @@ public abstract class NClobTypeDescriptor implements SqlTypeDescriptor { public boolean canBeRemapped() { return true; } + + protected abstract BasicExtractor getNClobExtractor(JavaTypeDescriptor javaTypeDescriptor); + + @Override + public ValueExtractor getExtractor(JavaTypeDescriptor javaTypeDescriptor) { + return getNClobExtractor( javaTypeDescriptor ); + } + + protected abstract BasicBinder getNClobBinder(JavaTypeDescriptor javaTypeDescriptor); @Override - public ValueExtractor getExtractor(final JavaTypeDescriptor javaTypeDescriptor) { - return new BasicExtractor( javaTypeDescriptor, this ) { - @Override - protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { - return javaTypeDescriptor.wrap( rs.getNClob( name ), options ); - } - - @Override - protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { - return javaTypeDescriptor.wrap( statement.getNClob( index ), options ); - } - - @Override - protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException { - return javaTypeDescriptor.wrap( statement.getNClob( name ), options ); - } - }; + public ValueBinder getBinder(JavaTypeDescriptor javaTypeDescriptor) { + return getNClobBinder( javaTypeDescriptor ); } - protected abstract BasicBinder getClobBinder(final JavaTypeDescriptor javaTypeDescriptor); - - public ValueBinder getBinder(final JavaTypeDescriptor javaTypeDescriptor) { - return getClobBinder( javaTypeDescriptor ); - } - - public static final ClobTypeDescriptor DEFAULT = - new ClobTypeDescriptor() { + public static final NClobTypeDescriptor DEFAULT = + new NClobTypeDescriptor() { { SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( this ); } - public BasicBinder getClobBinder(final JavaTypeDescriptor javaTypeDescriptor) { + @Override + public BasicBinder getNClobBinder(final JavaTypeDescriptor javaTypeDescriptor) { return new BasicBinder( javaTypeDescriptor, this ) { @Override protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException { - if ( options.useStreamForLobBinding() ) { - STREAM_BINDING.getClobBinder( javaTypeDescriptor ).doBind( st, value, index, options ); - } - else { - CLOB_BINDING.getClobBinder( javaTypeDescriptor ).doBind( st, value, index, options ); - } + getBinding( options ).getNClobBinder( javaTypeDescriptor ).doBind( st, value, index, options ); } }; } - }; + + @Override + public BasicExtractor getNClobExtractor(final JavaTypeDescriptor javaTypeDescriptor) { + return new BasicExtractor( javaTypeDescriptor, this ) { + @Override + protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { + return getBinding( options ).getNClobExtractor( javaTypeDescriptor ).doExtract( rs, name, options ); + } - public static final ClobTypeDescriptor CLOB_BINDING = - new ClobTypeDescriptor() { - public BasicBinder getClobBinder(final JavaTypeDescriptor javaTypeDescriptor) { + @Override + protected X doExtract(CallableStatement statement, int index, WrapperOptions options) + throws SQLException { + return getBinding( options ).getNClobExtractor( javaTypeDescriptor ).doExtract( statement, index, options ); + } + + @Override + protected X doExtract(CallableStatement statement, String name, WrapperOptions options) + throws SQLException { + return getBinding( options ).getNClobExtractor( javaTypeDescriptor ).doExtract( statement, name, options ); + } + }; + } + }; + + private static final NClobTypeDescriptor getBinding( WrapperOptions options ) { + return options.useStreamForLobBinding() ? STREAM_BINDING : NCLOB_BINDING; + } + + public static final NClobTypeDescriptor NCLOB_BINDING = + new NClobTypeDescriptor() { + @Override + public BasicBinder getNClobBinder(final JavaTypeDescriptor javaTypeDescriptor) { return new BasicBinder( javaTypeDescriptor, this ) { @Override protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) @@ -112,11 +123,36 @@ public abstract class NClobTypeDescriptor implements SqlTypeDescriptor { } }; } + + @Override + public BasicExtractor getNClobExtractor(final JavaTypeDescriptor javaTypeDescriptor) { + return new BasicExtractor(javaTypeDescriptor, this) { + + @Override + protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { + return javaTypeDescriptor.wrap( rs.getNClob( name ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, int index, WrapperOptions options) + throws SQLException { + return javaTypeDescriptor.wrap( statement.getNClob( index ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, String name, WrapperOptions options) + throws SQLException { + return javaTypeDescriptor.wrap( statement.getNClob( name ), options ); + } + + }; + }; }; - public static final ClobTypeDescriptor STREAM_BINDING = - new ClobTypeDescriptor() { - public BasicBinder getClobBinder(final JavaTypeDescriptor javaTypeDescriptor) { + public static final NClobTypeDescriptor STREAM_BINDING = + new NClobTypeDescriptor() { + @Override + public BasicBinder getNClobBinder(final JavaTypeDescriptor javaTypeDescriptor) { return new BasicBinder( javaTypeDescriptor, this ) { @Override protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) @@ -126,5 +162,29 @@ public abstract class NClobTypeDescriptor implements SqlTypeDescriptor { } }; } + + @Override + public BasicExtractor getNClobExtractor(final JavaTypeDescriptor javaTypeDescriptor) { + return new BasicExtractor(javaTypeDescriptor, this) { + + @Override + protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { + return javaTypeDescriptor.wrap( rs.getCharacterStream( name ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, int index, WrapperOptions options) + throws SQLException { + return javaTypeDescriptor.wrap( statement.getCharacterStream( index ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, String name, WrapperOptions options) + throws SQLException { + return javaTypeDescriptor.wrap( statement.getCharacterStream( name ), options ); + } + + }; + }; }; }