HHH-7698 - In efficient LOB creations backed by streams
This commit is contained in:
parent
e5d3b2b34c
commit
d118c24776
|
@ -31,16 +31,12 @@ import java.sql.Clob;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractLobCreator implements LobCreator {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Blob wrap(Blob blob) {
|
||||
return SerializableBlobProxy.generateProxy( blob );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Clob wrap(Clob clob) {
|
||||
if ( SerializableNClobProxy.isNClob( clob ) ) {
|
||||
return SerializableNClobProxy.generateProxy( clob );
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.type.descriptor;
|
||||
package org.hibernate.engine.jdbc;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
|
@ -49,5 +50,10 @@ public interface BinaryStream {
|
|||
*
|
||||
* @return The input stream length
|
||||
*/
|
||||
public int getLength();
|
||||
public long getLength();
|
||||
|
||||
/**
|
||||
* Release any underlying resources.
|
||||
*/
|
||||
public void release();
|
||||
}
|
|
@ -23,11 +23,16 @@
|
|||
*/
|
||||
package org.hibernate.engine.jdbc;
|
||||
|
||||
|
||||
/**
|
||||
* Marker interface for non-contextually created {@link java.sql.Blob} instances..
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface BlobImplementer {
|
||||
/**
|
||||
* Gets access to the data underlying this BLOB.
|
||||
*
|
||||
* @return Access to the underlying data.
|
||||
*/
|
||||
public BinaryStream getUnderlyingStream();
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.engine.jdbc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
|
@ -30,12 +31,12 @@ import java.lang.reflect.Proxy;
|
|||
import java.sql.Blob;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.type.descriptor.java.BinaryStreamImpl;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.type.descriptor.java.DataHelper;
|
||||
|
||||
/**
|
||||
* Manages aspects of proxying {@link Blob Blobs} for non-contextual creation, including proxy creation and
|
||||
* handling proxy invocations.
|
||||
* Manages aspects of proxying {@link Blob} references for non-contextual creation, including proxy creation and
|
||||
* handling proxy invocations. We use proxies here solely to avoid JDBC version incompatibilities.
|
||||
*
|
||||
* @author Gavin King
|
||||
* @author Steve Ebersole
|
||||
|
@ -44,8 +45,7 @@ import org.hibernate.type.descriptor.java.DataHelper;
|
|||
public class BlobProxy implements InvocationHandler {
|
||||
private static final Class[] PROXY_INTERFACES = new Class[] { Blob.class, BlobImplementer.class };
|
||||
|
||||
private InputStream stream;
|
||||
private long length;
|
||||
private BinaryStream binaryStream;
|
||||
private boolean needsReset = false;
|
||||
|
||||
/**
|
||||
|
@ -55,8 +55,7 @@ public class BlobProxy implements InvocationHandler {
|
|||
* @see #generateProxy(byte[])
|
||||
*/
|
||||
private BlobProxy(byte[] bytes) {
|
||||
this.stream = new BinaryStreamImpl( bytes );
|
||||
this.length = bytes.length;
|
||||
binaryStream = new BinaryStreamImpl( bytes );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -67,17 +66,17 @@ public class BlobProxy implements InvocationHandler {
|
|||
* @see #generateProxy(java.io.InputStream, long)
|
||||
*/
|
||||
private BlobProxy(InputStream stream, long length) {
|
||||
this.stream = stream;
|
||||
this.length = length;
|
||||
this.binaryStream = new StreamBackedBinaryStream( stream, length );
|
||||
}
|
||||
|
||||
private long getLength() {
|
||||
return length;
|
||||
return binaryStream.getLength();
|
||||
}
|
||||
|
||||
private InputStream getStream() throws SQLException {
|
||||
InputStream stream = binaryStream.getInputStream();
|
||||
try {
|
||||
if (needsReset) {
|
||||
if ( needsReset ) {
|
||||
stream.reset();
|
||||
}
|
||||
}
|
||||
|
@ -94,6 +93,7 @@ public class BlobProxy implements InvocationHandler {
|
|||
* @throws UnsupportedOperationException if any methods other than {@link Blob#length()}
|
||||
* or {@link Blob#getBinaryStream} are invoked.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings({ "UnnecessaryBoxing" })
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
final String methodName = method.getName();
|
||||
|
@ -102,6 +102,9 @@ public class BlobProxy implements InvocationHandler {
|
|||
if ( "length".equals( methodName ) && argCount == 0 ) {
|
||||
return Long.valueOf( getLength() );
|
||||
}
|
||||
if ( "getUnderlyingStream".equals( methodName ) ) {
|
||||
return binaryStream;
|
||||
}
|
||||
if ( "getBinaryStream".equals( methodName ) ) {
|
||||
if ( argCount == 0 ) {
|
||||
return getStream();
|
||||
|
@ -137,7 +140,7 @@ public class BlobProxy implements InvocationHandler {
|
|||
}
|
||||
}
|
||||
if ( "free".equals( methodName ) && argCount == 0 ) {
|
||||
stream.close();
|
||||
binaryStream.release();
|
||||
return null;
|
||||
}
|
||||
if ( "toString".equals( methodName ) && argCount == 0 ) {
|
||||
|
@ -197,4 +200,43 @@ public class BlobProxy implements InvocationHandler {
|
|||
}
|
||||
return cl;
|
||||
}
|
||||
|
||||
private static class StreamBackedBinaryStream implements BinaryStream {
|
||||
private final InputStream stream;
|
||||
private final long length;
|
||||
|
||||
private byte[] bytes;
|
||||
|
||||
private StreamBackedBinaryStream(InputStream stream, long length) {
|
||||
this.stream = stream;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
return stream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBytes() {
|
||||
if ( bytes == null ) {
|
||||
bytes = DataHelper.extractBytes( stream );
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLength() {
|
||||
return (int) length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
try {
|
||||
stream.close();
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,9 @@
|
|||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.type.descriptor;
|
||||
package org.hibernate.engine.jdbc;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
|
||||
/**
|
||||
|
@ -32,17 +34,28 @@ import java.io.Reader;
|
|||
*/
|
||||
public interface CharacterStream {
|
||||
/**
|
||||
* Retrieve the reader.
|
||||
* Provides access to the underlying data as a Reader.
|
||||
*
|
||||
* @return The reader.
|
||||
*/
|
||||
public Reader getReader();
|
||||
public Reader asReader();
|
||||
|
||||
/**
|
||||
* Retrieve the number of characters. JDBC 3 and earlier defined the length in terms of int type rather than
|
||||
* long type :(
|
||||
* Provides access to the underlying data as a String.
|
||||
*
|
||||
* @return The underlying String data
|
||||
*/
|
||||
public String asString();
|
||||
|
||||
/**
|
||||
* Retrieve the number of characters.
|
||||
*
|
||||
* @return The number of characters.
|
||||
*/
|
||||
public int getLength();
|
||||
public long getLength();
|
||||
|
||||
/**
|
||||
* Release any underlying resources.
|
||||
*/
|
||||
public void release();
|
||||
}
|
|
@ -23,11 +23,16 @@
|
|||
*/
|
||||
package org.hibernate.engine.jdbc;
|
||||
|
||||
|
||||
/**
|
||||
* Marker interface for non-contextually created {@link java.sql.Clob} instances..
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ClobImplementer {
|
||||
/**
|
||||
* Gets access to the data underlying this CLOB.
|
||||
*
|
||||
* @return Access to the underlying data.
|
||||
*/
|
||||
public CharacterStream getUnderlyingStream();
|
||||
}
|
||||
|
|
|
@ -33,11 +33,12 @@ import java.lang.reflect.Proxy;
|
|||
import java.sql.Clob;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.engine.jdbc.internal.CharacterStreamImpl;
|
||||
import org.hibernate.type.descriptor.java.DataHelper;
|
||||
|
||||
/**
|
||||
* Manages aspects of proxying {@link Clob Clobs} for non-contextual creation, including proxy creation and
|
||||
* handling proxy invocations.
|
||||
* handling proxy invocations. We use proxies here solely to avoid JDBC version incompatibilities.
|
||||
*
|
||||
* @author Gavin King
|
||||
* @author Steve Ebersole
|
||||
|
@ -46,12 +47,9 @@ import org.hibernate.type.descriptor.java.DataHelper;
|
|||
public class ClobProxy implements InvocationHandler {
|
||||
private static final Class[] PROXY_INTERFACES = new Class[] { Clob.class, ClobImplementer.class };
|
||||
|
||||
private String string;
|
||||
private Reader reader;
|
||||
private long length;
|
||||
private final CharacterStream characterStream;
|
||||
private boolean needsReset = false;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor used to build {@link Clob} from string data.
|
||||
*
|
||||
|
@ -59,9 +57,7 @@ public class ClobProxy implements InvocationHandler {
|
|||
* @see #generateProxy(String)
|
||||
*/
|
||||
protected ClobProxy(String string) {
|
||||
this.string = string;
|
||||
reader = new StringReader(string);
|
||||
length = string.length();
|
||||
this.characterStream = new CharacterStreamImpl( string );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,28 +68,25 @@ public class ClobProxy implements InvocationHandler {
|
|||
* @see #generateProxy(java.io.Reader, long)
|
||||
*/
|
||||
protected ClobProxy(Reader reader, long length) {
|
||||
this.reader = reader;
|
||||
this.length = length;
|
||||
this.characterStream = new CharacterStreamImpl( reader, length );
|
||||
}
|
||||
|
||||
protected long getLength() {
|
||||
return length;
|
||||
return characterStream.getLength();
|
||||
}
|
||||
|
||||
protected InputStream getAsciiStream() throws SQLException {
|
||||
resetIfNeeded();
|
||||
return new ReaderInputStream( reader );
|
||||
return new ReaderInputStream( characterStream.asReader() );
|
||||
}
|
||||
|
||||
protected Reader getCharacterStream() throws SQLException {
|
||||
resetIfNeeded();
|
||||
return reader;
|
||||
return characterStream.asReader();
|
||||
}
|
||||
|
||||
protected String getSubString(long start, int length) {
|
||||
if ( string == null ) {
|
||||
throw new UnsupportedOperationException( "Clob was not created from string; cannot substring" );
|
||||
}
|
||||
final String string = characterStream.asString();
|
||||
// semi-naive implementation
|
||||
int endIndex = Math.min( ((int)start)+length, string.length() );
|
||||
return string.substring( (int)start, endIndex );
|
||||
|
@ -105,6 +98,7 @@ public class ClobProxy implements InvocationHandler {
|
|||
* @throws UnsupportedOperationException if any methods other than {@link Clob#length()},
|
||||
* {@link Clob#getAsciiStream()}, or {@link Clob#getCharacterStream()} are invoked.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings({ "UnnecessaryBoxing" })
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
final String methodName = method.getName();
|
||||
|
@ -113,6 +107,9 @@ public class ClobProxy implements InvocationHandler {
|
|||
if ( "length".equals( methodName ) && argCount == 0 ) {
|
||||
return Long.valueOf( getLength() );
|
||||
}
|
||||
if ( "getUnderlyingStream".equals( methodName ) ) {
|
||||
return characterStream;
|
||||
}
|
||||
if ( "getAsciiStream".equals( methodName ) && argCount == 0 ) {
|
||||
return getAsciiStream();
|
||||
}
|
||||
|
@ -152,7 +149,7 @@ public class ClobProxy implements InvocationHandler {
|
|||
return getSubString( start-1, length );
|
||||
}
|
||||
if ( "free".equals( methodName ) && argCount == 0 ) {
|
||||
reader.close();
|
||||
characterStream.release();
|
||||
return null;
|
||||
}
|
||||
if ( "toString".equals( methodName ) && argCount == 0 ) {
|
||||
|
@ -171,7 +168,7 @@ public class ClobProxy implements InvocationHandler {
|
|||
protected void resetIfNeeded() throws SQLException {
|
||||
try {
|
||||
if ( needsReset ) {
|
||||
reader.reset();
|
||||
characterStream.asReader().reset();
|
||||
}
|
||||
}
|
||||
catch ( IOException ioe ) {
|
||||
|
|
|
@ -59,9 +59,7 @@ public class ContextualLobCreator extends AbstractLobCreator implements LobCreat
|
|||
return lobCreationContext.execute( CREATE_BLOB_CALLBACK );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Blob createBlob(byte[] bytes) {
|
||||
try {
|
||||
Blob blob = createBlob();
|
||||
|
@ -73,25 +71,11 @@ public class ContextualLobCreator extends AbstractLobCreator implements LobCreat
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Blob createBlob(InputStream inputStream, long length) {
|
||||
try {
|
||||
Blob blob = createBlob();
|
||||
OutputStream byteStream = blob.setBinaryStream( 1 );
|
||||
StreamUtils.copy( inputStream, byteStream );
|
||||
byteStream.flush();
|
||||
byteStream.close();
|
||||
// todo : validate length written versus length given?
|
||||
return blob;
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
throw new JDBCException( "Unable to prepare BLOB binary stream for writing",e );
|
||||
}
|
||||
catch ( IOException e ) {
|
||||
throw new HibernateException( "Unable to write stream contents to BLOB", e );
|
||||
}
|
||||
// IMPL NOTE : it is 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( inputStream, length );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -103,9 +87,7 @@ public class ContextualLobCreator extends AbstractLobCreator implements LobCreat
|
|||
return lobCreationContext.execute( CREATE_CLOB_CALLBACK );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Clob createClob(String string) {
|
||||
try {
|
||||
Clob clob = createClob();
|
||||
|
@ -117,24 +99,11 @@ public class ContextualLobCreator extends AbstractLobCreator implements LobCreat
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Clob createClob(Reader reader, long length) {
|
||||
try {
|
||||
Clob clob = createClob();
|
||||
Writer writer = clob.setCharacterStream( 1 );
|
||||
StreamUtils.copy( reader, writer );
|
||||
writer.flush();
|
||||
writer.close();
|
||||
return clob;
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
throw new JDBCException( "Unable to prepare CLOB stream for writing", e );
|
||||
}
|
||||
catch ( IOException e ) {
|
||||
throw new HibernateException( "Unable to write CLOB stream content", e );
|
||||
}
|
||||
// IMPL NOTE : it is 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 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -146,9 +115,7 @@ public class ContextualLobCreator extends AbstractLobCreator implements LobCreat
|
|||
return lobCreationContext.execute( CREATE_NCLOB_CALLBACK );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public NClob createNClob(String string) {
|
||||
try {
|
||||
NClob nclob = createNClob();
|
||||
|
@ -160,24 +127,11 @@ public class ContextualLobCreator extends AbstractLobCreator implements LobCreat
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public NClob createNClob(Reader reader, long length) {
|
||||
try {
|
||||
NClob nclob = createNClob();
|
||||
Writer writer = nclob.setCharacterStream( 1 );
|
||||
StreamUtils.copy( reader, writer );
|
||||
writer.flush();
|
||||
writer.close();
|
||||
return nclob;
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
throw new JDBCException( "Unable to prepare NCLOB stream for writing", e );
|
||||
}
|
||||
catch ( IOException e ) {
|
||||
throw new HibernateException( "Unable to write NCLOB stream content", e );
|
||||
}
|
||||
// IMPL NOTE : it is 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.createNClob( reader, length );
|
||||
}
|
||||
|
||||
public static final LobCreationContext.Callback<Blob> CREATE_BLOB_CALLBACK = new LobCreationContext.Callback<Blob>() {
|
||||
|
|
|
@ -30,8 +30,6 @@ import java.sql.NClob;
|
|||
|
||||
/**
|
||||
* Contract for creating various LOB references.
|
||||
*
|
||||
* @todo LobCreator really needs to be an api since we expose it to users.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Gail Badner
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.engine.jdbc;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.sql.Clob;
|
||||
|
@ -29,10 +30,10 @@ import java.sql.NClob;
|
|||
|
||||
/**
|
||||
* Manages aspects of proxying java.sql.NClobs for non-contextual creation, including proxy creation and
|
||||
* handling proxy invocations.
|
||||
* handling proxy invocations. We use proxies here solely to avoid JDBC version incompatibilities.
|
||||
* <p/>
|
||||
* Generated proxies are typed as {@link java.sql.Clob} (java.sql.NClob extends {@link java.sql.Clob}) and in JDK 1.6 environments, they
|
||||
* are also typed to java.sql.NClob
|
||||
* Generated proxies are typed as {@link java.sql.Clob} (java.sql.NClob extends {@link java.sql.Clob})
|
||||
* and in JDK 1.6+ environments, they are also typed to java.sql.NClob
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.engine.jdbc;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.sql.Blob;
|
||||
|
@ -41,44 +42,32 @@ public class NonContextualLobCreator extends AbstractLobCreator implements LobCr
|
|||
private NonContextualLobCreator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Blob createBlob(byte[] bytes) {
|
||||
return BlobProxy.generateProxy( bytes );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Blob createBlob(InputStream stream, long length) {
|
||||
return BlobProxy.generateProxy( stream, length );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Clob createClob(String string) {
|
||||
return ClobProxy.generateProxy( string );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Clob createClob(Reader reader, long length) {
|
||||
return ClobProxy.generateProxy( reader, length );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public NClob createNClob(String string) {
|
||||
return NClobProxy.generateProxy( string );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public NClob createNClob(Reader reader, long length) {
|
||||
return NClobProxy.generateProxy( reader, length );
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* Copyright (c) 2008, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,7 +20,6 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.engine.jdbc;
|
||||
import java.io.IOException;
|
||||
|
@ -42,5 +41,4 @@ public class ReaderInputStream extends InputStream {
|
|||
public int read() throws IOException {
|
||||
return reader.read();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.engine.jdbc;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
@ -62,9 +63,7 @@ public class SerializableBlobProxy implements InvocationHandler, Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
if ( "getWrappedBlob".equals( method.getName() ) ) {
|
||||
return getWrappedBlob();
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.engine.jdbc;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
@ -62,9 +63,7 @@ public class SerializableClobProxy implements InvocationHandler, Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
if ( "getWrappedClob".equals( method.getName() ) ) {
|
||||
return getWrappedClob();
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.engine.jdbc;
|
||||
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.sql.Clob;
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.engine.jdbc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.engine.jdbc;
|
||||
|
||||
import java.sql.Blob;
|
||||
|
||||
/**
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.engine.jdbc;
|
||||
|
||||
import java.sql.Clob;
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,12 +21,13 @@
|
|||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.type.descriptor.java;
|
||||
package org.hibernate.engine.jdbc.internal;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.hibernate.type.descriptor.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
|
||||
/**
|
||||
* Implementation of {@link BinaryStream}
|
||||
|
@ -50,7 +51,16 @@ public class BinaryStreamImpl extends ByteArrayInputStream implements BinaryStre
|
|||
return buf;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
public long getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
try {
|
||||
super.close();
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,12 +21,15 @@
|
|||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.type.descriptor.java;
|
||||
package org.hibernate.engine.jdbc.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
import org.hibernate.type.descriptor.CharacterStream;
|
||||
import org.hibernate.engine.jdbc.CharacterStream;
|
||||
import org.hibernate.type.descriptor.java.DataHelper;
|
||||
|
||||
/**
|
||||
* Implementation of {@link CharacterStream}
|
||||
|
@ -34,19 +37,51 @@ import org.hibernate.type.descriptor.CharacterStream;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class CharacterStreamImpl implements CharacterStream {
|
||||
private final StringReader reader;
|
||||
private final int length;
|
||||
private final long length;
|
||||
|
||||
private Reader reader;
|
||||
private String string;
|
||||
|
||||
public CharacterStreamImpl(String chars) {
|
||||
reader = new StringReader( chars );
|
||||
length = chars.length();
|
||||
this.string = chars;
|
||||
this.length = chars.length();
|
||||
}
|
||||
|
||||
public Reader getReader() {
|
||||
public CharacterStreamImpl(Reader reader, long length) {
|
||||
this.reader = reader;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Reader asReader() {
|
||||
if ( reader == null ) {
|
||||
reader = new StringReader( string );
|
||||
}
|
||||
return reader;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
@Override
|
||||
public String asString() {
|
||||
if ( string == null ) {
|
||||
string = DataHelper.extractString( reader );
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
if ( reader == null ) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
reader.close();
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,9 +31,11 @@ import java.sql.SQLException;
|
|||
import java.util.Comparator;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.jdbc.BlobImplementer;
|
||||
import org.hibernate.engine.jdbc.BlobProxy;
|
||||
import org.hibernate.engine.jdbc.WrappedBlob;
|
||||
import org.hibernate.type.descriptor.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
|
@ -117,16 +119,33 @@ public class BlobTypeDescriptor extends AbstractTypeDescriptor<Blob> {
|
|||
|
||||
try {
|
||||
if ( BinaryStream.class.isAssignableFrom( type ) ) {
|
||||
return (X) new BinaryStreamImpl( DataHelper.extractBytes( value.getBinaryStream() ) );
|
||||
} else if ( byte[].class.isAssignableFrom( type )) {
|
||||
return (X) DataHelper.extractBytes( value.getBinaryStream() );
|
||||
} else if (Blob.class.isAssignableFrom( type )) {
|
||||
if ( BlobImplementer.class.isInstance( value ) ) {
|
||||
// if the incoming Blob is a wrapper, just pass along its BinaryStream
|
||||
return (X) ( (BlobImplementer) value ).getUnderlyingStream();
|
||||
}
|
||||
else {
|
||||
// otherwise we need to build a BinaryStream...
|
||||
return (X) new BinaryStreamImpl( DataHelper.extractBytes( value.getBinaryStream() ) );
|
||||
}
|
||||
}
|
||||
else if ( byte[].class.isAssignableFrom( type )) {
|
||||
if ( BlobImplementer.class.isInstance( value ) ) {
|
||||
// if the incoming Blob is a wrapper, just grab the bytes from its BinaryStream
|
||||
return (X) ( (BlobImplementer) value ).getUnderlyingStream().getBytes();
|
||||
}
|
||||
else {
|
||||
// otherwise extract the bytes from the stream manually
|
||||
return (X) DataHelper.extractBytes( value.getBinaryStream() );
|
||||
}
|
||||
}
|
||||
else if (Blob.class.isAssignableFrom( type )) {
|
||||
final Blob blob = WrappedBlob.class.isInstance( value )
|
||||
? ( (WrappedBlob) value ).getWrappedBlob()
|
||||
: value;
|
||||
return (X) blob;
|
||||
}
|
||||
} catch ( SQLException e ) {
|
||||
}
|
||||
catch ( SQLException e ) {
|
||||
throw new HibernateException( "Unable to access blob stream", e );
|
||||
}
|
||||
|
||||
|
@ -142,9 +161,11 @@ public class BlobTypeDescriptor extends AbstractTypeDescriptor<Blob> {
|
|||
// 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() ) ) {
|
||||
}
|
||||
else if ( byte[].class.isAssignableFrom( value.getClass() ) ) {
|
||||
return options.getLobCreator().createBlob( ( byte[] ) value);
|
||||
} else if ( InputStream.class.isAssignableFrom( value.getClass() ) ) {
|
||||
}
|
||||
else if ( InputStream.class.isAssignableFrom( value.getClass() ) ) {
|
||||
InputStream inputStream = ( InputStream ) value;
|
||||
try {
|
||||
return options.getLobCreator().createBlob( inputStream, inputStream.available() );
|
||||
|
@ -154,7 +175,6 @@ public class BlobTypeDescriptor extends AbstractTypeDescriptor<Blob> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
throw unknownWrap( value.getClass() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,8 @@ import java.sql.Blob;
|
|||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.type.descriptor.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,7 +28,8 @@ import java.io.StringReader;
|
|||
import java.sql.Clob;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.hibernate.type.descriptor.CharacterStream;
|
||||
import org.hibernate.engine.jdbc.CharacterStream;
|
||||
import org.hibernate.engine.jdbc.internal.CharacterStreamImpl;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,9 +27,11 @@ import java.io.Serializable;
|
|||
import java.sql.Clob;
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.hibernate.engine.jdbc.ClobImplementer;
|
||||
import org.hibernate.engine.jdbc.ClobProxy;
|
||||
import org.hibernate.engine.jdbc.WrappedClob;
|
||||
import org.hibernate.type.descriptor.CharacterStream;
|
||||
import org.hibernate.engine.jdbc.CharacterStream;
|
||||
import org.hibernate.engine.jdbc.internal.CharacterStreamImpl;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
|
@ -102,7 +104,14 @@ public class ClobTypeDescriptor extends AbstractTypeDescriptor<Clob> {
|
|||
}
|
||||
|
||||
if ( CharacterStream.class.isAssignableFrom( type ) ) {
|
||||
return (X) new CharacterStreamImpl( DataHelper.extractString( value ) );
|
||||
if ( ClobImplementer.class.isInstance( value ) ) {
|
||||
// if the incoming Clob is a wrapper, just pass along its CharacterStream
|
||||
return (X) ( (ClobImplementer) value ).getUnderlyingStream();
|
||||
}
|
||||
else {
|
||||
// otherwise we need to build one...
|
||||
return (X) new CharacterStreamImpl( DataHelper.extractString( value ) );
|
||||
}
|
||||
}
|
||||
|
||||
final Clob clob = WrappedClob.class.isInstance( value )
|
||||
|
|
|
@ -34,8 +34,9 @@ import java.sql.SQLException;
|
|||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.type.descriptor.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
|
||||
/**
|
||||
* A help for dealing with BLOB and CLOB data
|
||||
|
|
|
@ -30,7 +30,8 @@ import java.sql.SQLException;
|
|||
import java.util.Arrays;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.type.descriptor.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,7 +28,8 @@ import java.io.StringReader;
|
|||
import java.sql.Clob;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.hibernate.type.descriptor.CharacterStream;
|
||||
import org.hibernate.engine.jdbc.CharacterStream;
|
||||
import org.hibernate.engine.jdbc.internal.CharacterStreamImpl;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,8 +30,9 @@ import java.sql.Blob;
|
|||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.jdbc.internal.BinaryStreamImpl;
|
||||
import org.hibernate.internal.util.SerializationHelper;
|
||||
import org.hibernate.type.descriptor.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,7 +27,8 @@ import java.io.Reader;
|
|||
import java.io.StringReader;
|
||||
import java.sql.Clob;
|
||||
|
||||
import org.hibernate.type.descriptor.CharacterStream;
|
||||
import org.hibernate.engine.jdbc.CharacterStream;
|
||||
import org.hibernate.engine.jdbc.internal.CharacterStreamImpl;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
||||
/**
|
||||
|
|
|
@ -29,7 +29,7 @@ import java.sql.ResultSet;
|
|||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.type.descriptor.BinaryStream;
|
||||
import org.hibernate.engine.jdbc.BinaryStream;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ import java.sql.ResultSet;
|
|||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.type.descriptor.CharacterStream;
|
||||
import org.hibernate.engine.jdbc.CharacterStream;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
@ -80,7 +80,7 @@ public abstract class ClobTypeDescriptor implements SqlTypeDescriptor {
|
|||
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
|
||||
throws SQLException {
|
||||
final CharacterStream characterStream = javaTypeDescriptor.unwrap( value, CharacterStream.class, options );
|
||||
st.setCharacterStream( index, characterStream.getReader(), characterStream.getLength() );
|
||||
st.setCharacterStream( index, characterStream.asReader(), characterStream.getLength() );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue