001/* 002 * Copyright 2002-2012 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.orm.hibernate3.support; 018 019import java.io.ByteArrayInputStream; 020import java.io.ByteArrayOutputStream; 021import java.io.IOException; 022import java.io.InputStream; 023import java.io.ObjectInputStream; 024import java.io.ObjectOutputStream; 025import java.io.Serializable; 026import java.sql.PreparedStatement; 027import java.sql.ResultSet; 028import java.sql.SQLException; 029import java.sql.Types; 030import javax.transaction.TransactionManager; 031 032import org.hibernate.HibernateException; 033 034import org.springframework.jdbc.support.lob.LobCreator; 035import org.springframework.jdbc.support.lob.LobHandler; 036 037/** 038 * Hibernate UserType implementation for arbitrary objects that get serialized to BLOBs. 039 * Retrieves the LobHandler to use from LocalSessionFactoryBean at config time. 040 * 041 * <p>Can also be defined in generic Hibernate mappings, as DefaultLobCreator will 042 * work with most JDBC-compliant database drivers. In this case, the field type 043 * does not have to be BLOB: For databases like MySQL and MS SQL Server, any 044 * large enough binary type will work. 045 * 046 * @author Juergen Hoeller 047 * @since 1.2 048 * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setLobHandler 049 * @deprecated as of Spring 4.3, in favor of Hibernate 4.x/5.x 050 */ 051@Deprecated 052public class BlobSerializableType extends AbstractLobType { 053 054 /** 055 * Initial size for ByteArrayOutputStreams used for serialization output. 056 * <p>If a serialized object is larger than these 1024 bytes, the size of 057 * the byte array used by the output stream will be doubled each time the 058 * limit is reached. 059 */ 060 private static final int OUTPUT_BYTE_ARRAY_INITIAL_SIZE = 1024; 061 062 /** 063 * Constructor used by Hibernate: fetches config-time LobHandler and 064 * config-time JTA TransactionManager from LocalSessionFactoryBean. 065 * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeLobHandler 066 * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#getConfigTimeTransactionManager 067 */ 068 public BlobSerializableType() { 069 super(); 070 } 071 072 /** 073 * Constructor used for testing: takes an explicit LobHandler 074 * and an explicit JTA TransactionManager (can be {@code null}). 075 */ 076 protected BlobSerializableType(LobHandler lobHandler, TransactionManager jtaTransactionManager) { 077 super(lobHandler, jtaTransactionManager); 078 } 079 080 @Override 081 public int[] sqlTypes() { 082 return new int[] {Types.BLOB}; 083 } 084 085 @Override 086 public Class<?> returnedClass() { 087 return Serializable.class; 088 } 089 090 @Override 091 public boolean isMutable() { 092 return true; 093 } 094 095 @Override 096 public Object deepCopy(Object value) throws HibernateException { 097 try { 098 // Write to new byte array to clone. 099 ByteArrayOutputStream baos = new ByteArrayOutputStream(OUTPUT_BYTE_ARRAY_INITIAL_SIZE); 100 ObjectOutputStream oos = new ObjectOutputStream(baos); 101 try { 102 oos.writeObject(value); 103 } 104 finally { 105 oos.close(); 106 } 107 108 // Read it back and return a true copy. 109 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 110 ObjectInputStream ois = new ObjectInputStream(bais); 111 try { 112 return ois.readObject(); 113 } 114 finally { 115 ois.close(); 116 } 117 } 118 catch (ClassNotFoundException ex) { 119 throw new HibernateException("Couldn't clone BLOB contents", ex); 120 } 121 catch (IOException ex) { 122 throw new HibernateException("Couldn't clone BLOB contents", ex); 123 } 124 } 125 126 @Override 127 protected Object nullSafeGetInternal( 128 ResultSet rs, String[] names, Object owner, LobHandler lobHandler) 129 throws SQLException, IOException, HibernateException { 130 131 InputStream is = lobHandler.getBlobAsBinaryStream(rs, names[0]); 132 if (is != null) { 133 ObjectInputStream ois = new ObjectInputStream(is); 134 try { 135 return ois.readObject(); 136 } 137 catch (ClassNotFoundException ex) { 138 throw new HibernateException("Could not deserialize BLOB contents", ex); 139 } 140 finally { 141 ois.close(); 142 } 143 } 144 else { 145 return null; 146 } 147 } 148 149 @Override 150 protected void nullSafeSetInternal( 151 PreparedStatement ps, int index, Object value, LobCreator lobCreator) 152 throws SQLException, IOException { 153 154 if (value != null) { 155 ByteArrayOutputStream baos = new ByteArrayOutputStream(OUTPUT_BYTE_ARRAY_INITIAL_SIZE); 156 ObjectOutputStream oos = new ObjectOutputStream(baos); 157 try { 158 oos.writeObject(value); 159 oos.flush(); 160 lobCreator.setBlobAsBytes(ps, index, baos.toByteArray()); 161 } 162 finally { 163 oos.close(); 164 } 165 } 166 else { 167 lobCreator.setBlobAsBytes(ps, index, null); 168 } 169 } 170 171}