How to perform XML Validation when using ModelDriven?

783 views Asked by At

I've created a Struts2 project in which I used XML based validation. Model class RegistrationForm is shown below

package com.projects;

import com.opensymphony.xwork2.ActionSupport;

public class RegistrationForm implements Serializable{

   private static final long serialVersionUID = 1L;
   private String fname;
   private String lname;
   private int numbr;

  public int getNumbr() {
   return numbr;
  }
  public void setNumbr(int numbr) {
     this.numbr = numbr;
  }
  public String getFname() {
    return fname;
  }
  public void setFname(String fname) {
    this.fname = fname;
  }
  public String getLname() {
    return lname;
  }
  public void setLname(String lname) {
    this.lname = lname;
  }
}

RegistrationFormAction.Java

package com.projects;

import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

public class RegistrationFormAction extends ActionSupport implements ModelDriven<RegistrationForm> {
 private RegistrationForm registrationForm;
 public RegistrationForm getRegistrationForm() {
  return registrationForm;
 }
 public void setRegistrationForm(RegistrationForm registrationForm) {
   this.registrationForm = registrationForm;
 }

 public RegistrationForm getModel(){
  registrationForm=new RegistrationForm();
  return registrationForm;
 }
 public String execute(){
    return "success";
 }
}

struts.xml

<?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE struts PUBLIC
   "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
   "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>

 <constant name="struts.devMode" value="true" />
 <package name="dd" extends="struts-default">

  <interceptors>
       <interceptor-stack name="defaultStack">
         <interceptor-ref name="exception" />
         <interceptor-ref name="alias" />
         <interceptor-ref name="servletConfig" />
         <interceptor-ref name="prepare" />
         <interceptor-ref name="i18n" />
         <interceptor-ref name="chain" />
         <interceptor-ref name="debugging" />
         <interceptor-ref name="profiling" />
         <interceptor-ref name="scopedModelDriven" />
         <interceptor-ref name="modelDriven" />
         <interceptor-ref name="params"/>
         <interceptor-ref name="validation"/>
         <interceptor-ref name="fileUpload" />
         <interceptor-ref name="checkbox" />
         <interceptor-ref name="staticParams" />
         <interceptor-ref name="conversionError" />
         <interceptor-ref name="workflow"/>
      </interceptor-stack>
    </interceptors>

      <action name="submitForm" class="com.projects.RegistrationFormAction">
         <interceptor-ref name="defaultStack" />
        <result name="success">/WelcomePage.jsp</result>
        <result name="input">/RegistrationForm.jsp</result>
  </action>
</package>
</struts>

RegistrationFormAction-validation.xml

<!DOCTYPE validators PUBLIC 
"-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> 

<validators>
<field name="registrationform">
      <field-validator type="visitor">
      <param name="appendPrefix">false</param>
     <message/>
    </field-validator>
 </field>

</validators>

RegistrationForm-validation.xml

 <!DOCTYPE validators PUBLIC 
"-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> 

<validators>
 <field name="fname">
  <field-validator type="requiredstring">
  <message>First Name can't be blank</message>
</field-validator>
</field>

<field name="lname">
  <field-validator type="requiredstring">
   <message>Last Name can't be blank</message>
  </field-validator>
 </field>
<field name="numbr">
  <field-validator type="int">
    <param name="min">1</param>
    <param name="max">10</param>
  <message>Number between 1 to 10</message>
 </field-validator>
 </field>
</validators>

but validation is not working.

1

There are 1 answers

1
Andrea Ligios On BEST ANSWER

There are a lot of things goin' on here! I'll post them in order of appearance in the question:

  1. Never make a POJO extends ActionSupport:

    public class RegistrationForm extends ActionSupport {
    

    must become

    public class RegistrationForm implements Serializable {
    
  2. Better returning SUCCESS than "success" to prevent typos (but ok this is secondary);

  3. The intercetpor stack customization has four problems:

    • you are overriding the existing basicStack, this risks to violate the POLA, especially if other people will work on this project; it's better to use a custom name instead, eg. myStack;

    • you are using only three interceptors, and this is suspicious; while many of the default interceptors can be dropped, many others instead should be always kept, especially with validation involved, eg. ConversionError Interceptor, or Workflow Interceptor, etc. Read how the whole thing works. As a rule, you should remove an Interceptor only when you know exactly what it does and you are absolutely sure you don't (and won't) need it.

    • When using ModelDriven (that is usually not recommended, because basically useless and source of problems when not experts with it), you need to put the ModelDriven Interceptor before the Parameters Interceptor, otherwise when the parameters interceptor runs, the model won't be pushed yet, and the setters will be searched on the action, eg. setFname(), instead that on the model (resulting in null properties in the model, and in the warning

      Unexpected Exception caught setting 'fname' on 'class RegistrationFormAction: Error setting expression 'fname' with value ['Sumit', ]

      because of the missing setters in the action).

    • Finally, if you are really using the code you posted, then you are NOT using the wrong stack you've created, because 1) The default one is the defaultStack, not the basicStack, so overriding basicStack has no effects, and 2) you've not used <default-interceptor-ref> to change the default stack reference, nor you've used the <interceptor-ref> inside the <action> tag to specify a different interceptor stack for that action only.
  4. You are mixing 1.0.2 and 1.0.3 in DOCTYPE of XML validation files, make everything 1.0.3 (and notice that they migrated from OpenSymphony to Apache); then change:

    <!DOCTYPE validators PUBLIC   
        "-//OpenSymphony Group//XWork Validator 1.0.2//EN"   
        "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
    

    to

    <!DOCTYPE validators PUBLIC 
        "-//Apache Struts//XWork Validator 1.0.3//EN"
        "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">  
    
  5. Ensure that the RegistrationFormAction-validation.xml file is in the action folder, while the RegistrationForm-validation.xml is in the RegistrationForm.java folder.

  6. Consider avoiding ModelDriven, because as Stephen Young says,

    You Must Tame Complexity to Become a Better Programmer

  7. As pointed out by AleksandrM's comment, there is also a typo in

    <field name="registrationform"> 
    

    that should be

    <field name="registrationForm">