4

I am forced into a situation where i am using hibernate createNativeQuery to return a List of Objects arrays.

One of the (many) columns from which my query returns values is a CLOB.

The Object which is returned is com.sun.Proxy object.

I have seen a question here where

getClass().getInterfaces()

was used to identify that it is a WrappedClob being returned.

However given that I now have this proxy object in my Java code, how do I convert it into something useful ... like a String?

Community
  • 1
  • 1
p45
  • 131
  • 1
  • 3
  • 11

4 Answers4

8

The following code helped to unProxy the clob

Link which help me, just add a bit of makeup to the code :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();
        }
Anupam
  • 509
  • 1
  • 6
  • 16
1

I have a diferent solution:

    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);
        }
    }
Eduardo
  • 11
  • 1
0

You can try this code. Probably it is not perfect, but it works for me :) I'm using it to convert regular clob to string so it should also work if you unwrap clob object with 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);
}
mrh
  • 917
  • 1
  • 9
  • 28
0

This is not a direct answer to OP’s question, as I did not have to deal with an Instance of ‘WrappedClob’. But as I still got the same misleading error message, I hope someone finds this useful:

The problem for me was, that hibernates implementation of ‘Clob to String’ for H2 and Postgres did not behave the same way. So, while my tests worked fine, the application would crash at runtime. To work around this, I instantiated different beans of ClobReader in different environments. The production environment would us the bean implementation for Postgres, while the test code uses the H2 bean.

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();
                }
            }
        }
    };
}
Jonas_Hess
  • 1,874
  • 1
  • 22
  • 32