Ibatis(Oracle) recuperar un cursor desde un procedure

Estoy intentando hacer un pequeño ejemplo para recuperar con ibatis desde java un cursor de un procedimiento de oracle, pero no consigo que funcione, mi ejemplo es el siguiente:
Mi procedimiento:
create or replace procedure "PRUEBAS".datos_empleados
  (
  Par1 IN VARCHAR2,
cursor1 OUT empleados_pkg.empleados_type
  )
AS
Begin
  /* tiene valor par1 */
  IF par1 IS NOT NULL
  THEN
   OPEN cursor1 FOR
    SELECT * FROM EMPLOYEES
    WHERE NAME = par1;
  /* no tiene valor */
  ELSE
     OPEN cursor1 FOR
    SELECT * FROM EMPLOYEES;
  END IF;
END datos_empleados;
Mi sqlMap:
    PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
    "http://ibatis.apache.org/dtd/sql-map-2.dtd">
          {call datos_empleados(?,?)}
Mi forma de llamarlo desde java:
private static final String NAME_SPACE_cursor     = "certificadosCursor.";
private static final String GET_CERTIF_MYLISTCURSOR_NIF     = "getMiListaNifCursor";
            Map map = new HashMap(1);
            System.out.println("getMiListaNifCursor: "+theNombre);
            map.put(MAP_par1,theNombre);
            sqlMapClient.queryForList(NAME_SPACE_cursor+GET_CERTIF_MYLISTCURSOR_NIF,map);    
            emps =  (ArrayList)map.get("cursor1");
            System.out.println("emps: "+emps);
El error que saca es:
Constructor CertificacionesBO
Trying to load ibatis configuration file maps/sql-map-config-certificados.xml
Ibatis Configuration loaded
GetMiListaNifCursor: angel
SQLException getMiListaNifCursor
Capturada SQLException:
--- The error occurred in maps/certificadosCursor.xml.
--- The error occurred while applying a parameter map.  
--- Check the certificadosCursor. NifPar.
--- Check the output parameters (retrieval of output parameters failed).
--- Cause: java. Lang. NullPointerException
com.ibatis.common.jdbc.exception.NestedSQLException:   
--- The error occurred in maps/certificadosCursor.xml.  
--- The error occurred while applying a parameter map.  
--- Check the certificadosCursor. NifPar.
--- Check the output parameters (retrieval of output parameters failed).
--- Cause: java. Lang. NullPointerException
Caused by: java. Lang. NullPointerException
    At com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback(GeneralStatement.java:188)
    At com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryForList(GeneralStatement.java:123)
    At com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExecutorDelegate.java:610)
    At com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExecutorDelegate.java:584)
    At com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForList(SqlMapSessionImpl.java:101)
    At com.ibatis.sqlmap.engine.impl.SqlMapClientImpl.queryForList(SqlMapClientImpl.java:78)
    At com.dao.certificados.CertificadosIbatisDAO.getMiListaNifCursor(CertificadosIbatisDAO.java:80)
    At com.bo.certificados.CertificacionesBO.getMiListaNifCursor(CertificacionesBO.java:48)
    At main. CertificadosCursor.main(CertificadosCursor.java:29)
Caused by: java. Lang. NullPointerException
    At com.ibatis.sqlmap.engine.execution.SqlExecutor.retrieveOutputParameters(SqlExecutor.java:354)
    At com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQueryProcedure(SqlExecutor.java:301)
    At com.ibatis.sqlmap.engine.mapping.statement.ProcedureStatement.sqlExecuteQuery(ProcedureStatement.java:34)
    At com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback(GeneralStatement.java:173)
    ... 8 more
Caused by:
java. Lang. NullPointerException
    At com.ibatis.sqlmap.engine.execution.SqlExecutor.retrieveOutputParameters(SqlExecutor.java:354)
    At com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQueryProcedure(SqlExecutor.java:301)
    At com.ibatis.sqlmap.engine.mapping.statement.ProcedureStatement.sqlExecuteQuery(ProcedureStatement.java:34)
    At com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback(GeneralStatement.java:173)
    At com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryForList(GeneralStatement.java:123)
    At com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExecutorDelegate.java:610)
    At com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExecutorDelegate.java:584)
    At com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForList(SqlMapSessionImpl.java:101)
    At com.ibatis.sqlmap.engine.impl.SqlMapClientImpl.queryForList(SqlMapClientImpl.java:78)
    At com.dao.certificados.CertificadosIbatisDAO.getMiListaNifCursor(CertificadosIbatisDAO.java:80)
    At com.bo.certificados.CertificacionesBO.getMiListaNifCursor(CertificacionesBO.java:48)
    At main. CertificadosCursor.main(CertificadosCursor.java:29)
Caused by:
java. Lang. NullPointerException
    At com.ibatis.sqlmap.engine.execution.SqlExecutor.retrieveOutputParameters(SqlExecutor.java:354)
    At com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQueryProcedure(SqlExecutor.java:301)
    At com.ibatis.sqlmap.engine.mapping.statement.ProcedureStatement.sqlExecuteQuery(ProcedureStatement.java:34)
    At com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback(GeneralStatement.java:173)
    At com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryForList(GeneralStatement.java:123)
    At com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExecutorDelegate.java:610)
    At com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExecutorDelegate.java:584)
    At com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForList(SqlMapSessionImpl.java:101)
    At com.ibatis.sqlmap.engine.impl.SqlMapClientImpl.queryForList(SqlMapClientImpl.java:78)
    At com.dao.certificados.CertificadosIbatisDAO.getMiListaNifCursor(CertificadosIbatisDAO.java:80)
    At com.bo.certificados.CertificacionesBO.getMiListaNifCursor(CertificacionesBO.java:48)
    At...

2 respuestas

Respuesta
1
Por lo que parece, faltan datos en el xml de mapeo y no sabe como mapear las columnas que obtiene el cursor, podrías por favor pegar el contenido del xml que está mapeando y la declaración de empleados_pkg. empleados_type?
Por otra parte estoy observando, que no estas llamando desde java a "PRUEBAS".datos_empleados aunque supongo que es porque tendrás el mapeo de esa manera deberías revisar y evitar llamar a métodos por otro nombre. Una prueba que podrías realizar es hacer la llamada desde JDBC a pelo, para saber si el problema es de la config de iBatis (tiene toda la pinta) o de la llamada/parámetros , aquí te dejo un ejemplo:
String query = "begin ? := "PRUEBAS".datos_empleados(?,?); end;";
CallableStatement stmt = conn.prepareCall(query);
stmt.setString(1, "Nombre");
stmt.registerOutParameter(2, OracleTypes.CURSOR);
stmt.execute();
ResultSet rs = (ResultSet)stmt.getObject(2);
while (rs.next()) {
    //Pos 1 -> ID, Pos2 -> FIRST_NAME, Pos 3 -> LAST_NAME
    System.out.println(rs.getString(2) + "\t" +
        rs.getString(3) + "\t");
}
Si estas usando la tabla EMPLOYEES de HR, la columna NAME no existe, es o bien FIRST_NAME, o LAST_NAME... y si no me pones los xml de iBatis no sé en qué más ayudarte :)
Primeramente perdón por la repetición de la pregunta, y gracias por contestar.
Parece que se ha cortado el mapeo es el siguiente:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap
    PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
    "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="certificadosCursor" >
    <resultMap id="result4" class="com.bo.certificados.Employee">
          <result property="id" column="ID"/>
          <result property="name" column="NAME"/>
    </resultMap>
<parameterMap id="nifPar" class="java.util.Map">
<parameter property="par1" mode="IN" jdbcType="VARCHAR" javaType="java.lang.String"/>
<parameter property="cursor1" mode="OUT" jdbcType="ORACLECURSOR" javaType="java.sql.ResultSet" />
    </parameterMap>    
      <!-- getMiListaNif -->
<procedure id="getMiListaNifCursor" resultMap="result4" parameterMap="nifPar" >
          {call datos_empleados(?,?)}
      </procedure>
</sqlMap>
la declaración de empleados_pkg.empleados_type supongo que te refieres a esto:
create or replace package "PRUEBAS".empleados_pkg
IS
  /* Definición del REF CURSOR type */
  TYPE empleados_type IS REF CURSOR
  RETURN EMPLOYEES%ROWTYPE;
END empleados_pkg;
Voy a probar lo que me dices aunque creo que el error es del mapeo de ibatis. Gracias.
Vale, hagamos una cosa.
Prueba el ejemplo de esta página http://www.it-eye.nl/weblog/2008/07/16/using-ibatis-with-a-stored-function-returning-a-ref-cursor/
En vez de usar el cursor como un parámetro de salida, haz que el procedure lo devuelva. Quizás a la hora de usar el mapa de parámetros al no estar "cursor1" en éste y devolver un null, es cuando pega el casque :)
Hazme saber como va progresando.
He intentado hacer el ejemplo de esa página pero no consigo que me cargue el mapeo correctamente, me dice java.lang.NullPointerException: Ibatis Locator not initialized
El mapeo del ejemplo que me has dicho, adaptado a mi caso puesto que yo solo tengo en la tabla "employees" dos columnas ID, NAME.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap
    PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
    "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="certificadosCursor" >
    <resultMap id="result3" class="com.bo.certificados.Employee">
          <result property="id" column="ID"/>
          <result property="name" column="NAME"/>
    </resultMap>
<parameterMap id="parameters3" class="java.util.Map">
<parameter property="employees" javaType="java.sql.ResultSet" jdbcType="ORACLECURSOR" mode="OUT" resultMap="result3"/>
<parameter property="name" jdbcType="VARCHAR" javaType="java.lang.String" mode="IN"/>
    </parameterMap>
<procedure id="getMiListaNifCursor" parameterMap="parameters3" >
        < ![CDATA[
               { ? = call employee_pkg.find_employees_rc(?) }
        ]]>
      </procedure>
</sqlMap>
Me estoy volviendo loco con esto... gracias
¿Puedes ponerme la traza completa del error
Esto es lo que devuelve por consola:
Constructor CertificacionesBO
Trying to load ibatis configuration file maps/sql-map-config-certificados.xml
Exception in thread "main" java.lang.NullPointerException: Ibatis Locator not initialized
    at com.dao.certificados.IbatisLocatorCertificados.getSqlMapClient(IbatisLocatorCertificados.java:76)
    at com.dao.certificados.CertificadosIbatisDAO.<init>(CertificadosIbatisDAO.java:35)
    at com.dao.certificados.DAOFactory.getCertificadoDAO(DAOFactory.java:19)
    at com.bo.certificados.CertificacionesBO.getMiListaNifCursor(CertificacionesBO.java:44)
    at main.CertificadosCursor.main(CertificadosCursor.java:29)
¿Y me puedes pegar el código de CertificadosIbatisDao.java? :)
Parece que el error que te da es del código y no de la configuración.
Supongo que habrás empezado hace poco con iBatis y yo la verdad es que en frameworks de persistencia solo he tocado Hibernate. Quizás podrías mirarte este tutorial http://svn.apache.org/repos/asf/ibatis/java/ibatis-2/trunk/ibatis-2-docs/es/iBATIS-SqlMaps-2-Tutorial_es.pdf a lo mejor te sirve algo. Y si tienes algún problema busca en las mailing-lists de la página del proyecto de iBatis http://www.mail-archive.com/[email protected]/
Siento no poder ayudarte más, pero he hecho todo lo que estaba en mi mano :)
Saludos, y si tienes más dudas no dudes en preguntar
Muchas gracias por la ayuda.
El código de CertificadosIbatisDao esta bien puesto que mapeandolo sin el cursor me funciona.Con ibatis no llevo mucho pero anteriormente lo había configurado para sql server, pero parece que para Oracle es de otra manera y lo necesito para Oracle...
El ejemplo que viene en el tutorial que me has dicho ya le hice, mi problema era que eso solo devolvía un registro y yo necesito que me devuelvan varios, lo he adaptado pero no devuelve nada, esto sería lo que echo, mapeo:
<select id="getPerson2" parameterClass="java.lang.String" resultClass="examples.domain.Person">
SELECT
PER_ID as id,
PER_FIRST_NAME as firstName,
PER_LAST_NAME as lastName,
PER_BIRTH_DATE as birthDate,
PER_WEIGHT_KG as weightInKilograms,
PER_HEIGHT_M as heightInMeters
FROM PERSON
WHERE PER_FIRST_NAME = #firstName#
</select>
llamada desde java:
            SqlMapClient sqlMap = MyAppSqlConfig.getSqlMapInstance();
            List lista = (List) sqlMap.queryForList ("getPerson2", "A%");
            System.out.println("lista.size(: "+lista.size());
Lista. ¿size() devuelve 0
alguna idea? Sino no pasa nada.
Muchas gracias por tu interés y tu tiempo
Muchas gracias por tu interés al final lo tuve que hacer con select y updates sencillos sin cursores.
De todas maneras gracias por tu tiempo.
Respuesta
Teniendo en cuenta que no tengo ni idea de lo que es IBATIS (me informare)
La forma de usar cursores con parametros que yo he usado siempre no tiene la misma sintaxis que el tuyo
    OPEN cursor1 FOR
    SELECT * FROM EMPLOYEES
    WHERE NAME = par1
yo lo pondria así
    OPEN cursor1 FOR
    SELECT * FROM EMPLOYEES
    WHERE NAME = ? using par1
Espero te sirva pero vamos... ibatis ibatis...
Suerte

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas