Hello,
I have been having a little trouble with the interceptor stack but I have quite
a bit of info, so
I'm hoping someone can help me out.
Here it goes:
I created my own interceptor stack with the following:
[code]
<interceptor-stack name="crudStack">
<interceptor-ref name="token"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="params"/>
<interceptor-ref name="user"/> <----------- Note this interceptor
<interceptor-ref name="prepare"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation"/>
<interceptor-ref name="workflow"/>
</interceptor-stack>
[/code]
The user interceptor which I created puts the user into the value stack.
However
I noticed for some forms the xwork validation RequiredStringValidator
started failing even though the input was valid.
For example, the following form fails validation [shortened for explanation
purposes]:
[code]
<!-- Form to save a collection name -->
<s:form method="post" >
<s:textfield label="%{getText('name')}" name="collectionName"/>
</s:form>
[/code]
However this form works [shortened for explanation purposes]:
<!-- Form to save a language type -->
<s:form method="post">
<s:textfield label="%{getText('name')}" name="languageType.name"/>
</s:form>
Notice the difference is the first one I am setting the value directly on
the action where in the second form, I am setting a value on an object
within the action.
Furthermore, When I change the stack to the following both forms work:
[code]
<interceptor-stack name="crudStack">
<interceptor-ref name="token"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="params"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation"/>
<interceptor-ref name="workflow"/>
<interceptor-ref name="user"/> <----------- Moved interceptor to
bottom of stack
</interceptor-stack>
[/code]
I did some more digging and I found the difference is:
When ognl is able to find the value itself in the tree
for the validator a string rather than an array with a single value is retuned
causing the validation to pass.
So when ognl.java executes the following method:
[code]
public static Object getValue( Object tree, Map context, Object root, Class
resultType ) throws OgnlException
{
Object result;
OgnlContext ognlContext = (OgnlContext)addDefaultContext(root,
context);
result = ((Node)tree).getValue( ognlContext, root );
if (resultType != null) {
result = getTypeConverter( context ).convertValue( context, root,
null, null, result, resultType);
}
return result;
}
[/code]
For the SECOND form, which passes, the code:
result = ((Node)tree).getValue( ognlContext, root );
finds a value and returns however,
for the FIRST form, which fails, ognl gets a null from:
result = ((Node)tree).getValue( ognlContext, root );
and executes then executes:
result = getTypeConverter( context ).convertValue( context, root, null, null,
result, resultType);
which is actually a call to:
com.opensymphony.xwork2.util.XWorkMapPropertyAccessor.getProperty(Map context,
Object target, Object name)
which delegates to its parent class method:
ognl.MapPropertyAccessor.getProperty(context, target, name)
Now, this actually finds the value and returns it as a string array with a
single value. It returns this array
to the RequiredStringValidator so in the validate(Object object) method the
following code evaluates
to true because a String[] is not an instance of String:
[code]
if (!(value instanceof String)) {
addFieldError(fieldName, object);
}
[/code]
If you have any thoughts, they would be greatly appreciated.
Thanks again,
-Nate