public T handle (ResultSet resultSet);
pureQuery calls the handle() method to create an object that represents a query result. pureQuery passes the query results to the method in an instance of java.sql.ResultSet. If you are creating an implementation of ResultHandler<RES>, implement this method to create and return an object of type <RES> that represents a query result in the ResultSet instance.
When you specify a handler as a parameter, the parameter must be the last parameter in the method signature. If you specify a ResultHandler together with a ParameterHandler as parameters, the handlers must be the last two parameters in the method signature.
Imagine that an application that queries a data source sends the results of the queries in full as String objects to another application. That other application expects the String to contain a series of objects in the JSON format. You can use the handle() method in the ResultHandler<RES> interface to convert the query results to a single JSON string that represents an array of objects.
package customHandlers;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import com.ibm.pdq.runtime.handlers.ResultHandler;
public class JSONResultHandler implements ResultHandler<String>
{
// The ResultHandler<RES> interface defines this method
public String handle (ResultSet rs)
{
StringBuffer stringBuffer = new StringBuffer ();
try {
ResultSetMetaData resultSetMetaData = rs.getMetaData ();
int columnCount = resultSetMetaData.getColumnCount ();
boolean first = true;
stringBuffer.append ("[");
while (rs.next ()) {
// All row objects, except the last, are followed by a ","
if (!first) stringBuffer.append (",");
first = false;
stringBuffer.append ("{");
for (int x = 1; x <= columnCount; x++) {
stringBuffer.append ("\"");
stringBuffer.append (toJSONString (resultSetMetaData.getColumnLabel (x)));
stringBuffer.append ("\":\"");
stringBuffer.append (toJSONString (rs.getString (x)));
stringBuffer.append ("\"");
if (x < columnCount) stringBuffer.append (",");
}
stringBuffer.append ("}");
}
stringBuffer.append ("]");
}
catch (SQLException e) {
throw new RuntimeException ("The JSONResultHandler failed to create a JSON string from the query results.", e);
}
return stringBuffer.toString ();
}
private String toJSONString (String value)
{
if (value != null) {
int valueLength = value.length ();
StringBuffer sb = new StringBuffer (valueLength);
for (int i = 0; i < valueLength; i++) {
char c = value.charAt (i);
switch (c) {
case '\\':
sb.append ("\\\\");
break;
case '"':
sb.append ("\\\"");
break;
case '/':
sb.append ("\\/");
break;
case 0x08:
sb.append ("\\b");
break;
case 0xC:
sb.append ("\\f");
break;
case 0xA:
sb.append ("\\n");
break;
case 0xD:
sb.append ("\\r");
break;
case 0x9:
sb.append ("\\t");
break;
default:
sb.append (c);
break;
}
}
return sb.toString ();
}
else
return null;
}
}
Here is an example of a JSON string that the JSONResultHandler could produce:
[{"DEPTNO":"A00","DEPTNAME":"SPIFFY COMPUTER SERVICE DIV.","MGRNO":"000010","ADMRDEPT":"A00","LOCATION":"null"},
{"DEPTNO":"B01","DEPTNAME":"PLANNING","MGRNO":"000020",
"ADMRDEPT":"A00","LOCATION":"null"},...]
There are two ways in which you can specify ResultHandler objects for annotated methods.
@Select(sql = “select * from employee where workdept = ?1.departmentNumber")
@Handler(resultHandler = customHandlers.JSONResultHandler.class)
String toJSON(DepartmentBean department);
When you specify a handler as a parameter, the parameter must be the last parameter in the method signature.
For example, suppose you wanted to get the results of your query in an Iterator<EmployeeBean>, and that you only wanted the Iterator<EmployeeBean> to contain rows 11 through 20 of the results. You could use the com.ibm.pdq.runtime.data.handlers.IteratorPagingResultHandler<RES>. In an interface, you could define an annotated method that takes an instance of IteratorPagingResultHandler<RES> as a parameter.
@Select(sql = "select * from employee where workdept = ?1.departmentNumber")
Iterator<EmployeeBean> selectEmployeesInDepartment(DepartmentBean department, IteratorPagingResultHandler resultHandler);
If you wanted to get rows 11 through 20 of the results, you could invoke the method like this:
// Execute the query and create an iterator for rows 11-20
Iterator<EmployeeBean> employees = face.selectEmployeesInDepartment(theDepartment, new IteratorPagingResultHandler(EmployeeBean.class, 11, 20));
If you wanted to use a single annotated method declaration with multiple ResultHandler<RES> implementations, you could define an annotated method that uses the generic ResultHandler<RES> in the signature:
@Select(sql = "select * from employee where workdept = ?1.departmentNumber")
<RES> RES selectEmployeesInDepartment(DepartmentBean department, ResultHandler<RES> resultHandler);
You could then invoke the method by passing a ResultHandler object of a specific type:
Iterator<EmployeeBean> employee = face.selectEmployeesInDepartment(theDepartment, new IteratorPagingResultHandler(EmployeeBean.class, 11, 20));
Connection con = DriverManager.getConnection(...);
Data d = DataFactory.getData(con);
// Execute the query and create an iterator for rows 11-20
Iterator<EmployeeBean> employees = d.query("select * from employee where workdept = ?1.departmentNumber",
theDepartment, new IteratorPagingResultHandler(EmployeeBean.class,11, 20));