HHH-7586 Re-architect Type or TypeFactory dynamic descriptors

This commit is contained in:
brmeyer 2012-09-11 18:29:53 -04:00
parent 7ce07642cb
commit 04ed36bf0a
6 changed files with 141 additions and 106 deletions

View File

@ -39,9 +39,6 @@ import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import org.hibernate.engine.spi.RowSelection;
import org.jboss.logging.Logger;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
@ -62,6 +59,7 @@ import org.hibernate.dialect.lock.SelectLockingStrategy;
import org.hibernate.dialect.pagination.LegacyLimitHandler; import org.hibernate.dialect.pagination.LegacyLimitHandler;
import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.engine.jdbc.LobCreator; import org.hibernate.engine.jdbc.LobCreator;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.exception.spi.ConversionContext; import org.hibernate.exception.spi.ConversionContext;
import org.hibernate.exception.spi.SQLExceptionConversionDelegate; import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
@ -83,9 +81,9 @@ import org.hibernate.sql.CaseFragment;
import org.hibernate.sql.ForUpdateFragment; import org.hibernate.sql.ForUpdateFragment;
import org.hibernate.sql.JoinFragment; import org.hibernate.sql.JoinFragment;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.sql.BlobTypeDescriptor;
import org.hibernate.type.descriptor.sql.ClobTypeDescriptor; import org.hibernate.type.descriptor.sql.ClobTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.jboss.logging.Logger;
/** /**
* Represents a dialect of SQL implemented by a particular RDBMS. * Represents a dialect of SQL implemented by a particular RDBMS.
@ -378,10 +376,6 @@ public abstract class Dialect implements ConversionContext {
protected SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) { protected SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) {
SqlTypeDescriptor descriptor; SqlTypeDescriptor descriptor;
switch ( sqlCode ) { switch ( sqlCode ) {
case Types.BLOB: {
descriptor = useInputStreamToInsertBlob() ? BlobTypeDescriptor.STREAM_BINDING : null;
break;
}
case Types.CLOB: { case Types.CLOB: {
descriptor = useInputStreamToInsertBlob() ? ClobTypeDescriptor.STREAM_BINDING : null; descriptor = useInputStreamToInsertBlob() ? ClobTypeDescriptor.STREAM_BINDING : null;
break; break;

View File

@ -25,6 +25,7 @@ package org.hibernate.dialect;
import java.sql.Types; import java.sql.Types;
import org.hibernate.type.descriptor.sql.BlobTypeDescriptor;
import org.hibernate.type.descriptor.sql.LongVarbinaryTypeDescriptor; import org.hibernate.type.descriptor.sql.LongVarbinaryTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
@ -53,6 +54,6 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
@Override @Override
protected SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) { protected SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) {
return sqlCode == Types.BLOB ? LongVarbinaryTypeDescriptor.INSTANCE : super.getSqlTypeDescriptorOverride( sqlCode ); return sqlCode == Types.BLOB ? BlobTypeDescriptor.PRIMITIVE_ARRAY_BINDING : super.getSqlTypeDescriptorOverride( sqlCode );
} }
} }

View File

@ -51,6 +51,7 @@ import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
* Convenience base class for {@link BasicType} implementations * Convenience base class for {@link BasicType} implementations
* *
* @author Steve Ebersole * @author Steve Ebersole
* @author Brett Meyer
*/ */
public abstract class AbstractStandardBasicType<T> public abstract class AbstractStandardBasicType<T>
implements BasicType, StringRepresentableType<T>, XmlRepresentableType<T>, ProcedureParameterExtractionAware<T> { implements BasicType, StringRepresentableType<T>, XmlRepresentableType<T>, ProcedureParameterExtractionAware<T> {
@ -253,24 +254,7 @@ public abstract class AbstractStandardBasicType<T>
} }
public final T nullSafeGet(ResultSet rs, String name, final SessionImplementor session) throws SQLException { public final T nullSafeGet(ResultSet rs, String name, final SessionImplementor session) throws SQLException {
// todo : have SessionImplementor extend WrapperOptions final WrapperOptions options = getOptions(session);
final WrapperOptions options = new WrapperOptions() {
public boolean useStreamForLobBinding() {
return Environment.useStreamsForBinary();
}
public LobCreator getLobCreator() {
return Hibernate.getLobCreator( session );
}
public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
final SqlTypeDescriptor remapped = sqlTypeDescriptor.canBeRemapped()
? session.getFactory().getDialect().remapSqlTypeDescriptor( sqlTypeDescriptor )
: sqlTypeDescriptor;
return remapped == null ? sqlTypeDescriptor : remapped;
}
};
return nullSafeGet( rs, name, options ); return nullSafeGet( rs, name, options );
} }
@ -288,24 +272,7 @@ public abstract class AbstractStandardBasicType<T>
Object value, Object value,
int index, int index,
final SessionImplementor session) throws SQLException { final SessionImplementor session) throws SQLException {
// todo : have SessionImplementor extend WrapperOptions final WrapperOptions options = getOptions(session);
final WrapperOptions options = new WrapperOptions() {
public boolean useStreamForLobBinding() {
return Environment.useStreamsForBinary();
}
public LobCreator getLobCreator() {
return Hibernate.getLobCreator( session );
}
public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
final SqlTypeDescriptor remapped = sqlTypeDescriptor.canBeRemapped()
? session.getFactory().getDialect().remapSqlTypeDescriptor( sqlTypeDescriptor )
: sqlTypeDescriptor;
return remapped == null ? sqlTypeDescriptor : remapped;
}
};
nullSafeSet( st, value, index, options ); nullSafeSet( st, value, index, options );
} }
@ -403,24 +370,7 @@ public abstract class AbstractStandardBasicType<T>
@Override @Override
public T extract(CallableStatement statement, int startIndex, final SessionImplementor session) throws SQLException { public T extract(CallableStatement statement, int startIndex, final SessionImplementor session) throws SQLException {
// todo : have SessionImplementor extend WrapperOptions final WrapperOptions options = getOptions(session);
final WrapperOptions options = new WrapperOptions() {
public boolean useStreamForLobBinding() {
return Environment.useStreamsForBinary();
}
public LobCreator getLobCreator() {
return Hibernate.getLobCreator( session );
}
public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
final SqlTypeDescriptor remapped = sqlTypeDescriptor.canBeRemapped()
? session.getFactory().getDialect().remapSqlTypeDescriptor( sqlTypeDescriptor )
: sqlTypeDescriptor;
return remapped == null ? sqlTypeDescriptor : remapped;
}
};
return remapSqlTypeDescriptor( options ).getExtractor( javaTypeDescriptor ).extract( return remapSqlTypeDescriptor( options ).getExtractor( javaTypeDescriptor ).extract(
statement, statement,
startIndex, startIndex,
@ -430,10 +380,16 @@ public abstract class AbstractStandardBasicType<T>
@Override @Override
public T extract(CallableStatement statement, String[] paramNames, final SessionImplementor session) throws SQLException { public T extract(CallableStatement statement, String[] paramNames, final SessionImplementor session) throws SQLException {
// todo : have SessionImplementor extend WrapperOptions final WrapperOptions options = getOptions(session);
final WrapperOptions options = new WrapperOptions() { return remapSqlTypeDescriptor( options ).getExtractor( javaTypeDescriptor ).extract( statement, paramNames, options );
}
// TODO : have SessionImplementor extend WrapperOptions
private WrapperOptions getOptions(final SessionImplementor session) {
return new WrapperOptions() {
public boolean useStreamForLobBinding() { public boolean useStreamForLobBinding() {
return Environment.useStreamsForBinary(); return Environment.useStreamsForBinary()
|| session.getFactory().getDialect().useInputStreamToInsertBlob();
} }
public LobCreator getLobCreator() { public LobCreator getLobCreator() {
@ -447,7 +403,5 @@ public abstract class AbstractStandardBasicType<T>
return remapped == null ? sqlTypeDescriptor : remapped; return remapped == null ? sqlTypeDescriptor : remapped;
} }
}; };
return remapSqlTypeDescriptor( options ).getExtractor( javaTypeDescriptor ).extract( statement, paramNames, options );
} }
} }

View File

@ -23,6 +23,8 @@
*/ */
package org.hibernate.type.descriptor.java; package org.hibernate.type.descriptor.java;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable; import java.io.Serializable;
import java.sql.Blob; import java.sql.Blob;
import java.sql.SQLException; import java.sql.SQLException;
@ -41,6 +43,7 @@ import org.hibernate.type.descriptor.WrapperOptions;
* treat them as immutable because we cannot properly check them for changes nor deep copy them. * treat them as immutable because we cannot properly check them for changes nor deep copy them.
* *
* @author Steve Ebersole * @author Steve Ebersole
* @author Brett Meyer
*/ */
public class BlobTypeDescriptor extends AbstractTypeDescriptor<Blob> { public class BlobTypeDescriptor extends AbstractTypeDescriptor<Blob> {
public static final BlobTypeDescriptor INSTANCE = new BlobTypeDescriptor(); public static final BlobTypeDescriptor INSTANCE = new BlobTypeDescriptor();
@ -136,10 +139,23 @@ public class BlobTypeDescriptor extends AbstractTypeDescriptor<Blob> {
return null; return null;
} }
if ( ! Blob.class.isAssignableFrom( value.getClass() ) ) { // Support multiple return types from
throw unknownWrap( value.getClass() ); // org.hibernate.type.descriptor.sql.BlobTypeDescriptor
if ( Blob.class.isAssignableFrom( value.getClass() ) ) {
return options.getLobCreator().wrap( (Blob) value );
} else if ( byte[].class.isAssignableFrom( value.getClass() ) ) {
return options.getLobCreator().createBlob( ( byte[] ) value);
} else if ( InputStream.class.isAssignableFrom( value.getClass() ) ) {
InputStream inputStream = ( InputStream ) value;
try {
return options.getLobCreator().createBlob( inputStream, inputStream.available() );
}
catch ( IOException e ) {
throw unknownWrap( value.getClass() );
}
} }
return options.getLobCreator().wrap( (Blob) value );
throw unknownWrap( value.getClass() );
} }
} }

View File

@ -31,7 +31,6 @@ import java.sql.SQLException;
import java.sql.Types; import java.sql.Types;
import org.hibernate.type.descriptor.BinaryStream; import org.hibernate.type.descriptor.BinaryStream;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
@ -56,24 +55,11 @@ public abstract class BlobTypeDescriptor implements SqlTypeDescriptor {
return true; return true;
} }
protected abstract <X> BasicExtractor<X> getBlobExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor);
@Override @Override
public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) { public <X> BasicExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>( javaTypeDescriptor, this ) { return getBlobExtractor( javaTypeDescriptor );
@Override
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getBlob( name ), options );
}
@Override
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( statement.getBlob( index ), options );
}
@Override
protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( statement.getBlob( name ), options );
}
};
} }
protected abstract <X> BasicBinder<X> getBlobBinder(final JavaTypeDescriptor<X> javaTypeDescriptor); protected abstract <X> BasicBinder<X> getBlobBinder(final JavaTypeDescriptor<X> javaTypeDescriptor);
@ -93,16 +79,39 @@ public abstract class BlobTypeDescriptor implements SqlTypeDescriptor {
return new BasicBinder<X>( javaTypeDescriptor, this ) { return new BasicBinder<X>( javaTypeDescriptor, this ) {
@Override @Override
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException { protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException {
BlobTypeDescriptor descriptor = BLOB_BINDING;
if ( options.useStreamForLobBinding() ) { if ( options.useStreamForLobBinding() ) {
STREAM_BINDING.getBlobBinder( javaTypeDescriptor ).doBind( st, value, index, options ); descriptor = STREAM_BINDING;
} }
else if ( byte[].class.isInstance( value ) ) { else if ( byte[].class.isInstance( value ) ) {
// performance shortcut for binding BLOB data in byte[] format // performance shortcut for binding BLOB data in byte[] format
PRIMITIVE_ARRAY_BINDING.getBlobBinder( javaTypeDescriptor ).doBind( st, value, index, options ); descriptor = PRIMITIVE_ARRAY_BINDING;
}
else {
BLOB_BINDING.getBlobBinder( javaTypeDescriptor ).doBind( st, value, index, options );
} }
descriptor.getBlobBinder( javaTypeDescriptor ).doBind( st, value, index, options );
}
};
}
@Override
public <X> BasicExtractor<X> getBlobExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>( 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 );
}
@Override
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
return BLOB_BINDING.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 );
} }
}; };
} }
@ -120,6 +129,26 @@ public abstract class BlobTypeDescriptor implements SqlTypeDescriptor {
} }
}; };
} }
@Override
public <X> BasicExtractor<X> getBlobExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
@Override
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getBytes( name ), options );
}
@Override
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( statement.getBytes( index ), options );
}
@Override
protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( statement.getBytes( name ), options );
}
};
}
}; };
public static final BlobTypeDescriptor BLOB_BINDING = public static final BlobTypeDescriptor BLOB_BINDING =
@ -134,6 +163,26 @@ public abstract class BlobTypeDescriptor implements SqlTypeDescriptor {
} }
}; };
} }
@Override
public <X> BasicExtractor<X> getBlobExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
@Override
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getBlob( name ), options );
}
@Override
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( statement.getBlob( index ), options );
}
@Override
protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( statement.getBlob( name ), options );
}
};
}
}; };
public static final BlobTypeDescriptor STREAM_BINDING = public static final BlobTypeDescriptor STREAM_BINDING =
@ -149,6 +198,28 @@ public abstract class BlobTypeDescriptor implements SqlTypeDescriptor {
} }
}; };
} }
@Override
public <X> BasicExtractor<X> getBlobExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
@Override
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap( rs.getBinaryStream( name ), options );
}
@Override
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
// TODO: CallableStatement does not have getBinaryStream
return javaTypeDescriptor.wrap( statement.getBytes( index ), options );
}
@Override
protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
// TODO: CallableStatement does not have getBinaryStream
return javaTypeDescriptor.wrap( statement.getBytes( name ), options );
}
};
}
}; };
} }

View File

@ -23,7 +23,10 @@
*/ */
package org.hibernate.test.typeoverride; package org.hibernate.test.typeoverride;
import org.junit.Test; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Configuration;
@ -31,17 +34,14 @@ import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.PostgreSQL81Dialect; import org.hibernate.dialect.PostgreSQL81Dialect;
import org.hibernate.dialect.PostgreSQLDialect; import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.dialect.SybaseASE15Dialect; import org.hibernate.dialect.SybaseASE15Dialect;
import org.hibernate.dialect.SybaseDialect;
import org.hibernate.testing.SkipForDialect; import org.hibernate.testing.SkipForDialect;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.type.descriptor.sql.BlobTypeDescriptor; import org.hibernate.type.descriptor.sql.BlobTypeDescriptor;
import org.hibernate.type.descriptor.sql.IntegerTypeDescriptor; import org.hibernate.type.descriptor.sql.IntegerTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.descriptor.sql.VarcharTypeDescriptor; import org.hibernate.type.descriptor.sql.VarcharTypeDescriptor;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
/** /**
* @author Gail Badner * @author Gail Badner
@ -62,17 +62,16 @@ public class TypeOverrideTest extends BaseCoreFunctionalTestCase {
// no override // no override
assertSame( IntegerTypeDescriptor.INSTANCE, remapSqlTypeDescriptor( IntegerTypeDescriptor.INSTANCE ) ); assertSame( IntegerTypeDescriptor.INSTANCE, remapSqlTypeDescriptor( IntegerTypeDescriptor.INSTANCE ) );
// override depends on Dialect.useInputStreamToInsertBlob(); // A few dialects explicitly override BlobTypeDescriptor.DEFAULT
// Postgresql explicitly overrides BlobTypeDescriptor.DEFAULT if ( PostgreSQL81Dialect.class.isInstance( getDialect() ) || PostgreSQLDialect.class.isInstance( getDialect() ) ) {
if ( getDialect().useInputStreamToInsertBlob() ) {
assertSame( assertSame(
BlobTypeDescriptor.STREAM_BINDING, BlobTypeDescriptor.BLOB_BINDING,
getDialect().remapSqlTypeDescriptor( BlobTypeDescriptor.DEFAULT ) getDialect().remapSqlTypeDescriptor( BlobTypeDescriptor.DEFAULT )
); );
} }
else if ( PostgreSQL81Dialect.class.isInstance( getDialect() ) || PostgreSQLDialect.class.isInstance( getDialect() ) ) { else if (SybaseDialect.class.isInstance( getDialect() )) {
assertSame( assertSame(
BlobTypeDescriptor.BLOB_BINDING, BlobTypeDescriptor.PRIMITIVE_ARRAY_BINDING,
getDialect().remapSqlTypeDescriptor( BlobTypeDescriptor.DEFAULT ) getDialect().remapSqlTypeDescriptor( BlobTypeDescriptor.DEFAULT )
); );
} }