improve javadoc

experiment with transferTo() to copy Blob/Clob streams instead of getSubString()

Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
Gavin King 2024-11-04 12:57:03 +01:00
parent 35b97a040e
commit f9e544e394
3 changed files with 105 additions and 20 deletions

View File

@ -108,6 +108,8 @@ public interface LobCreator {
* Return an instance which can actually be written to a JDBC
* {@code PreparedStatement}.
*
* @see java.sql.PreparedStatement#setBlob(int, Blob)
*
* @apiNote This is needed for Oracle
*
* @see org.hibernate.dialect.Dialect#useConnectionToCreateLob
@ -120,6 +122,8 @@ public interface LobCreator {
* Return an instance which can actually be written to a JDBC
* {@code PreparedStatement}.
*
* @see java.sql.PreparedStatement#setClob(int, Clob)
*
* @apiNote This is needed for Oracle
*
* @see org.hibernate.dialect.Dialect#useConnectionToCreateLob
@ -132,6 +136,8 @@ public interface LobCreator {
* Return an instance which can actually be written to a JDBC
* {@code PreparedStatement}.
*
* @see java.sql.PreparedStatement#setNClob(int, NClob)
*
* @apiNote This is needed for Oracle
*
* @see org.hibernate.dialect.Dialect#useConnectionToCreateLob

View File

@ -10,6 +10,7 @@ import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.NClob;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.hibernate.JDBCException;
@ -37,6 +38,11 @@ public class BlobAndClobCreator extends AbstractLobCreator implements LobCreator
*/
public static final LobCreationContext.Callback<Clob> CREATE_CLOB_CALLBACK = Connection::createClob;
/**
* Callback for performing contextual NCLOB creation
*/
public static final LobCreationContext.Callback<NClob> CREATE_NCLOB_CALLBACK = Connection::createNClob;
protected final LobCreationContext lobCreationContext;
protected final boolean useConnectionToCreateLob;
@ -54,6 +60,10 @@ public class BlobAndClobCreator extends AbstractLobCreator implements LobCreator
return lobCreationContext.fromContext( CREATE_BLOB_CALLBACK );
}
/**
* Create a {@link Blob} object after reading a {@code byte[]}
* array from a JDBC {@link ResultSet}.
*/
@Override
public Blob createBlob(byte[] bytes) {
final Blob blob = createBlob();
@ -66,11 +76,18 @@ public class BlobAndClobCreator extends AbstractLobCreator implements LobCreator
}
}
/**
* Create a {@link Blob} object after reading an {@link InputStream}
* from a JDBC {@link ResultSet}.
*
* @implNote
* It's very inefficient to use JDBC LOB locator creation to create
* a LOB with the contents of the given stream, since that requires
* reading the whole stream. So instead just wrap the given stream,
* just like what {@link NonContextualLobCreator} does.
*/
@Override
public Blob createBlob(InputStream stream, long length) {
// IMPL NOTE: it's inefficient to use JDBC LOB locator creation to
// create a LOB backed by a given stream. So just wrap the stream
// (which is what the NonContextualLobCreator does).
return NonContextualLobCreator.INSTANCE.createBlob( stream, length );
}
@ -79,10 +96,23 @@ public class BlobAndClobCreator extends AbstractLobCreator implements LobCreator
*
* @return The created CLOB reference.
*/
public Clob createClob() {
Clob createClob() {
return lobCreationContext.fromContext( CREATE_CLOB_CALLBACK );
}
/**
* Create the basic contextual NCLOB reference.
*
* @return The created NCLOB reference.
*/
NClob createNClob() {
return lobCreationContext.fromContext( CREATE_NCLOB_CALLBACK );
}
/**
* Create a {@link Clob} object after reading a {@code String}
* from a JDBC {@link ResultSet}.
*/
@Override
public Clob createClob(String string) {
try {
@ -95,11 +125,18 @@ public class BlobAndClobCreator extends AbstractLobCreator implements LobCreator
}
}
/**
* Create a {@link Clob} object after reading an {@link InputStream}
* from a JDBC {@link ResultSet}.
*
* @implNote
* It's very inefficient to use JDBC LOB locator creation to create
* a LOB with the contents of the given stream, since that requires
* reading the whole stream. So instead just wrap the given stream,
* just like what {@link NonContextualLobCreator} does.
*/
@Override
public Clob createClob(Reader reader, long length) {
// IMPL NOTE: it's inefficient to use JDBC LOB locator creation to
// create a LOB backed by a given stream. So just wrap the stream
// (which is what the NonContextualLobCreator does).
return NonContextualLobCreator.INSTANCE.createClob( reader, length );
}
@ -113,39 +150,81 @@ public class BlobAndClobCreator extends AbstractLobCreator implements LobCreator
return NonContextualLobCreator.INSTANCE.createNClob( reader, length );
}
/**
* Obtain a {@link Blob} instance which can be written to a JDBC
* {@link java.sql.PreparedStatement} using
* {@link java.sql.PreparedStatement#setBlob(int, Blob)}.
*/
@Override
public Blob toJdbcBlob(Blob blob) {
try {
return useConnectionToCreateLob
? createBlob( blob.getBytes( 1, (int) blob.length() ) )
: super.toJdbcBlob( blob );
if ( useConnectionToCreateLob ) {
// final Blob jdbcBlob = createBlob();
// blob.getBinaryStream().transferTo( jdbcBlob.setBinaryStream(1) );
// return jdbcBlob;
return createBlob( blob.getBytes( 1, (int) blob.length() ) );
}
else {
return super.toJdbcBlob( blob );
}
}
catch (SQLException e) {
throw new JDBCException( "Could not create JDBC Clob", e );
throw new JDBCException( "Could not create JDBC Blob", e );
}
// catch (IOException e) {
// throw new HibernateException( "Could not create JDBC Blob", e );
// }
}
/**
* Obtain a {@link Clob} instance which can be written to a JDBC
* {@link java.sql.PreparedStatement} using
* {@link java.sql.PreparedStatement#setClob(int, Clob)}.
*/
@Override
public Clob toJdbcClob(Clob clob) {
try {
return useConnectionToCreateLob
? createClob( clob.getSubString( 1, (int) clob.length() ) )
: super.toJdbcClob( clob );
if ( useConnectionToCreateLob ) {
// final Clob jdbcClob = createClob();
// clob.getCharacterStream().transferTo( jdbcClob.setCharacterStream(1) );
// return jdbcClob;
return createClob( clob.getSubString( 1, (int) clob.length() ) );
}
else {
return super.toJdbcClob( clob );
}
}
catch (SQLException e) {
throw new JDBCException( "Could not create JDBC Clob", e );
}
// catch (IOException e) {
// throw new HibernateException( "Could not create JDBC Clob", e );
// }
}
/**
* Obtain an {@link NClob} instance which can be written to a JDBC
* {@link java.sql.PreparedStatement} using
* {@link java.sql.PreparedStatement#setNClob(int, NClob)}.
*/
@Override
public NClob toJdbcNClob(NClob clob) {
try {
return useConnectionToCreateLob
? createNClob( clob.getSubString( 1, (int) clob.length() ) )
: super.toJdbcNClob( clob );
if ( useConnectionToCreateLob ) {
// final NClob jdbcClob = createNClob();
// clob.getCharacterStream().transferTo( jdbcClob.setCharacterStream(1) );
// return jdbcClob;
return createNClob( clob.getSubString( 1, (int) clob.length() ) );
}
else {
return super.toJdbcNClob( clob );
}
}
catch (SQLException e) {
throw new JDBCException( "Could not create JDBC Clob", e );
}
throw new JDBCException( "Could not create JDBC NClob", e );
}
// catch (IOException e) {
// throw new HibernateException( "Could not create JDBC NClob", e );
// }
}
}

View File

@ -52,7 +52,7 @@ public class LobCreatorBuilderImpl implements LobCreatorBuilder {
}
/**
* For used when JDBC Connection is not available.
* For use when JDBC {@link Connection} is not available.
*
* @return Appropriate LobCreatorBuilder
*/
@ -62,7 +62,7 @@ public class LobCreatorBuilderImpl implements LobCreatorBuilder {
}
/**
* Build a LobCreator using the given context
* Build a {@link LobCreator} using the given context
*
* @param lobCreationContext The LOB creation context
*