Typed Reference Cursor of Collection

Demonstration of using user defined typed collections as result set of a typed cursor.

Example Description

  • A cursor element must be of type PL/SQL Record.
  • Any attribute of the PL/SQL Record can define an user defined type.
  • If the PL/SQL Record defines only one attribute the result cursor will be a Java list of objects defined by the user defined type.
  • If the PL/SQL Record defines more than one attribute the result cursor will be a Java list of transfer objects defined from the PL/SQL Record. The user defined type attribute of the PL/SQL Record will be transfer object corresponding to the user defined type.
  • If the user defined type collection the result of the typed cursor is a Java List of Java List.

Object Definition

The user defined type 'REFCUR_OBJECT' is used as collection element.
PL/SQL Package Specification : REFCUR_OBJECT
/**
 * REFCUR_OBJECT for typed ref cursor examples.
 */
create or replace type refcur_object force as object (
  n           number(9),
  v           varchar2(100)
);

Collection Definition

The user defined type 'REFCUR_COLLECTION' is used as cursor element.
PL/SQL Package Specification : REFCUR_COLLECTION
/**
 * REFCUR_COLLECTION for typed ref cursor examples.
 */
create or replace type refcur_collection force as table of refcur_object;

Package Specification

PL/SQL Package Specification : TYPED_REF_CURSOR_COLLECTION
create or replace package TYPED_REF_CURSOR_COLLECTION
/**
 * Typed Ref Cursor of Collection Demo.
 */
as

-- this type of PL/SQL record will be treated as list of object/transfer object value
type rec_refcur_collection is record (
  o   refcur_collection
);

-- this typed ref cursor represents a list of list of object/transfer object values
type c_refcur_collection is ref cursor return rec_refcur_collection;

-- this type of PL/SQL record will be treated as object/transfer object value
type rec_refcur_collection_mixed is record (
  ts            timestamp,
  row_number_id number,
  refcur_list   refcur_collection
);

-- this typed ref cursor represents a list of transfer objects containing a list element
type c_refcur_collection_mixed is ref cursor return rec_refcur_collection_mixed;

/**
 * Return a list of list of objects/transfer objects.
 *
 * @return List of list of objects/transfer objects.
 */
function get_refcur_collection(i_number_of_rows in number) return c_refcur_collection;

/**
 * Return a list of pl/sql records/transfer objects including a list of objects.
 *
 * @return List of pl/sql records/transfer objects including a list of objects.
 */
function get_refcur_collection_mixed(i_number_of_rows in number) return c_refcur_collection_mixed;

end TYPED_REF_CURSOR_COLLECTION;

Package Body

PL/SQL Package Specification : TYPED_REF_CURSOR_COLLECTION
create or replace package body TYPED_REF_CURSOR_COLLECTION
as

/**
 * Return a list of list of objects/transfer objects.
 *
 * @return List of list of objects/transfer objects.
 */
function get_refcur_collection(i_number_of_rows in number) return c_refcur_collection
is
  c c_refcur_collection;
begin
  open c for
    with row_number_id as 
      (select rownum id from dual connect by level<=i_number_of_rows)
    select  cast(multiset(select refcur_object(row_number_id.id, 'element refcur_object no. ' || rownum)
                            from dual
                            connect by level<=i_number_of_rows) as refcur_collection)
      from  row_number_id;

  return c;
end get_refcur_collection;

/**
 * Return a list of pl/sql records/transfer objects including a list of objects.
 *
 * @return List of pl/sql records/transfer objects including a list of objects.
 */
function get_refcur_collection_mixed(i_number_of_rows in number) return c_refcur_collection_mixed
is
  c c_refcur_collection_mixed;
begin
  open c for
    with row_number_id as 
      (select rownum id, (systimestamp+rownum*123.456) ts from dual connect by level<=i_number_of_rows)
    select  row_number_id.ts,
            row_number_id.id,
            cast(multiset(select refcur_object(row_number_id.id, 'element refcur_object no. ' || rownum)
                            from dual
                            connect by level<=i_number_of_rows) as refcur_collection)
      from  row_number_id;

  return c;
end get_refcur_collection_mixed;

end TYPED_REF_CURSOR_COLLECTION;

Factory API : Calling the PL/SQL package

Using the static factory to get the remote service.
Java Calling Class : TypedRefCursorCollectionFactoryApi.java
package plsql_workbench_examples.factoryapi;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

import factory.ExamplesRPCFactory;
import service.TypedRefCursorCollectionService;
import transferobject.RefcurObject;
import transferobject.TypedRefCursorCollectionTO;
import transferobject.TypedRefCursorCollectionTO.RecRefcurCollectionMixed;

public class TypedRefCursorCollectionFactoryApi {
  public static void main(String[] args)
  {
    try {
      // set database credentials and configuration parameters
      System.setProperty("dbw_examples.url", "jdbc:oracle:thin:@192.168.0.109:1521/orcl");
      System.setProperty("dbw_examples.username", "dbw_examples");
      System.setProperty("dbw_examples.password", "dbw_examples");

      // get the service
      TypedRefCursorCollectionService service = ExamplesRPCFactory.getTypedRefCursorCollectionService();

      // call the stored procedure and receive a list of list as result
      List<List<RefcurObject>> listOfList;
      listOfList = service.getRefcurCollection(ThreadLocalRandom.current().nextInt(2, 8), 0);

      // print information
      int row = 1;
      for (List<RefcurObject> list : listOfList) {
        System.out.println("row:" + (row++));
        for (RefcurObject obj : list) {
          System.out.format("element RefcurObject[n:%s, v:'%s']%n", obj.n, obj.v);
        }
      }

      // call the stored procedure and receive a list of PL/SQL record/transfer objects containing a collection/list
      List<TypedRefCursorCollectionTO.RecRefcurCollectionMixed> mixedList;
      mixedList = service.getRefcurCollectionMixed(ThreadLocalRandom.current().nextInt(2, 8), 0);

      // print information
      for (RecRefcurCollectionMixed mixedElement : mixedList) {
        System.out.format("row element [id:%s, ts:%s]%n", mixedElement.rowNumberId, mixedElement.ts);
        for (RefcurObject obj : mixedElement.refcurList) {
          System.out.format("\tlist element RefcurObject[n:%s, v:'%s']%n", obj.n, obj.v);
        }
      }
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
}

Spring API : Calling the PL/SQL package

Using Spring annotation to inject the service and call the remote service.
Java Calling Class : TypedRefCursorCollectionSpringApi.java
package plsql_workbench_examples.springapi;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.stereotype.Component;

import service.TypedRefCursorCollectionService;
import transferobject.RefcurObject;
import transferobject.TypedRefCursorCollectionTO;
import transferobject.TypedRefCursorCollectionTO.RecRefcurCollectionMixed;

@Component
public class TypedRefCursorCollectionSpringApi {
  @Autowired
  private TypedRefCursorCollectionService typedRefCursorCollectionService;

  public static void main(String[] args)
  {
    // set database credentials and configuration parameters
    System.setProperty("dbw_examples.url", "jdbc:oracle:thin:@192.168.0.109:1521/orcl");
    System.setProperty("dbw_examples.username", "dbw_examples");
    System.setProperty("dbw_examples.password", "dbw_examples");

    // Register Spring Beans, Spring Context and call demo method 
    try (GenericApplicationContext ctx = BaseSpringConfig.getCtx(TypedRefCursorCollectionSpringApi.class)) {
      ctx.getBean(TypedRefCursorCollectionSpringApi.class).runDemo();
    }
  }

  private void runDemo()
  {
    try {
      // call the stored procedure and receive a list of list as result
      List<List<RefcurObject>> listOfList;
      listOfList = typedRefCursorCollectionService.getRefcurCollection(ThreadLocalRandom.current().nextInt(2, 8), 0);

      // print information
      int row = 1;
      for (List<RefcurObject> list : listOfList) {
        System.out.println("row:" + (row++));
        for (RefcurObject obj : list) {
          System.out.format("element RefcurObject[n:%s, v:'%s']%n", obj.getN(), obj.getV());
        }
      }

      // call the stored procedure and receive a list of PL/SQL record/transfer objects containing a collection/list
      List<TypedRefCursorCollectionTO.RecRefcurCollectionMixed> mixedList;
      mixedList = typedRefCursorCollectionService.getRefcurCollectionMixed(ThreadLocalRandom.current().nextInt(2, 8),
                                                                           0);

      // print information
      for (RecRefcurCollectionMixed mixedElement : mixedList) {
        System.out.format("row element [id:%s, ts:%s]%n", mixedElement.getRowNumberId(), mixedElement.getTs());
        for (RefcurObject obj : mixedElement.getRefcurList()) {
          System.out.format("\tlist element RefcurObject[n:%s, v:'%s']%n", obj.getN(), obj.getV());
        }
      }
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }
}