You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@struts.apache.org by "Shannon, Andrew" <an...@pqa.com> on 2008/06/06 14:59:12 UTC
s2 : custom expression validator - evaluates null properties
After doing some research on how the struts2 ognl stack implementation
works when attempting to find a null
value on the value stack (essentially it returns nothing when evaluating
an expression), I had to figure out a work
around for a special case to handle some Long type properties. I saw a
few posts from a while back where others
seem to have wrestled with the same issue. I believe the stack
implementation is just fine, so I came up with this
validator to solve my problem. Maybe this can help someone else out
too.
------------------------------------------------------------------------
-------------------------------
package x.y.z.web.validator;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.util.TextParseUtil;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.validator.ValidationException;
import com.opensymphony.xwork2.validator.validators.ValidatorSupport;
/**
* CustomExpressionValidator
* <p/>
* The purpose for this validator is to allow us to evaluate null
properties
* on the value stack. The reason for this is that expressions are
interpreted
* to populate the properties with values in the expression string, and
if a property
* is null on the value stack, then no value is placed into the string
and the
* resulting expression is essentially useless and cannot evaluate.
* <p/>
* The tactic employed in this validator is to leverage some control
over how the
* expression is populated by introducing a ParsedValueEvaluator that
will return a
* string value of "null" into the expression when the property value is
null.
* <p/>
* The resulting string is then executed against the value stack as any
other expression.
* <p/>
* This validator will return a boolean value of true or false.
* <p/>
* This example was developed because there was a conditional pair of
query string parameters
* that needed to be validated. If it was just one param then the more
appropriate validation
* is to use the @RequiredFieldValidator.
* <p/>
* private Long requiredIdOne;
* private Long requiredIdTwo;
* <p/>
* public Long getRequiredIdOne() {
* return requiredIdOne;
* }
*<p/>
* public void setRequiredIdOne(final Long requiredIdOne) {
* this.requiredIdOne = requiredIdOne;
* }
*<p/>
* public Long getRequiredIdTwo() {
* return requiredIdTwo;
* }
* <p/>
* public void setRequiredIdTwo(final Long requiredIdTwo) {
* this.requiredIdTwo = requiredIdTwo;
* }
* <p/>
* @Validations(
* customValidators = {
* @CustomValidator(
* type = "customExpressionValidator",
* message = "",
* key = "validation.idQueryStringParameter.required",
* parameters = {@ValidationParameter(
* name = "expression",
* value = "((${requiredIdOne} != null) ||
(${requiredIdTwo} != null))"
* + "&& !((${requiredIdOne} != null) &&
(${requiredIdTwo} != null))")})
* }
* )
* public String actionMethod() {
* return Action.SUCCESS;
* }
* <p/>
* <p/>
* You must delimit the property to be found on the stack using ${...}
notation.
* <p/>
* This notation is used by the text parser methods in TextParseUtil.
* <p/>
* Don't forget to put an entry for your validator in validators.xml.
* A JMock test was used to prove this validator works, as well as
actual implementation.
* JMock MockObjectTestCase's are very effective for testing/developing
validtors since all
* the Struts2 ingredients are easily created or mocked.
* <p/>
*/
public final class CustomExpressionValidator extends ValidatorSupport {
private String expression;
public void setExpression(final String expression) {
this.expression = expression;
}
public String getExpression() {
return expression;
}
public void validate(final Object object) throws ValidationException
{
ValueStack stack = ActionContext.getContext().getValueStack();
// Create the expression string by populating it with property
// values off the stack.
String parsedObject = TextParseUtil.translateVariables(
expression, stack, new
TextParseUtil.ParsedValueEvaluator() {
public Object evaluate(final Object parsedValue) {
if (parsedValue != null) {
return parsedValue.toString();
}
// This string value of null will be inserted into the
expression when
// the saught after property defined as ${property} is
null on the stack. It
// will indeed be evaluated as null when the expression
is executed against
// the stack.
return "null";
}
});
// Evaluate the expression string against the stack.
Object obj = stack.findValue(parsedObject);
Boolean answer = Boolean.FALSE;
if (obj != null && Boolean.valueOf(obj.toString()) instanceof
Boolean) {
answer = Boolean.valueOf(obj.toString());
} else {
log.error("Got result of " + obj + " when trying to get
Boolean from CustomExpressionValidator");
}
if (!answer.booleanValue()) {
addActionError(object);
}
}
}
Andrew Shannon
Senior Associate
Perrin Quarles Associates
andrewshannon@pqa.com