DATAJPA-506 - Add support for conversion of Blob values to byte[] in native queries.

JpaQueryExecution no applies type conversion for Blob instances to be able to return byte[] from repository calls.

Original pull request: #72.
This commit is contained in:
Thomas Darimont
2014-05-16 17:09:06 +02:00
committed by Oliver Gierke
parent af45da40c6
commit 68e2ee5ed9
4 changed files with 133 additions and 1 deletions

View File

@@ -24,6 +24,7 @@ import javax.persistence.Query;
import javax.persistence.StoredProcedureQuery;
import javax.persistence.TypedQuery;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
@@ -43,6 +44,12 @@ import org.springframework.util.Assert;
*/
public abstract class JpaQueryExecution {
private static final DefaultConversionService conversionService = new DefaultConversionService();
static {
conversionService.addConverter(JpaResultConverters.BlobToByteArrayConverter.INSTANCE);
}
/**
* Executes the given {@link AbstractStringBasedJpaQuery} with the given {@link ParameterBinder}.
*
@@ -55,11 +62,26 @@ public abstract class JpaQueryExecution {
Assert.notNull(query);
Assert.notNull(values);
Object result;
try {
return doExecute(query, values);
result = doExecute(query, values);
} catch (NoResultException e) {
return null;
}
if (result == null) {
return null;
}
JpaQueryMethod queryMethod = query.getQueryMethod();
Class<?> requiredType = queryMethod.getReturnType();
if (void.class.equals(requiredType) || requiredType.isAssignableFrom(result.getClass())) {
return result;
}
return conversionService.convert(result, requiredType);
}
/**

View File

@@ -0,0 +1,87 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.jpa.repository.query;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Blob;
import java.sql.SQLException;
import org.springframework.core.convert.converter.Converter;
import org.springframework.dao.CleanupFailureDataAccessException;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.util.StreamUtils;
/**
* Container for additional JPA result {@link Converter}s.
*
* @author Thomas Darimont
* @since 1.6
*/
class JpaResultConverters {
/**
* {@code private} to prevent instantiation.
*/
private JpaResultConverters() {}
/**
* Converts the given {@link Blob} into a {@code byte[]}.
*
* @author Thomas Darimont
*/
enum BlobToByteArrayConverter implements Converter<Blob, byte[]> {
INSTANCE;
@Override
public byte[] convert(Blob source) {
if (source == null) {
return null;
}
InputStream blobStream = null;
try {
blobStream = source.getBinaryStream();
if (blobStream != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
StreamUtils.copy(blobStream, baos);
return baos.toByteArray();
}
} catch (SQLException e) {
throw new DataRetrievalFailureException("Couldn't retrieve data from blob.", e);
} catch (IOException e) {
throw new DataRetrievalFailureException("Couldn't retrieve data from blob.", e);
} finally {
if (blobStream != null) {
try {
blobStream.close();
} catch (IOException e) {
throw new CleanupFailureDataAccessException("Couldn't close binary stream for given blob.", e);
}
}
}
return null;
}
}
}

View File

@@ -1390,6 +1390,23 @@ public class UserRepositoryTests {
flushTestUsers();
byte[] result = null; // repository.findBinaryDataByIdJpaQl(firstUser.getId());
assertThat(result.length, is(data.length));
assertThat(result, is(data));
}
/**
* @see DATAJPA-506
*/
@Test
public void findBinaryDataByIdNative() throws Exception {
byte[] data = "Woho!!".getBytes("UTF-8");
firstUser.setBinaryData(data);
flushTestUsers();
byte[] result = repository.findBinaryDataByIdNative(firstUser.getId());
assertThat(result.length, is(data.length));
assertThat(result, is(data));
}

View File

@@ -445,4 +445,10 @@ public interface UserRepository extends JpaRepository<User, Integer>, JpaSpecifi
* @see DATAJPA-551
*/
Slice<User> findTop2UsersBy(Pageable page);
/**
* @see DATAJPA-506
*/
@Query(value = "select u.binaryData from User u where u.id = ?", nativeQuery = true)
byte[] findBinaryDataByIdNative(Integer id);
}