Eliminate tedious programming: Recover data with XML and Reflection - JavaWorld November
2000
Tutorial Details:
Eliminate tedious programming: Recover data with XML and Reflection
Eliminate tedious programming: Recover data with XML and Reflection
By: By Abhilash Koneri
Automate ResultSet parsing using XML and Reflection
nterprise data consists of various types of functional information, such as product specifications, vendor details, invoices, and sales orders. Whether this data is critical or not, its persistence should not be compromised in any enterprise application. Because of their robustness and proven history tackling persistence, relational databases often persist enterprise data. Thus, data retrieval from a relational database is an integral task for any middleware application. Java's Enterprise JavaBeans architecture is fast becoming the most obvious choice for developing robust middleware applications. The JDBC API facilitates an application layer that performs the data retrieval. This data-access layer translates, or maps, the data in the database entities -- rows, columns, and tables -- into instances of Java classes. In this article, I will demonstrate how to establish the mapping between the database entities and Java classes through XML. I will also use XML to show you how you can rid yourself of certain mundane steps involved in data retrieval.
Typical data retrieval
Simple value-holder classes -- popularly called value classes -- encapsulate functional data in Java. Typically, such classes are made up of one or more private fields and their get() and set() accessor methods. Each field maps to one of the data entities in the database. A simple data retrieval will involve:
Writing the appropriate fetch statement (in SQL)
Executing the fetch statement on an open database connection
Parsing the returned ResultSet
Creating value objects for each row retrieved and adding to a collection that is returned
Although the JDBC API provides powerful support for each of the above steps, it cannot completely eliminate them. Hence, developers end up writing repetitious and functionally similar pieces of code; writing the SQL is the only imaginative part of data retrieval. By purging this task's mundane code, object-relational mapping tools can keep programming somewhat interesting. But, for simple data retrieval, the same benefits can be realized using XML and Reflection.
Sample implementation
Let's assume this standard example: Our employee database features columns such as EMPLOYEE_FIRST_NAME , EMPLOYEE_LAST_NAME , EMPLOYEE_NUMBER , and so on. An EmployeeInfo class with the corresponding fields below encapsulates the employee information:
public class EmployeeInfo
{
private String employeeNumber;
private String employeeFirstName;
private String employeeLastName;
private int employeeExperience;
private Timestamp employeeDOB;
private String employeeEmail;
private Timestamp employeeDOJ;
public String getEmployeeNumber()
{
return this.employeeNumber;
}
.
.
public void setEmployeeNumber(String employeeNumber)
{
this.employeeNumber=employeeNumber;
}
.
.
.
.
}
Now, let's assume that some business functionality requires employee objects to be fetched from the relational database. Typical code that creates the EmployeeInfo objects from the data in the database would look like this:
public Vector getActiveEmployees() throws SQLException
{
String sQuery = "select employee_first_name, "+
" employee_last_name, "+
" employee_dob,"+
" employee_experience,"+
" employee_DOJ, "+
" employee_email "+
"from employee";
Statement querySmt = null;
ResultSet rs = null;
Vector vecEmployees = null;
try
{
querySmt = databaseConnect.createStatement();
rs = querySmt.executeQuery(sQuery);
//LOOP
while(rs.next())
{
EmployeeInfo empInfo = new EmployeInfo();
empInfo.setEmployeeFirstName(rs.getString("EMPLOYEE_FIRST_NAME"));
empInfo.setEmployeeLastName(rs.getString("EMPLOYEE_LAST_NAME"));
empInfo.setEmployeeNumber(rs.getString("EMPLOYEE_NUMBER"));
empInfo.setEmployeeDOB(rs.getTimestamp("EMPLOYEE_DOB"));
empInfo.setEmployeeDOJ(rs.getTimestamp("EMPLOYEE_DOJ"));
empInfo.setEmployeeEmail(rs.getString("EMPLOYEE_EMAIL"));
empInfo.setEmployeeExperience(rs.getInt("EMPLOYEE_EXPERIENCE"));
vecEmployees.addElement(empInfo);
}//END LOOP
}
finally
{
try
{
if(smt != null) smt.close();
if(rs != null) rs.close();
}
catch(SQLException sqlE)
{
}
}
}
The code regions between LOOP and END LOOP denote the most unimaginative and repetitious portion of this assignment. A developer would have to complete similar processing in other database fetches. Most programmers, whether lazy or not, would fail to enthusiastically embrace this particular challenge. The combination of XML and Reflection provides an approach that helps developers circumvent this type of tedious processing.
Let's add the class ResultSetParser with the getCollection() method, which returns the value objects' collection and takes the ResultSet as one of the arguments. The ResultSetParser class diminishes the above code to:
public Vector getActiveEmployees() throws SQLException
{
String sQuery = "select employee_first_name, "+
" employee_last_name, "+
" employee_dob,"+
" employee_experience,"+
" employee_DOJ, "+
" employee_email "+
"from employee";
Statement querySmt = null;
ResultSet rs = null;
Vector vecEmployees = null;
try
{
querySmt = databaseConnect.createStatement();
rs = querySmt.executeQuery(sQuery);
ResultSetParser rsp = new ResultSetParser(new File(Constants.LOAD_XML_PATH+
"LOAD_EMPLOYEE.XML"));
vecEmployees = rsp.getCollection(rs);
}
finally
{
try
{
if(querySmt != null) querySmt.close();
if(rs != null) rs.close();
}
catch(SQLException sqlE)
{
}
}
return vecEmployees;
}
The code reduction in the above example may not seem very significant, but using ResultSetParser does make a difference for value classes with numerous state variables. The other advantage to this approach is that any ResultSet can be parsed.
ResultSetParser 's generic method uses XML and Reflection to parse the ResultSet and return the collection. The following code is the XML used for the data access above:
< VALUES CLASS="myproj.employee.model.EmployeeInfo" >
< COLUMNS NAME="EMPLOYEE_FIRST_NAME" METHOD="setEmployeeFirstName"
/>
< COLUMNS NAME="EMPLOYEE_LAST_NAME" METHOD="setEmployeeLastName"
/>
< COLUMNS NAME="EMPLOYEE_EXPERIENCE"
METHOD="setEmployeeExperience" />
< COLUMNS NAME="EMPLOYEE_DOB" METHOD="setEmployeeDOB" />
< COLUMNS NAME="EMPLOYEE_DOJ" METHOD="setEmployeeDOJ" />
< COLUMNS NAME="EMPLOYEE_EMAIL" METHOD="setEmployeeEmail"
/>
< /VALUES>
The VALUES element holds the class name as an attribute. The child elements map each database column to the corresponding set() methods in the VALUES CLASS , which are used to set a state variable in the valueClass .
A simple SAX parser can now parse this XML and store the mapping in a hashtable. The following code excerpt completes this task:
.
.
.
private class PropertyParser extends HandlerBase
{
//mappingTable is a hashtable in the Outer Class
public void startElement(String strElement,
AttributeList attrList)
{
if(strElement.equals("VALUES"))
{
valueClassName = attrList.getValue("CLASS");
}
else if(strElement.equals("COLUMNS"))
{
String columnName = attrList.getValue("NAME");
String methodName = attrList.getValue("METHOD");
mappingTable.put(columnName,methodName);
}
}
public void endElement(String strElement)
{
}
public void parsePropertyFile(File xmlFile)
{
try
{
SAXParser saxParser = SAXParserFactory
.newInstance()
.newSAXParser();
saxParser.parse(xmlFile,this);
}
catch(Exception e)
{
System.out.println(""+e);
}
}
}
An inner class called PropertyParser is used for parsing the XML document. An instance of SAXParser completes the actual parsing of the XML document and fires different parsing events, which are handled by the PropertyParser . We implement only one of the events via startElement() to obtain the mapping between the method name and the database column name.
Retrieving data from the ResultSet will require a call to its appropriate get() method. ResultSet implementations support a wide variety of ways to obtain data; the method used depends on the database's data type. For example, ResultSet 's getString() method can retrieve numeric data type from the database as a String . There are two ways to ensure that the most appropriate get() method is called on the ResultSet :
Obtain the data type of the column whose data is being retrieved. Use the get() method that returns the equivalent data type in Java. For example, to fetch data that stores as VARCHAR(2) in Oracle, you would call getString() on the ResultSet .
Obtain the argument type of the valueClass 's corresponding set() method, as defined by the XML mapping. Call the get() method on the ResultSet that returns the compatible data type. For example, if the retrieved data originates from a column called EMPLOYEE_DOB , then getTimestamp() is used on the ResultSet , since the corresponding set() method -- setEmployeeDOB() -- takes java.sql.Timestamp as an argument.
Option 1 may not be broad enough to support different data types across different database types. Option 2 is simpler to realize using Reflection. Since Reflection is necessary for instantiating the value classes (known only at runtime), option 2 would be the most obvious choice.
Next, you must obtain the arguments for each of the set() methods indicated in the XML. The code excerpt below attempts to accomplish this:
private void getMethodArguments() throws ClassNotFoundException
{
Class c = Class.forName(valueClassName);
Method[] valueClassMethods = c.getMethods();
for(int i=0;i{
String methodName = valueClassMethods[i].getName();
Class[] parameter = valueClassMethods[i]
.getParameterTypes();
if(parameter.length > 0)
methodArguments.put(methodName,parameter[0].getName());
}
}
The methodArguments is a hashtable in the outer class. The code above
Read
Tutorial at: Click here to view the tutorial
Rate Tutorial: Eliminate tedious programming: Recover data with XML and Reflection - JavaWorld November
2000
View Tutorial: Eliminate tedious programming: Recover data with XML and Reflection - JavaWorld November
2000
Related
Tutorials:
Accelerate your RMI
programming
Accelerate your RMI
programming |
Untangle your servlet code with
reflection
Untangle your servlet code with
reflection |
Reflection
vs. code generation
Reflection
vs. code generation |
Use XML data binding to do your
laundry
Use XML data binding to do your
laundry |
Navigate data with the Mapper framework
Navigate data with the Mapper framework |
Test networked
code the easy way
Test networked
code the easy way |
Sun boosts
Sun boosts enterprise Java |
Publish and find UDDI tModels with JAXR and
WSDL
Publish and find UDDI tModels with JAXR and
WSDL |
High-availability mobile applications
High-availability mobile applications |
XStream
XStream is a simple library to serialize objects to XML and back again. |
Object-relation mapping without the container
If you follow the latest developer buzz then you\\\\\'ve likely heard of IOC (Inversion of Control) containers and AOP (aspect-oriented programming). |
Practical Reflection: an excerpt from Hardcore Java
Practical Reflection: an excerpt from Hardcore Java
In this chapter from Hardcore Java, "Practical Reflection," Robert Simmons Jr. writes: "Reflection is one of the least understood aspects of Java, but also one of the most powerful. Reflection is used i |
Simple classes for JDBC
Simple classes for JDBC |
Getting Groovy with XML
XML sucks. Oh, wait, XML rocks. Well, it actually does a lot of both. It rocks because of all of the editors, validators, and tools written for it. XML has all but replaced any notion of a new custom text-based data language. But it also sucks because it\ |
Mandarax
Mandarax is an open source java class library for deduction rules. It provides an infrastructure for defining, managing and querying rule bases. |
JTimepiece
JTimepiece is the advanced library for working with dates and times in Java. Many easy-to-use methods in this API make it easy for any developer, from beginner to expert, to use JTimepiece. |
Advanced form processing using JSP
Processing HTML forms using servlets, or more often, CGI scripts, is one of the most common operations performed on the Web today. However, that JavaServer Pages (JSPs) can play a significant role in sophisticated form processing is a little-known secret. |
JSP Format Bean Library
JSP Format Bean Library is a collection of beans which support Java Server Pages(JSP). JSP allows the HTML developer to embed Java into a page. There are a number of common operations in a scripted page that would be tedious or complex without additional |
What is Persistence Framework?
What is Persistence Framework?
What is Persistence Framework?
A persistence framework moves the program data in its most natural form (in memory objects) to and from a permanent data store the database. The persistence framework manages the |
New Technical Articles: 64-bit Programming on Solaris 10 OS for x86 Platforms
Four technical articles describe the new Sun Studio 10 software's 64-bit programming features on the Solaris 10 OS for x86 and AMD64 platforms. Important issues regarding the AMD64 ABI (Application Binary Interface), debugging, migration to 64-bits, and p |
|
|
|