Scoped Model Driven interceptor in Struts 2 not binding model to session scope

2.2k Views Asked by At

I want to share model(form data) among multiple requests so have implemented ScopedModelDriven Interceptor in the action class.

Below is my code

Model - EventSearchBean.java

public class EventSearchBean {

   private Integer eventId;

   private String location;

   //getters and setters

}

Action - EventSearchAction

public class EventSearchAction implements ScopedModelDriven<EventSearchBean>
{
   private EventSearchBean eventSearchBean;

   public static final String EVENT_MODEL_SESSION_KEY = "eventSearchBean"; 

   public EventSearchBean getModel() {
        return eventSearchBean;
   }

   public String getScopeKey() {
        return EVENT_MODEL_SESSION_KEY;
   }

   public void setModel(EventSearchBean eventSearchBean) {
        this.eventSearchBean = eventSearchBean;  
   }

   public void setScopeKey(String arg0) {
        // TODO Auto-generated method stub
   }

   public String execute();
   {
     String locale = eventSearchBean.getLocation();

     //Calling business service to fetch events based on location
     List<> eventList = eventManager.getEvents(locale);

     return "success";

   }
}

struts.xml

     <!-- old stack used for other action classes -->

    <interceptor-stack name="oldStack">
      <interceptor-ref name="servletConfig"/>
      <interceptor-ref name="modelDriven"/>
      <interceptor-ref name="exception"/>  
      <interceptor-ref name="fileUpload"/>
      <interceptor-ref name="params"/>
    </interceptor-stack>

   <!-- new stack used for EventSearchAction class -->
    <interceptor-stack name="newStack">
      <interceptor-ref name="servletConfig"/>
      <interceptor-ref name="scopedModelDriven"/>
      <interceptor-ref name="exception"/>  
      <interceptor-ref name="fileUpload"/>
      <interceptor-ref name="params"/>
    </interceptor-stack> 

    <action name="eventSearch" class="com.karthik.EventSearchAction">
       <interceptor-ref name="newStack">
         <param  name="scope">session</param>
         <param  name="name">eventSearchBean</param>
         <param  name="className">com.karthik.beans.EventSearchBean</param> 
       </interceptor-ref>
       <result name="success">/jsp/eventlist.jsp</result>
       <result name="error">/jsp/generalExceptionPage.jsp</result>
    </action>

1) New model is getting created on every request(Model data is not getting copied from session for subsequent request). What needs to be changed in code to put model in session scope?
How to make model behave like ActionForm of session scope in Struts1?

2) If I remove new operator in action class while declaring model, that is
private EventSearchBean eventSearchBean;
I get Null Pointer exception when I access model in action class.
How to declare/initialize model?

3) How to override/update model in session only when form is submitted in UI?

2

There are 2 best solutions below

6
Andrea Ligios On

Exploding the defaultStack, this is what you're defining:

<interceptor-stack name="defaultStack">
    <interceptor-ref name="exception"/>
    <interceptor-ref name="alias"/>
    <interceptor-ref name="servletConfig"/>
    <interceptor-ref name="i18n"/>
    <interceptor-ref name="prepare"/>
    <interceptor-ref name="chain"/>
    <interceptor-ref name="scopedModelDriven"/> <!-- here -->
    <interceptor-ref name="modelDriven"/>
    <interceptor-ref name="fileUpload"/>
    <interceptor-ref name="checkbox"/>
    <interceptor-ref name="datetime"/>
    <interceptor-ref name="multiselect"/>
    <interceptor-ref name="staticParams"/>
    <interceptor-ref name="actionMappingParams"/>
    <interceptor-ref name="params"/>
    <interceptor-ref name="conversionError"/>
    <interceptor-ref name="validation">
        <param name="excludeMethods">input,back,cancel,browse</param>
    </interceptor-ref>
    <interceptor-ref name="workflow">
        <param name="excludeMethods">input,back,cancel,browse</param>
    </interceptor-ref>
    <interceptor-ref name="debugging"/>
    <interceptor-ref name="deprecation"/>
</interceptor-stack>

<interceptor-ref name="scopedModelDriven">
    <param  name="scope">session</param>
    <param  name="name">eventSearchBean</param>
    <param  name="className">com.karthik.beans.EventSearchBean</param> 
</interceptor-ref>

As you can see, it already includes the ScopedModelDriven Interceptor. Hence you are defining it twice, the first time in the defaultStack, the second one manually, but only the second has the parameters set, the first has everything empty :)

Then, instead of

<interceptor-ref name="defaultStack"/>
<interceptor-ref name="scopedModelDriven">
    <param  name="scope">session</param>
    <param  name="name">eventSearchBean</param>
    <param  name="className">com.karthik.beans.EventSearchBean</param> 
</interceptor-ref>

just use

<interceptor-ref name="defaultStack">
    <param  name="scopedModelDriven.scope">session</param>
    <param  name="scopedModelDriven.name">eventSearchBean</param>
    <param  name="scopedModelDriven.className">com.karthik.beans.EventSearchBean</param> 
</interceptor-ref>
3
Karthik On
    <interceptor-stack name="newStack">
       <interceptor-ref name="servletConfig"/>
       <interceptor-ref name="scopedModelDriven"/>
       <interceptor-ref name="modelDriven"/>
       <interceptor-ref name="exception"/>  
       <interceptor-ref name="fileUpload"/>
       <interceptor-ref name="params"/>
    </interceptor-stack> 

    <action name="eventSearch" class="com.karthik.EventSearchAction">
       <interceptor-ref name="newStack">
         <param name="scopedModelDriven.scope">session</param>
         <param name="scopedModelDriven.name">eventSearchBean</param>
         <param name="scopedModelDriven.className">com.karthik.beans.EventSearchBean</param> 
       </interceptor-ref>
       <result name="success">/jsp/eventlist.jsp</result>
       <result name="error">/jsp/generalExceptionPage.jsp</result>
    </action>

The following changes were made in the code:

  • If custom stack is used, the custom stack should contain modelDriven interceptor besides scopedModelDriven interceptor.

  • If the params are specified inside the action class as shown above, the params must be prefixed with scopedModelDriven. That is, scopedModelDriven.paramName whereas if scopedModelDriven params are specified within the interceptor stack outside action class, prefix is not required.

  • The model in the action class must not be initialized with new operator. The model has to be just declared. That is, private EventSearchBean eventSearchBean;