Hibernate createNativeQuery, возвращающий объект Proxy для Clob
Я вынужден оказаться в ситуации, когда я использую hibernate createNativeQuery для возврата массивов списка объектов.
Одним из (многих) столбцов, из которых мой запрос возвращает значения, является CLOB.
Объект, который возвращается, является объектом com.sun.Proxy.
Я видел вопрос здесь, где
getClass().getInterfaces()
был использован для определения того, что это возвращаемый WrappedClob.
Однако, учитывая, что у меня теперь есть этот прокси-объект в моем коде Java, как мне преобразовать его во что-то полезное... как строку?
4 ответа
Следующий код помог снять прокси с прокола
Ссылка, которая мне поможет, просто добавьте немного кода в код:D
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Clob;
import java.sql.SQLException;
/**
* Unproxy clob.
*
* @param proxy the proxy
* @return the string
* @throws InvocationTargetException the invocation target exception
* @throws IntrospectionException the introspection exception
* @throws IllegalAccessException the illegal access exception
* @throws SQLException the SQL exception
* @throws IOException Signals that an I/O exception has occurred.
*/
public static String unproxyClob(Object proxy)
throws InvocationTargetException, IntrospectionException, IllegalAccessException, SQLException, IOException {
try {
BeanInfo beanInfo = Introspector.getBeanInfo(proxy.getClass());
for (PropertyDescriptor property : beanInfo.getPropertyDescriptors()) {
Method readMethod = property.getReadMethod();
if (readMethod.getName().contains(GET_WRAPPED_CLOB)) {
Object result = readMethod.invoke(proxy);
return clobToString((Clob) result);
}
}
} catch (InvocationTargetException | IntrospectionException | IllegalAccessException | SQLException | IOException exception) {
LOGGER.fatal(exception);
throw exception;
}
return null;
}
/**
* Clob to string.
*
* @param data the data
* @return the string
* @throws SQLException the SQL exception
* @throws IOException Signals that an I/O exception has occurred.
*/
public static String clobToString(Clob data) throws SQLException, IOException {
StringBuilder sb = new StringBuilder();
Reader reader = data.getCharacterStream();
BufferedReader br = new BufferedReader(reader);
String line;
while (null != (line = br.readLine())) {
sb.append(line);
}
br.close();
return sb.toString();
}
У меня другое решение:
public void getResult(){
String sql = "your sql";
Query query = entityManager.createNativeQuery(sql);
List<Object[]> resultList = query.getResultList();
for (Object[] obj : resultList) {
StringUtil.convertToString((Clob)obj[0]);
}
}
public static String convertToString(Clob clob) {
Reader reader = null;
BufferedReader bufferedReader = null;
try {
reader = clob.getCharacterStream();
bufferedReader = new BufferedReader(reader);
return IOUtils.toString(bufferedReader);
} catch (Exception e) {
throw new RuntimeException("Error while reading String from CLOB", e);
} finally {
IOUtils.closeQuietly(reader);
IOUtils.closeQuietly(bufferedReader);
}
}
Вы можете попробовать этот код. Возможно, он не идеален, но он работает для меня:) Я использую его для преобразования обычного clob в строку, поэтому он также должен работать, если вы разворачиваете объект clob с помощью getWrappedClob()
Clob clob = wrappedClob.getWrappedClob();
String result = null;
Long length = clob.length();
char[] char_array = new char[length.intValue()];
Reader characterStream = clob.getCharacterStream();
try {
int read = characterStream.read(char_array, 0, length.intValue());
result = new String(char_array);
} catch (IOException e) {
log.error("Exception during read from CLOB: " + e);
}
Это не прямой ответ на вопрос ОП, так как мне не приходилось иметь дело с экземпляром «WrappedClob». Но поскольку я все еще получаю то же вводящее в заблуждение сообщение об ошибке, я надеюсь, что кто-то найдет это полезным:
Проблема для меня заключалась в том, что реализация спящего режима «Clob to String» для H2 и Postgres не вела себя одинаково. Таким образом, хотя мои тесты работали нормально, приложение вылетало во время выполнения. Чтобы обойти это, я создал разные bean-компоненты ClobReader в разных средах. В производственной среде будет использоваться реализация bean-компонента для Postgres, а в тестовом коде используется bean-компонент H2.
public interface ClobReader {
String clobToString(Object clob) throws SQLException, IOException;
}
@Bean
public ClobReader clobReaderPostgres() {
return new ClobReader() {
@Override
public String clobToString(final Object clob) {
if (clob == null) {
return null;
}
return clob.toString();
}
};
}
@Bean
@Primary
public ClobReader clobReaderH2() {
return new ClobReader() {
@Override
public String clobToString(final Object obj) throws SQLException, IOException {
final Clob clob = (Clob) obj;
try (final Reader reader = clob.getCharacterStream()) {
try (final StringWriter stringWriter = new StringWriter()) {
IOUtils.copy(reader, stringWriter);
return stringWriter.toString();
}
}
}
};
}