![]() |
|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
|
![]() |
![]() |
SummaryBy Victor Okunev
For some projects, you need a more flexible business object structure. For example, different companies may have different requirements forProduct
bean properties. Without a proper framework, you may end up spending long hours customizing your data structures for every new customer, soon finding yourself with parallel software versions. This article lays a foundation for a simple framework to build truly adaptive systems, saving you hours of routine programming. As a bonus, you get a refresher on JDBC (Java Database Connectivity) and JSPs (JavaServer Pages), and you'll also learn how to use XSLT (Extensible Stylesheet Language for Transformations) to generate Java source code. (4,800 words; February 1, 2002)
n some commercial software projects, you cannot afford to cast in
stone the structure of business objects. For example, different companies may
have different and even mutually exclusive requirements for
Product
bean properties. Without a proper framework in place, you may end up spending
long hours customizing all your data structures, including classes, database
tables, DTDs (document type definitions), and so on, for every new customer.
Needless to say, you may soon find yourself with a pocketful of parallel
software versions and a maintenance headache. How do you ensure that your design
is flexible enough to satisfy varying business requirements without a need to do
extra coding each time those requirements change?
In this article, I lay a foundation for a simple framework I successfully employed to build truly adaptive systems. It is based upon dynamic source code generation from a class's metadata maintained in a data dictionary. In the process, you'll get a refresher on JDBC (Java Database Connectivity) and JSPs (JavaServer Pages), and you'll also learn to generate source code with one of today's most fascinating XML-related technologies, XSLT (Extensible Stylesheet Language for Transformations).
Short design session
First, let's
set up a simple hypothetical project to which we can apply all the wonderful
techniques discussed here. The project will be an application geared towards a
vertical market that has a Product concept in its business vocabulary.
You can pick your own favorite business domain -- financial services, online
retailing, or maybe even technical training; anything that uses a product. The
system architecture is not a constraint either; it may range from a standalone
application to a distributed n-tier system. In this article, we will
concentrate on the business object design issues equally applicable in the wide
array of different projects.
Since we won't design this application for a particular customer, we must
make sure we know the business well enough to cover the most complex cases. To
achieve that, we hire the best domain experts, run a few CRC
(class-responsibility-collaboration) sessions, chart several use cases, and
eventually assemble a clear understanding of a Product concept, among many
others. With that information on hand, we can build a conceptual business domain
model that includes our perfect Product
bean depicted below:
|
This is roughly what we do in real projects before the actual coding, especially if we adhere to a good software development process.
Traditional implementation
Now we
can implement the construction phase, where we craft the Product
bean's Java code. In Java terms, a bean is a reusable component from
either the JavaBean or the Enterprise JavaBean (EJB) frameworks. Despite many
significant differences between the two kinds of beans, there are also
similarities. For example, they share the notion of a bean property. The bean
property is based on the standard Java naming convention for the pair of
accessor methods. Thus, if the bean has a nonindexed property code
,
it is assumed that it provides the writer and reader methods
setCode()
and getCode()
, respectively. The reader
method for the boolean
type property would be
isCode()
. For an indexed property, the bean is assumed to possess
two sets of setCode()
and getCode()
methods, one of
which would be indexed while the other would deal with the whole array. The
java.beans.Introspector
uses the same rule set applied in reverse
to dynamically analyze the bean class and discover the set of exposed bean
properties on the fly.
The properties concept becomes particularly handy when you need to map a
business object to a data repository, like a database table or an XML document.
Similarly, it helps at the presentation tier too. For example, the JSP API
provides a mechanism for mapping HTTP request parameters to the bean's
properties. The following action saves a tremendous amount of routine coding by
magically initializing bean properties from the matching fields in an HTML form:
<jsp:setProperty name="myBean" property="*"/>
Ultimately, a bean is just a Java class that adheres to a set of well-defined rules. Let's use the simpler bean type, JavaBean, for our project, which will adequately demonstrate the points made here. Later you may apply these techniques to EJB components as well.
Now we can say that our Product
bean has the
integer
property code
, the String
property name
, the boolean
property
testedOnAnimals
, and the date
property
availableSince
. As we might expect, the bean translates to Java as
Listing 1 shows:
Listing 1. Product.java public class Product {
private int
code;
private String name;
private boolean
testedOnAnimals;
private java.util.Date
availableSince;
public Product() {}
public
int getCode() {
return
code;
}
public void setCode(int newCode)
{
code =
newCode;
}
public void setName(String newName)
{
name =
newName;
}
public String getName()
{
return
name;
}
public void setTestedOnAnimals(boolean
newTestedOnAnimals) {
testedOnAnimals =
newTestedOnAnimals;
}
public boolean
isTestedOnAnimals() {
return
testedOnAnimals;
}
public void
setAvailableSince(java.util.Date newAvailableSince)
{
availableSince =
newAvailableSince;
}
public java.util.Date
getAvailableSince() {
return
availableSince;
}
}
The pros and cons of traditional implementation
For this project, we've chosen a straightforward, fast, and
inexpensive approach to building the Product
bean. Certainly, we
may extend it to EJBs as well. As a result, we will have a system that hopefully
suits all possible scenarios within the business domain.
In most cases, we can get away with this approach. However, what
happens if a new customer unexpectedly comes up with a different perspective on
our carefully designed beans? What if we must add a new Boolean property
y3KCompliant
to the Product
bean? Remember, we'd need
to modify not only this particular bean's source code, but also all the relevant
data structures, including BeanInfo
classes, SQL statements, and
perhaps some classes that belong to our application's view and controller parts.
Worse yet, what if the customer wants permission to do all that without our
help? Don't forget that when you deal with a real commercial business
application, you likely have at least 100 different business objects. So, what
if you must tune each object for every new customer? On the flip side, what once
looked like a quick and easy solution appears to be a bottleneck.
One common solution adds extra properties to each business object, reserved
specifically for the client's proprietary purposes. Let's try this tactic and
add three extra properties for a few primitive types, as well as for the
String
and the Date
types to our Product
class:
|
Sometimes this solves the problem, but frankly it looks ugly and feels uncomfortable. From my years in software development, I've learned that a lack of inner comfort is a reliable sign of bad design. And really, how can we be certain that each type's three extra properties are sufficient? Moreover, those customers who never needed those extra properties will pay high price in the form of wasted table space. Can't we design a system that easily adapts itself to the different business requirements?
Code generation to the rescue
The
problem we face resembles the situation in which a Website's static HTML content
can no longer satisfy business demand. In that case, Web application developers
use various technologies to deliver dynamic data-driven content. We need
something similar that, instead of HTML, generates Java source code for our
beans. This becomes our main objective now. Once we have an adequate solution,
you can extend it to all other data structures involved in application
customization. Assuming you have a proper application framework in place, you
should be able to simply plug in the new code without any additional coding. If
you can do that, then your clients will be able to perform such customization
themselves -- if provided with a slick GUI interface, of course.
To benefit from the automatic code generation process, we need to feed it
detailed bean descriptions. In other words, we need a repository that we can
query for the class's metadata. This is similar to the idea of the database
metadata we can obtain using the getMetaData()
method of the
java.sql.Connection
interface from the JDBC API. In the RDBMS
(relational database management system) world, such information is usually
maintained through the data dictionary -- a set of system tables that
completely describe the database structure.
In the OOAD (object-oriented analysis and design) world, UML (Unified Modeling Language) often expresses the class metadata. An increasing number of UML modeling tools provide forward-engineering facilities from UML to source code and vice versa. Even though I prefer to keep the UML model and the source code in synch, I am not satisfied with the level of control we have over the code-generation process with these kind of tools.
Another language used to describe metadata is, of course, XML. It has several features that make it particularly attractive for this task:
In fact, the XML Metadata Interchange (XMI) format developed by IBM, Unisys, Oracle, and other industry leaders is a common language for metadata interchange between modeling tools, as well as between the tools and metadata repositories. Though we could use it here, it probably would require another article as an introduction. Also, XMI is to some extent overkill for what we want to do. However, you should keep XMI in mind when you work on more sophisticated projects. Certainly all the techniques we discuss in this article will still be valid if you decide to employ XMI.
Before we continue, I would like to mention one interesting solution addressed in Mark Pollack's "Code Generation Using Javadoc" (JavaWorld, August 2000). Pollack and his team used simple Java classes to describe the metadata for complex classes. They took advantage of the Java compiler to check their model's integrity. Then they created a doclet for the javadoc utility included in the Java SDK. The doclet generated source code based on the information the javadoc dynamically obtained from analyzing these metadata classes. Although I give much credit to this team for its innovation and reuse of existing tools, we cannot use this approach in our hypothetical project. Someone still has to know how to code the metadata classes manually. This would be a hard sell to an average customer. Our objective is to build a framework that provides hands-free business object customization.
The game plan
In our solution, we
will combine the best of existing techniques. We'll maintain the class metadata
in the simple data dictionary that we design from scratch. A relational database
is probably the most suitable tool for this purpose, for the following reasons:
Once we have the metadata in the data dictionary, we can use the XML metadata server to dynamically extract the information and present it as an XML document by HTTP request. By using HTTP, we remove any technological constraints on the XML metadata server implementation, although I do prefer using JSPs or the Servlet API to build a metadata server.
As soon as we receive the XML document's class metadata, we will employ a generic XSLT processor to transform the document into Java source code. In addition to the metadata, we also need an XSLT stylesheet, which includes the processing instructions that the XSLT processor needs to perform its transformation magic.
Once we have all the pieces in place, we just need to customize a bean class by tweaking a few records in the data dictionary, sending an HTTP request, and receiving freshly minted Java classes. Any customer could probably do this, since no programming is involved.
The following figure is a high-level sequence diagram that helps to visualize this game plan.
The game plan |
Create a data dictionary
There is
no standard data dictionary schema that we can borrow for our project. Every
team designs one that suits its requirements best. Let's design a simple
proof-of-concept data dictionary. Later, I'll elaborate on how to make it more
sophisticated and suitable for a commercial project.
We need just two tables. The Beans table contains information about the bean
classes, while the Properties table describes their properties. Below are the
SQL statements that you can use to build these tables in the relational database
of your choice: DROP TABLE Beans;
CREATE TABLE Beans (id INT,name VARCHAR(30) NOT
NULL,comments
VARCHAR(100)); DROP TABLE Properties;
CREATE
TABLE Properties (beanId INT,name VARCHAR(30) NOT NULL,type
VARCHAR(30) NOT
NULL,comments VARCHAR(100));
Even though I'd rather you use JDBC to create these tables, feel free to use
whatever tools and interfaces you prefer to enter data. This might be a good
time to think about what kind of tool you'll provide to future customers for
these purposes as well. Let's describe the metadata for our INSERT INTO Beans (id,name,comments) VALUES (1,"Product","ThisProduct
bean in this data dictionary:
bean
represents a product that the company offers to its customers");
INSERT INTO
Properties (beanId,name,type,comments) VALUES
(1,"code","int","the product
inventory code");
INSERT INTO Properties (beanId,name,type,comments)
VALUES
(1,"name","String","the product name");
INSERT INTO Properties
(beanId,name,type,comments) VALUES
(1,"testedOnAnimals","boolean","the flag
that indicates if the product
was tested on animals");
INSERT INTO
Properties (beanId,name,type,comments)
VALUES
(1,"availableSince","java.util.Date","the date when the company
started
offering this product to its customers");
As I mentioned earlier, this is probably the absolute minimum information we need to maintain in order to make our metadata useful. (Well, we could probably live without the comments, but uncommented code is considered unprofessional in the programming world.) Therefore, Tables 1 and 2 show what we finally need.
Table 1. Beans
|
Table 2. Properties
|
In real life, you would probably need to stretch these tables a bit. You may
want to consider including more useful information in your metadata. Actually,
the Java API provides some good suggestions in the form of
java.lang.Class
and several classes from the
java.lang.reflect
package. There are also two useful classes in the
java.beans
package. In fact, the
java.beans.BeanDescriptor
class essentially encapsulates the
metadata about the bean itself, whereas the
java.beans.PropertyDescriptor
class does the same for a bean
property. If you are not satisfied with the offered metadata model, these
descriptor classes let you expand it by associating a set of named attributes
with the entity. I have found this feature particularly handy for setting
constraints on the acceptable data values for the bean's properties. I've
described it in the context of a data validation framework presented in "Validation
with Pure Java" (JavaWorld, December 2000).
With all this in mind, here are additional fields with self-describing names that may be worth adding to your commercial-grade metadata structure.
Beans table:
package
imports
modifiers
isAbstract
isInterface
superClass
implements
displayName
description
Properties table:
modifiers
isAbstract
isIndexed
isHidden
isLookup
lookupTableName
isLowercaseAllowed
isPassword
isRequired
isReadonly
defaultValue
maxValue
minValue
maxLength
displayName
description
displayFormat
You probably also need to make provisions for the metadata version control by adding a project and version field or similar extra fields to each table.
Describe metadata in XML
Before we
extract metadata into the XML document, we must agree on its structure. For that
purpose, we can use one of the two existing metalanguages: DTDs or XML Schemas.
DTDs are somewhat old fashioned, mostly due to their limited typing
capabilities; however, they are simple, compact, and readable by the human eye.
Perhaps that is why they remain quite popular. On the other hand, XML Schemas
offer more advanced features, like inheritance and strong typing, at the expense
of simplicity. For our purposes, a DTD works fine. Here is how we structure the
metadata document: <!ELEMENT bean (name,property*,comments?)>
<!ELEMENT property
(name,type,comments?)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT
type (#PCDATA)>
<!ELEMENT comments EMPTY>
This really means that a <bean>
element must have exactly
one <name>
child and optionally any number of
<property>
elements. A <property>
element
in turn must have exactly one <name>
and one
<type>
element. Both <bean>
and
<property>
elements may have an optional
<comments>
element.
Now we need to build an XML metadata server that does the following:
We use JSPs to create this simple XML metadata server. The server accesses the database directly from the JSP with the JDBC 2.0 core API, which comes with the Java 2 Platform, Standard Edition (J2SE). Please note that this is not the recommended approach. I've chosen it solely to stay focused on the functionality without distracting your attention with complex Web application design issues. According to Sun Microsystems' Java BluePrints, you should create JSPs with as little Java code exposed as possible. Normally you would implement something like this with a servlet or at least with a custom JSP tag from something like the Jakarta Taglibs project for the database access. My goal today, however, is to provide you with an easy-to-understand algorithm that you can try on your home computer with minimum effort.
To open a database connection, the java.sql.DriverManager
class
needs the following information:
We provide this information as the HTTP request's parameters. Another important request parameter is the name of the bean whose metadata we are extracting. Listing 2 is the resulting JSP:
Listing 2. GenXml.jsp <?xml version="1.0" encoding="ISO-8859-1"?>
<%@ page
import="java.sql.*" %>
<%
try
{
String driver =
request.getParameter("driver");
String url =
request.getParameter("url");
String username =
request.getParameter("username");
String password =
request.getParameter("password");
String bean =
request.getParameter("bean");
Class.forName(driver);
Connection
con = DriverManager.getConnection(url,
username,
password);
Statement st =
con.createStatement();
ResultSet rs = st.executeQuery("SELECT *
FROM Beans WHERE name='" +
bean + "'");
// we
expect exactly one record here
if( !rs.next() )
{
throw new IllegalArgumentException("No
metadata found for the
bean " +
bean);
}
%>
<bean>
<name><%=
rs.getString("name") %></name>
<comments><%=
rs.getString("comments")
%></comments>
<%
rs.close();
rs
= st.executeQuery("SELECT b.* from Beans a, Properties b WHERE
b.beanId=a.id
AND a.name='" + bean + "'");
while(rs.next())
{
%>
<property>
<name><%=
rs.getString("name")
%></name>
<type><%=
rs.getString("type")
%></type>
<comments><%=
rs.getString("comments")
%></comments>
</property>
<%
}
st.close();
con.close();
%>
</bean>
<%
}
catch( Exception ex ) {
%>
<exception><%=
ex.getMessage() %></exception>
<%
}
%>
For the JSP to function, it must be deployed on a Web server that provides a JSP/Java servlet engine. These days it is increasingly difficult to find a Web server that doesn't support Java technology. If you don't have one yet, maybe now is the time. Check out these free products that offer full JSP and servlet support:
Once you deploy http://<myserver>/<mypath>/GenXml.jsp?driver=<jdbcdGenXml.jsp
on a Web server, you should be able
to process a request in the following format:
river>&url=<dburl>&username=<dbuser>&password=<dbpwd>
&bean=Product
You must substitute the variables with angle brackets for real values. Don't
forget to use <?xml version="1.0" encoding="ISO-8859-1" ?>
&
instead of &
, when
specifying the url
parameter. If you do everything correctly, you
should receive a response, which is essentially the Product
bean's
metadata expressed in XML:
<bean>
<name>Product</name>
<comments>This bean represents a product that
the company
offers to its customers</comments>
<property>
<name>code</name>
<type>int</type>
<comments>the product
inventory code</comments>
</property>
<property>
<name>name</name>
<type>String</type>
<comments>the product
name</comments>
</property>
<property>
<name>testedOnAnimals</name>
<type>boolean</type>
<comments>the flag
that indicates if the product was
tested on animals</comments>
</property>
<property>
<name>availableSince</name>
<type>java.util.Date</type>
<comments>the date
when the company started offering this
product to its
customers</comments>
</property>
</bean>
If your request causes an exception, most likely due to invalid parameter
values, the page generates a different type of XML document with the
<?xml version="1.0" encoding="ISO-8859-1" ?> <exception>
element:
<exception>No
metadata found for the bean Produkt</exception>
If you're itching to see how this XML metadata server works, you may query mine, available here.
Transform XML into Java code
Before
XSLT became a wonderful reality, you had to transform XML into Java like this:
handcraft a class that utilizes a DOM or a SAX parser to extract the data from
the source XML document, apply some hardcoded rules to it, and eventually spit
out the Java code. Every time you had to change some rules, you would have to
modify and recompile the handcrafted class. If you decided to transform into
another language -- Smalltalk, say -- you would have had to build another class
that does just that. This is doable, of course, but it's no fun, especially if
you know about XSLT.
XSLT is an official World Wide Web Consortium (W3C) Recommendation. It lets you transform an XML document into almost anything else. Traditionally, though, you use it to transform the document into HTML, text, or other XML document types. The XSLT processor performs the transformation according to the rules defined in the XSLT stylesheet, which is an XML document itself. If you need to change the transformation logic, you simply modify the stylesheet with a text editor.
Many different implementations of the XSLT processors are available today; check the W3C Website for references. We will use the Xalan XSLT processor developed under the Apache XML project. Because it's a Java-based implementation, Xalan comes with some features particularly attractive for a Java developer. One such feature is support for TRaX (Transformation API for XML), which is part of the Java API for XML Processing (JAXP). TRaX helps you build applications that utilize the XSLT transformation service through a standard, implementation-neutral interface.
Another goodie is the XSLT Compiler, a tool that compiles the transformation logic from a stylesheet into a lightweight Java class called a translet. You may then use Sun's XSLT runtime processor to apply the translet to an XML document and significantly increase the transformation performance.
Listing 3 defines a stylesheet to transform our simple metadata into Java source code. If you later decide to expand your metadata structure, you will have to reflect the changes in the stylesheet as well:
Listing 3. JavaBean.xsl <?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:java="http://xml.apache.org/xslt/java"
exclude-result-prefixes="java">
<xsl:output
method = "text"/>
<xsl:template match="bean">
/**
*
<xsl:value-of select="comments"/>
* This class has been generated by
the XSLT processor from the
metadata
*/
public class <xsl:value-of
select="name"/>
{
/**
* Creates a new
instance of the <xsl:value-of
select="name"/>
bean
*/
public
<xsl:value-of select="name"/>()
{}
<xsl:apply-templates
select="property"/>
}
</xsl:template>
<xsl:template
match="property">
private <xsl:value-of
select="type"/>
<xsl:text>
</xsl:text>
<xsl:value-of
select="name"/>;
<xsl:variable name="name"
select="name"/>
<xsl:variable name="cname"
select="java:Capitalizer.capitalize($name)"/>
/**
* Sets <xsl:value-of select="comments"/>
*
@param <xsl:value-of select="name"/> is
<xsl:value-of
select="comments"/>
*/
public void set<xsl:value-of
select="$cname"/>(<xsl:value-
of select="type"/> <xsl:text>
</xsl:text><xsl:value-
of select="name"/>)
{
this.<xsl:value-of
select="name"/> =
<xsl:value-of
select="name"/>;
}
/**
* Returns <xsl:value-of select="comments"/>
*
@return <xsl:value-of select="comments"/>
*/
public <xsl:value-of
select="type"/><xsl:text></xsl:text>
<xsl:apply-templates
select="type"/><xsl:value-of
select="$cname"/>()
{
return <xsl:value-of
select="name"/>;
}
</xsl:template>
<xsl:template
match="type">
<xsl:variable name="type"
select="."/>
<xsl:choose>
<xsl:when
test="$type='boolean'">is</xsl:when>
<xsl:otherwise>get</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
The XSLT language, XSL, requires time and effort to learn. The above stylesheet may not tell you much yet. If you are already versed in XSL, let me briefly explain how this works.
There are three templates in this stylesheet. One processes the
<bean>
element. This is where we provide the bean's class
definition and the default constructor. The other template processes the
<property>
element. Please note that I used the Xalan-Java
extensions mechanism to initialize the XSL variable arbitrarily called
cname
. This variable contains the name of the property with the
first character capitalized. Here I use it to generate the names of the accessor
methods. Since XSLT does not provide an extension function, I had to create a
small Java utility class, Capitalizer
(shown in Listing 4), that
capitalizes the first character in the string. This class must be compiled and
made available to the XSLT processor via the CLASSPATH
at
transformation time:
Listing 4. Capitalizer.java /**
* This class provides an XSLT extension function that
* may be
utilized by Xalan-Java extension mechanism.
*/
public class Capitalizer
{
/**
* This method
capitalizes the first character
* in the provided
string.
* @return modified
string
*/
public static
String capitalize(String str)
{
return
Character.toUpperCase(str.charAt(0)) +
str.substring(1);
}
}
Please note that the idea of the XSLT extensions is not proprietary to Xalan. In fact, it is part of the XSLT Recommendation.
Finally, a third template decides on the getter method's name. Remember, it
should have the prefix is
for boolean
properties and
get
for all the others. Before we continue, please note that XSLT
is rich enough to let you accomplish the same transformation in different ways.
For example, instead of a separate template, we could use the
<xsl:for-each select="property">
element to process the
<property>
element.
Now we have all the ingredients to cook up our java org.apache.xalan.xslt.Process -in xmlSource -xsl stylesheet
-out outputfile
Product
bean.
Once you have Xalan installed and configured, you may perform the transformation
from the command line like this:
The mandatory -in
parameter must be the source XML document's
URL. You may point it to a local file or to the URL I suggested earlier.
The optional -xsl
parameter is the URL pointing to an XSLT
stylesheet. Again, you are welcome to try the one I have prepared for you: http://www.climbstairs.org/examples/JavaBean.xsl. Please note
that this parameter is optional because you may specify the XSLT URL directly
inside the source XML document via processing instruction (PI). I would not
recommend doing that simply because by decoupling these two documents you gain
more flexibility. For example, you may decide in the future to create another
XSLT stylesheet to generate an IDL (Interface Definition Language) for your
CORBA application.
The optional -out
parameter specifies the name of the file to
host the source code for the Java class we are about to receive. You may omit it
to output the transformation results on the screen.
If you've configured your CLASSPATH
properly, Listing 5 shows
what you get as a result of the transformation:
Listing 5. Product.java /**
* This bean represents a product that the company offers to
its
customers
* This class has been generated by the XSLT processor from
the
metadata
*/
public class Product
{
/**
* Creates a new
instance of the Product bean
*/
public Product()
{}
private int
code;
/**
* Sets the product
inventory code
* @param code is the product
inventory code
*/
public
void setCode(int code)
{
this.code =
code;
}
/**
* Returns the product inventory code
* @return the
product inventory code
*/
public int getCode()
{
return
code;
}
private String
name;
/**
* Sets the product
name
* @param name is the product
name
*/
public void
setName(String name)
{
this.name =
name;
}
/**
* Returns the product name
* @return the product
name
*/
public String
getName() {
return
name;
}
private
boolean testedOnAnimals;
/**
* Sets the flag that
indicates if the product was tested on animals
*
@param testedOnAnimals is the flag that indicates if the product
was tested
on animals
*/
public void
setTestedOnAnimals(boolean testedOnAnimals)
{
this.testedOnAnimals =
testedOnAnimals;
}
/**
* Returns the flag that indicates if the product was tested
on
animals
* @return the flag that indicates if
the product was tested on
animals
*/
public boolean isTestedOnAnimals()
{
return
testedOnAnimals;
}
private
java.util.Date
availableSince;
/**
* Sets the date when
the company started offering this product to
its
customers
* @param availableSince is the date when
the company started
offering this product to its
customers
*/
public void
setAvailableSince(java.util.Date availableSince)
{
this.availableSince =
availableSince;
}
/**
* Returns the date when the company started offering this product
to its
customers
* @return the date when the company
started offering this product
to its customers
*/
public java.util.Date getAvailableSince()
{
return
availableSince;
}
}
This result is exactly what we expected. This source code compiles very well; I'm sure the compiler has no appreciation for what it took to put it together.
What's next
Once you are happy with
the transformation, you are welcome to build a JSP or a servlet that performs it
via the TRaX API or by utilizing the XSL Tag Library, which is part of the
Apache Jakarta Taglibs collection. You may then request the transformation via
an HTTP request, receive the Java code, and compile it dynamically using the
java.lang.Compiler
class. You may apply the same technique to
produce the BeanInfo
class, different support classes, relevant SQL
statements, DTDs, and anything else to accompany every bean class you generate.
To plug the freshly minted classes into your application, you may consider using
the Reflection API, which dynamically discovers their structure.
A framework that works
Everything
I've described in this article serves as a foundation of the framework I am
successfully applying in commercial projects. The business domain of financial
services where I currently work operates with large quantities of relatively
bulky business objects. Every new customer requires a substantial customization
of these objects. Without this framework, our team would not be able to meet the
tight development schedules. I'm sharing it with you because it really works, it
saves you a lot of time and money, and it utilizes some of the most fascinating
technologies available today.
About the author
Sun Certified Java Programmer and
Microsoft Systems Engineer Victor Okunev
is a design architect of the research and development team for Vancouver-based
Marlborough Stirling Plexus. With an M.S. in
computer science from the Moscow State Institute of Radio Engineering,
Electronics, and Automation, Victor has more than 11 years' experience in
software development, primarily on enterprise-scale applications. Victor also
works as a Java instructor with Learning
Tree International, writes for JavaWorld, snowboards, and enjoys
sea and whitewater kayaking.
![]() |
![]() |
|
![]() |
Copyright © 2004 JavaWorld.com, an IDG company |
![]() |
![]() |
![]() |