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