PDA

View Full Version : Change command class in runtime! good or bad?


lkamal
Jun 15th, 2007, 01:36 AM
Hi all,

I'm implementing a search functionality. Here the search functionality is called with a search type in url.
eg: http://localhost/myapp/search.html?recType="employee"

I'm using a SimpleFormController for this.

Depending on the search recType the search fields have to be changed.
eg:

employee-> name, email, ...
invoice -> invoice date, amount,...

Option 1:
Add all these fields to one command object and depending on the recType show hide fields in the JSP page.
class MyForm{
String name;
String email;
String invoiceDate;
....
}

Option 2:
Write different command classes for each type and inside the showForm() method decide which command class to be set and depending on the recType show hide fields inside the jsp.

Option 3:
Write different forms for each type and inside the showForm() method decide which command class to be set and depending on the recType change the view as well. (ie: create different search jsp pages for each recType).

What would be the best way to handle this type of a situation? Would this 3rd option become a maintenance nightmare?

Hope you'll be able to help me and discuss this issue using your experiences?

Thanks in advanced.

Jörg Heinicke
Jun 15th, 2007, 04:39 AM
I can't see an advantage of not using 3 different controllers and views. They are different anyway. Common stuff in the controllers can be moved to an abstract class. All those ifs will make your code really hard - if it will work at all. Command class name is not supposed to be changed at runtime.

Jörg

lkamal
Jun 15th, 2007, 05:36 AM
Hi Heinicke,

Of cause, I think option 3 is the best option in my case. But my concern is whether that would be hard to maintain rather than other options.

Command class name is not supposed to be changed at runtime.
Do you mean about the commandName or the commandClass? I'm not going to change the commandName, but I'm going to change the commandClass.

Cheers.

ramin_farhanian
Jun 16th, 2007, 08:01 AM
hi,
I guess you are abusing the decoupled spring mvc design. I do believe that It's good to be creative and try new ways of doing something. But in your case I guess you force yourself to face complexity. And why? You bind a few things together. Are you sure they wont change? Are you sure the code will be readable after six month?

Meanwhile I have developed a few applications with Spring MVC. I have always used AbstractCommandController for the search pages. Please Tell me how you are filling the criteria section and the search result in your jsp.

All The Best,
Ramin Farhanian

cwilkes
Jun 16th, 2007, 12:57 PM
You could have search.html's controller just redirect to the appropriate page, ie:

ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
return new ModelAndView(new RedirectView("search" + request.getParameter("searchType") + ".html"), request.getParameterMap());
}


and then the browser will be redireted to "searchEmployee.html" or "searchAccount.html"

Jörg Heinicke
Jun 16th, 2007, 08:11 PM
Do you mean about the commandName or the commandClass? I'm not going to change the commandName, but I'm going to change the commandClass.

commandClass. The Spring controllers even check if command object is of type commandClass. You really abuse the Spring controllers without any need.

Jörg

martynhiemstra
Jun 18th, 2007, 08:33 AM
A web application design is as difficult as you make it. You are making it very difficult. The simplerer the better.

Just create 3 controllers and views or create 1 controller and 1 view and only display/analyse the data (Search fields) that are neccessary.

lkamal
Jun 20th, 2007, 03:55 AM
commandClass. The Spring controllers even check if command object is of type commandClass. You really abuse the Spring controllers without any need.

I can check the recordType in formBackingObject method and set required type using setCommandClass.

-------------------------------
In my scenario, the search operation takes a SearchBean as a parameter and gives a SearchResultsBean instance with searchResult. There are different SearchBeans for different types. For Employee objects EmployeeSearchBean, for Invoice, InvoiceSearchBean, etc (about 10 types). All these classes are existing ones which I have to use in my application.

So what I did was, have a Factory to return the SearchBean depending on the recordType and set that into the Controller at runtime. Then show the formPage like viewName = request.getParameter("recordType") + searchPage. And each of these jsps like EmployeeseachPage or InvoicesearchPage are submitting values that matches those SearchBeans.

How should I achieve this?

martynhiemstra
Jun 20th, 2007, 04:25 AM
2 Options:


1. Create 1 command, controller and jsp page. In the jsp page you only display the options beloning to the current search type. In the controller only search according to the selected type.

2. Create 3 command beans, controllers and jsp pages. Create another controller mapped to search.html that forwards to the different controllers according to the passed parameter.


Dont try and change command classes real time because that is plain evil. That goes against how Spring works. Instead use Spriong as it is meant to. Think of how you want your application to work and then configure it.

lkamal
Jun 20th, 2007, 05:47 AM
1. Create 1 command, controller and jsp page. In the jsp page you only display the options beloning to the current search type. In the controller only search according to the selected type.
So all the fields for 10 different search objects will be there in one commandClass? So that will have more than 50 fields??

2. Create 3 command beans, controllers and jsp pages. Create another controller mapped to search.html that forwards to the different controllers according to the passed parameter.
So what you are suggesting is to write one controller per each type making 10 controllers for 10 types available in my system?

Jörg Heinicke
Jun 20th, 2007, 02:09 PM
3. Create an abstraction. The details are hidden in a thread (http://forum.springframework.org/showthread.php?t=38451) which is about a different problem I had when I implemented it.

Jörg

lkamal
Jun 21st, 2007, 03:36 AM
So what about having one SimpleFormController implementation and setting the CommandClass and formView jsps using the x-servlet.xml.

eg:

<bean id="employeeSearchController" class="xxx.yyy.SearchRecordsController">
<property name="formView">
<value>employeeSearchForm</value>
</property>
<property name="successView">
<value>employeeSearchResults</value>
</property>
<property name="commandName">
<value>searchCommand</value>
</property>
</bean>

<bean id="invoiceSearchController" class="xxx.yyy.SearchRecordsController">
<property name="formView">
<value>invoiceSearchForm</value>
</property>
<property name="successView">
<value>invoiceSearchResults</value>
</property>
<property name="commandName">
<value>searchCommand</value>
</property>
</bean>


1. But I can not set the CommandClass from the config file. Is there a way to do that? How? Is it a good method to follow?

The following config portion is not working.

<property name="commandClass">
<ref bean="customerSearchBeanClass" />
</property>

<bean id="customerSearchBeanClass" class="xxx.CustomerSearchBean" />



2. Even this will have another issue on initBind() since I have to write separate initBind() methods for each type. Isnt' it? Is there any way to set Binders into a controller through configuration same as validators?

So finally what this leads to is -> write separate controllers for each type which extends my AbstractSearchController?

lkamal
Jun 21st, 2007, 07:13 AM
Hi cwilkes,

You could have search.html's controller just redirect to the appropriate page, ie:

ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
return new ModelAndView(new RedirectView("search" + request.getParameter("searchType") + ".html"), request.getParameterMap());
}


and then the browser will be redireted to "searchEmployee.html" or "searchAccount.html"

When redirected with request.getParameterMap(); is there a way for me to populate the commandObject.searchType field automatically when it's shown on the particular search page rather than explicitly setting that field inside the formBackingObject() method as follows.


protected Object formBackingObject(HttpServletRequest request) throws Exception {
Object object = super.formBackingObject(request);
String type = request.getParameter("searchType");
if(type != null){
((SearchFormBean) object).setSearchType(type);
}
}


Thanks.

Jörg Heinicke
Jun 21st, 2007, 03:58 PM
So what about having one SimpleFormController implementation and setting the CommandClass and formView jsps using the x-servlet.xml.

That's definitely a way to go - even a good one if you have not major parts in that controller switching to different code parts in dependency on the actual command class.

1. But I can not set the CommandClass from the config file. Is there a way to do that? How? Is it a good method to follow?


<property name="commandClass">
<ref bean="customerSearchBeanClass" />
</property>

<bean id="customerSearchBeanClass" class="xxx.CustomerSearchBean" />


You are trying to set the command bean, not the command class. Solution would be


<property name="commandClass" value="xxx.CustomerSearchBean"/>


Or is there a reason why you can't let Spring create an instance of CustomerSearchBean. Tell us about the "nature" of the bean and I can tell you alternatives to inject it if necessary.

2. Even this will have another issue on initBind() since I have to write separate initBind() methods for each type.

Hmm, if you need to do such stuff writing separate controllers might be a better solution. It's probably not the only place where they differ ...

Is there any way to set Binders into a controller through configuration same as validators?

Yes, it is. Use PropertyEditorRegistrar (http://static.springframework.org/spring/docs/2.0.x/api/index.html?org/springframework/beans/PropertyEditorRegistrar.html)s. They are not yet documented in the Spring 2.0.5 reference, but should be in the 2.0.6 which is due (can already be downloaded, but is not yet announced).

So finally what this leads to is -> write separate controllers for each type which extends my AbstractSearchController?

As I said, if there are if's/switch's in your code executing different parts for each command class it's probably better to write one AbstractSearchController and multiple concrete implementations.

Jörg

lkamal
Jun 22nd, 2007, 01:44 AM
My SearchController class has no if's or switches, those are done in a separate Factory. My factory looks for the type of the SearchFormBean that comes in and do the search correctly.

So if I can inject the binders as well, then there no need to write individual concretes that extend the SearchController, but configure those at the config file as I showed in the previous message.

Now I do have about 10 <bean> tags configured with the same class but with different id, commandClass, formView and SuccessView. So this will create 10 different instances of the same class right?

My question is: if I can get the commandClass, formView and SuccessView values also from my factory, would that be a good solution if I set the commandClass also at runtime? I got so many answers for this saying that it's just abusing the spring mvc.

Please let me know what does this means? What is the idea behind having the commandClass set at the initialization (using config or the constructor of the controller)? Why it's considered bad when that is set at runtime depending on a parameter?

Jörg Heinicke
Jun 22nd, 2007, 03:04 AM
So if I can inject the binders as well

As I wrote: use PropertyEditorRegistrars.

So this will create 10 different instances of the same class right?

Yes.

if I can get the commandClass, formView and SuccessView values also from my factory, would that be a good solution if I set the commandClass also at runtime?

If that's preferable you should be able to do it. But I wonder what it buys you since you move the configuration into code. In that case I'd not pass commandClass around, but directly the formBackingObject. You can overwrite the method of the same name and ask your factory for it.

What is the idea behind having the commandClass set at the initialization (using config or the constructor of the controller)? Why it's considered bad when that is set at runtime depending on a parameter?

It was not quite clear from the beginning what you are after. So at least I thought you want to manipulate the state (of which commandClass is a part of) of a stateless controller - which is always a bad idea. What you are doing is actually not setting the commandClass at runtime, but deciding dynamically which one to use. It should never get set on the controller, but always be retrieved from the factory in your case.

Jörg