struts-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Carlos Cajina" <cecaj...@hotmail.com>
Subject Re: Pre-populating a form from a database
Date Thu, 02 Dec 2004 18:38:08 GMT
> However, I can't get the action to trigger when I go to the form 
> initially.
> I am a bit lost on this one even though I'm trying to understand these
> tutorials.

One of the solutions I've implemented is to create an intermediate action 
that loads data from a database, populates de ActionForm, and directs the 
user to the apropiate JSP.
One way to achive almost "automagically" ActionForm population (and to 
obtain DTO's from ActionForm data) is through Jakarta Commons Beanutils. I'm 
supposed to add a mini-how-to to Commons Wiki but day-time job keeps me busy 
even @ night :^P So here's an extract:

"* Since I'm using Struts in my current J2EE project one of my concerns was 
to find a way to transfer data between the presentation layer and the data 
layer. From the Struts part I have ActionForms and from the data persistence 
part I have Value Objects and CMP Entity Beans.
* According to Ted Husted's "Struts in Action" (2003, Manning) there are 
several strategies to transfer values between tiers. I was using one that 
relies on "factory methods" ("A helper method encapsulates, instantiates, 
and populates a business tier bean."), but including such methods in my 
ActionForms to instantiate, populate, and return a specific value object 
brought along (at least to me) messy code to handle data type conversions 
and validations, moreover, as Ted points it "This strategy binds the 
ActionForm to the business-tier type". Of course there are advantages to 
this approach, but the use of reflection -as I hope you'll see- is a cleaner 
and safer path, and introduces very little overhead.

* For the sake of simplicity in my ActionForms I only have string 
properties -even though users "see" and save String, Date, Integer, Boolean, 
Timestamp, and Float values. Considering that the BeanUtils methods can 
convert data between Strings and native types this seemed like a good 
decision. If you have "exotic" data types,s you'll have to implement "bridge 
methods" to keep data type conversion transparent (I'll show a rather simple 
example later)

Having described some of my scenario, here's what I did:

1. Following commons-beanutils JavaDocs' two-step recipe, I wrote a class 
that implemented the Converter interface. Within this class the convert() 
method should accept theclass that you want to convert to, and a String 
representing the incoming value to be converted. I had to go through this 
first step because from the user perspective dates are handled in dd-mm-yyyy 
format but they go into the database as an SQL DATE value, using yyyy-mm-dd 
format. To implement the Converter interface I kind of cheated because I 
grabbed commons-beanutils source code and peek into the default 
SqlDateConverter class code (written by Mr. Craig R. McClanahan) What I did 
next was re-implement the convert() method to add code within the try to 
"reverse" the date format, like this:

int year,month,day;
String userDate = (String) value;

year = Integer.parseInt(userDate.substring(6));
month = Integer.parseInt(userDate.substring(3,5));
day = Integer.parseInt(userDate.substring(0,2));

GregorianCalendar dbDate = new GregorianCalendar(year, month-1, day);

Date correctDate = new Date(dbDate.getTimeInMillis());

return (correctDate);

NOTE: there are default converters that use Locale objects, if you need 
something more refined (you can "load" them during App startup an 
define -depending on the constructor you use- the default values to be 
returned)

2. The next step in the recipe is to "register an instance of your converter 
class by calling the ConvertUtils.register() method". It is suggested that 
this be done at application startup time, and since I already had a 
ServletContext Listener I just added the following lines in the 
contextInitialized method:

appContext.log("Registering MyOwnSqlDateConverter...");
ConvertUtils.register(new MyOwnSqlDateConverter(),java.sql.Date.class);
appContext.log("MyOwnSqlDateConverter registered...");

As you can imagine, for every String to java.sql.Date conversion that takes 
place in the application the converter to use will be the one I'm providing 
in step 1 and registering in step 2.

3. Finally, to populate ActionForms and create Value Objects you should add 
some simple methods:

    public void populateFormFromValueObjectData(Object vo) throws Exception
    {
        try {
            BeanUtils.copyProperties(this, vo);
        } catch (Throwable t) {
            throw new PopulateSolicitudDataException(t);
        }
    }

and

    public SomeValueObject getSomeValueObjectFromFormData() throws Exception
    {
        SomeValueObject svo = new SomeValueObject();

        try {
            BeanUtils.copyProperties(svo, this);
        } catch (Throwable t) {
            throw new PopulateSolicitudVOException(t);
        }

        return svo;
    }

In both cases, "this" references the ActionForm. In the first method, 
BeanUtils.copyProperties(this, vo) copy property values from the origin bean 
(vo) to the destination bean (this=ActionForm) for all cases where the 
property names are the same, doing all the necessary data type conversions 
under the hood; and the same applies for BeanUtils.copyProperties(svo, 
this).

Doing things this ways allows you to transfer data between tiers without 
binding your form to the business tier, in fact, you don't even have to know 
the details of the data transfer objects (value objects) to get data from 
them and send data through them. Mr. Husted refers to this kind of 
felxibility as "round-tripping ActionForms and business beans".

One of my actual ActionForms has to gather a lot of data (or is it datum? 
sorry, not very good in english grammar) using wizard like screens, but this 
information doesn't go to the same places in the database. I create three 
different types of Value Objects and obtain information from those three 
types with just a few lines of code and without caring about any data type 
conversions. This is one step closer to heaven for me! :^)

I hope this serves you as a good and practical introduction to part of the 
commons-beanutils power ;^)  If any questions arise or you come up with 
better examples and/or corrections, please share them!"

Regards and good luck!

Carlos

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
For additional commands, e-mail: user-help@struts.apache.org


Mime
View raw message