001/* 002 * Copyright 2002-2017 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.jdbc.core.support; 018 019import java.io.InputStream; 020import java.io.Reader; 021import java.sql.PreparedStatement; 022import java.sql.SQLException; 023import java.sql.Types; 024 025import org.springframework.jdbc.core.DisposableSqlTypeValue; 026import org.springframework.jdbc.support.lob.DefaultLobHandler; 027import org.springframework.jdbc.support.lob.LobCreator; 028import org.springframework.jdbc.support.lob.LobHandler; 029 030/** 031 * Object to represent an SQL BLOB/CLOB value parameter. BLOBs can either be an 032 * InputStream or a byte array. CLOBs can be in the form of a Reader, InputStream 033 * or String. Each CLOB/BLOB value will be stored together with its length. 034 * The type is based on which constructor is used. Objects of this class are 035 * immutable except for the LobCreator reference. Use them and discard them. 036 * 037 * <p>This class holds a reference to a LocCreator that must be closed after the 038 * update has completed. This is done via a call to the closeLobCreator method. 039 * All handling of the LobCreator is done by the framework classes that use it - 040 * no need to set or close the LobCreator for end users of this class. 041 * 042 * <p>A usage example: 043 * 044 * <pre class="code">JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); // reusable object 045 * LobHandler lobHandler = new DefaultLobHandler(); // reusable object 046 * 047 * jdbcTemplate.update( 048 * "INSERT INTO imagedb (image_name, content, description) VALUES (?, ?, ?)", 049 * new Object[] { 050 * name, 051 * new SqlLobValue(contentStream, contentLength, lobHandler), 052 * new SqlLobValue(description, lobHandler) 053 * }, 054 * new int[] {Types.VARCHAR, Types.BLOB, Types.CLOB}); 055 * </pre> 056 * 057 * @author Thomas Risberg 058 * @author Juergen Hoeller 059 * @since 1.1 060 * @see org.springframework.jdbc.support.lob.LobHandler 061 * @see org.springframework.jdbc.support.lob.LobCreator 062 * @see org.springframework.jdbc.core.JdbcTemplate#update(String, Object[], int[]) 063 * @see org.springframework.jdbc.object.SqlUpdate#update(Object[]) 064 * @see org.springframework.jdbc.object.StoredProcedure#execute(java.util.Map) 065 */ 066public class SqlLobValue implements DisposableSqlTypeValue { 067 068 private final Object content; 069 070 private final int length; 071 072 /** 073 * This contains a reference to the LobCreator - so we can close it 074 * once the update is done. 075 */ 076 private final LobCreator lobCreator; 077 078 079 /** 080 * Create a new BLOB value with the given byte array, 081 * using a DefaultLobHandler. 082 * @param bytes the byte array containing the BLOB value 083 * @see org.springframework.jdbc.support.lob.DefaultLobHandler 084 */ 085 public SqlLobValue(byte[] bytes) { 086 this(bytes, new DefaultLobHandler()); 087 } 088 089 /** 090 * Create a new BLOB value with the given byte array. 091 * @param bytes the byte array containing the BLOB value 092 * @param lobHandler the LobHandler to be used 093 */ 094 public SqlLobValue(byte[] bytes, LobHandler lobHandler) { 095 this.content = bytes; 096 this.length = (bytes != null ? bytes.length : 0); 097 this.lobCreator = lobHandler.getLobCreator(); 098 } 099 100 /** 101 * Create a new CLOB value with the given content string, 102 * using a DefaultLobHandler. 103 * @param content the String containing the CLOB value 104 * @see org.springframework.jdbc.support.lob.DefaultLobHandler 105 */ 106 public SqlLobValue(String content) { 107 this(content, new DefaultLobHandler()); 108 } 109 110 /** 111 * Create a new CLOB value with the given content string. 112 * @param content the String containing the CLOB value 113 * @param lobHandler the LobHandler to be used 114 */ 115 public SqlLobValue(String content, LobHandler lobHandler) { 116 this.content = content; 117 this.length = (content != null ? content.length() : 0); 118 this.lobCreator = lobHandler.getLobCreator(); 119 } 120 121 /** 122 * Create a new BLOB/CLOB value with the given stream, 123 * using a DefaultLobHandler. 124 * @param stream the stream containing the LOB value 125 * @param length the length of the LOB value 126 * @see org.springframework.jdbc.support.lob.DefaultLobHandler 127 */ 128 public SqlLobValue(InputStream stream, int length) { 129 this(stream, length, new DefaultLobHandler()); 130 } 131 132 /** 133 * Create a new BLOB/CLOB value with the given stream. 134 * @param stream the stream containing the LOB value 135 * @param length the length of the LOB value 136 * @param lobHandler the LobHandler to be used 137 */ 138 public SqlLobValue(InputStream stream, int length, LobHandler lobHandler) { 139 this.content = stream; 140 this.length = length; 141 this.lobCreator = lobHandler.getLobCreator(); 142 } 143 144 /** 145 * Create a new CLOB value with the given character stream, 146 * using a DefaultLobHandler. 147 * @param reader the character stream containing the CLOB value 148 * @param length the length of the CLOB value 149 * @see org.springframework.jdbc.support.lob.DefaultLobHandler 150 */ 151 public SqlLobValue(Reader reader, int length) { 152 this(reader, length, new DefaultLobHandler()); 153 } 154 155 /** 156 * Create a new CLOB value with the given character stream. 157 * @param reader the character stream containing the CLOB value 158 * @param length the length of the CLOB value 159 * @param lobHandler the LobHandler to be used 160 */ 161 public SqlLobValue(Reader reader, int length, LobHandler lobHandler) { 162 this.content = reader; 163 this.length = length; 164 this.lobCreator = lobHandler.getLobCreator(); 165 } 166 167 168 /** 169 * Set the specified content via the LobCreator. 170 */ 171 @Override 172 public void setTypeValue(PreparedStatement ps, int paramIndex, int sqlType, String typeName) throws SQLException { 173 if (sqlType == Types.BLOB) { 174 if (this.content instanceof byte[] || this.content == null) { 175 this.lobCreator.setBlobAsBytes(ps, paramIndex, (byte[]) this.content); 176 } 177 else if (this.content instanceof String) { 178 this.lobCreator.setBlobAsBytes(ps, paramIndex, ((String) this.content).getBytes()); 179 } 180 else if (this.content instanceof InputStream) { 181 this.lobCreator.setBlobAsBinaryStream(ps, paramIndex, (InputStream) this.content, this.length); 182 } 183 else { 184 throw new IllegalArgumentException( 185 "Content type [" + this.content.getClass().getName() + "] not supported for BLOB columns"); 186 } 187 } 188 else if (sqlType == Types.CLOB) { 189 if (this.content instanceof String || this.content == null) { 190 this.lobCreator.setClobAsString(ps, paramIndex, (String) this.content); 191 } 192 else if (this.content instanceof InputStream) { 193 this.lobCreator.setClobAsAsciiStream(ps, paramIndex, (InputStream) this.content, this.length); 194 } 195 else if (this.content instanceof Reader) { 196 this.lobCreator.setClobAsCharacterStream(ps, paramIndex, (Reader) this.content, this.length); 197 } 198 else { 199 throw new IllegalArgumentException( 200 "Content type [" + this.content.getClass().getName() + "] not supported for CLOB columns"); 201 } 202 } 203 else { 204 throw new IllegalArgumentException("SqlLobValue only supports SQL types BLOB and CLOB"); 205 } 206 } 207 208 /** 209 * Close the LobCreator, if any. 210 */ 211 @Override 212 public void cleanup() { 213 this.lobCreator.close(); 214 } 215 216}