BindStatus.java
上传用户:jiancairen
上传日期:2007-08-27
资源大小:26458k
文件大小:9k
- /*
- * Copyright 2002-2004 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.springframework.web.servlet.support;
- import java.beans.PropertyEditor;
- import java.util.Arrays;
- import java.util.List;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.springframework.beans.BeanWrapperImpl;
- import org.springframework.context.NoSuchMessageException;
- import org.springframework.util.StringUtils;
- import org.springframework.validation.BindException;
- import org.springframework.validation.Errors;
- import org.springframework.validation.ObjectError;
- import org.springframework.web.util.HtmlUtils;
- /**
- * Simple adapter to expose the bind status of a field or object.
- * Set as a variable both by the JSP bind tag and Velocity/FreeMarker macros.
- *
- * <p>Obviously, object status representations (i.e. errors at the object level
- * rather than the field level) do not have an expression and a value but only
- * error codes and messages. For simplicity's sake and to be able to use the same
- * tags and macros, the same status class is used for both scenarios.
- *
- * @author Rod Johnson
- * @author Juergen Hoeller
- * @author Darren Davison
- * @see RequestContext#getBindStatus
- * @see org.springframework.web.servlet.tags.BindTag
- */
- public class BindStatus {
- protected final Log logger = LogFactory.getLog(getClass());
- private final RequestContext requestContext;
- private final String path;
- private final boolean htmlEscape;
- private final String expression;
- private Object value;
- private final String[] errorCodes;
- private final String[] errorMessages;
- private final Errors errors;
- private PropertyEditor editor;
- /**
- * Create a new BindStatus instance, representing a field or object status.
- * @param requestContext the current RequestContext
- * @param path the bean and property path for which values and errors
- * will be resolved (e.g. "customer.address.street")
- * @param htmlEscape whether to HTML-escape error messages and string values
- * @throws IllegalStateException if no corresponding Errors object found
- */
- public BindStatus(RequestContext requestContext, String path, boolean htmlEscape)
- throws IllegalStateException {
- this.requestContext = requestContext;
- this.path = path;
- this.htmlEscape = htmlEscape;
- // determine name of the object and property
- String beanName = null;
- int dotPos = path.indexOf('.');
- if (dotPos == -1) {
- // property not set, only the object itself
- beanName = path;
- this.expression = null;
- }
- else {
- beanName = path.substring(0, dotPos);
- this.expression = path.substring(dotPos + 1);
- }
- this.errors = requestContext.getErrors(beanName, false);
- if (this.errors != null) {
- // Usual case: An Errors instance is available as request attribute.
- // Can determine error codes and messages for the given expression.
- // Can use a custom PropertyEditor, as registered by a form controller.
- List objectErrors = null;
- if (this.expression != null) {
- if ("*".equals(this.expression)) {
- objectErrors = this.errors.getAllErrors();
- }
- else if (this.expression.endsWith("*")) {
- objectErrors = this.errors.getFieldErrors(this.expression);
- }
- else {
- objectErrors = this.errors.getFieldErrors(this.expression);
- this.value = this.errors.getFieldValue(this.expression);
- if (this.errors instanceof BindException) {
- this.editor = ((BindException) this.errors).getCustomEditor(this.expression);
- }
- else {
- if (logger.isDebugEnabled()) {
- logger.debug("Cannot not expose custom property editor because Errors instance [" +
- this.errors + "] is not of type BindException");
- }
- }
- if (htmlEscape && this.value instanceof String) {
- this.value = HtmlUtils.htmlEscape((String) this.value);
- }
- }
- }
- else {
- objectErrors = this.errors.getGlobalErrors();
- }
- this.errorCodes = getErrorCodes(objectErrors);
- this.errorMessages = getErrorMessages(objectErrors);
- }
- else {
- // No Errors instance available as request attribute:
- // Probably forwarded directly to a form view.
- // Let's do the best we can: extract a plain value if appropriate.
- Object target = requestContext.getRequest().getAttribute(beanName);
- if (target == null) {
- throw new IllegalStateException("Neither Errors instance nor plain target object for bean name " +
- beanName + " available as request attribute");
- }
- if (this.expression != null && !"*".equals(this.expression) && !this.expression.endsWith("*")) {
- BeanWrapperImpl bw = new BeanWrapperImpl(target);
- this.value = bw.getPropertyValue(this.expression);
- }
- this.errorCodes = new String[0];
- this.errorMessages = new String[0];
- }
- }
- /**
- * Extract the error codes from the given ObjectError list.
- */
- private String[] getErrorCodes(List objectErrors) {
- String[] codes = new String[objectErrors.size()];
- for (int i = 0; i < objectErrors.size(); i++) {
- ObjectError error = (ObjectError) objectErrors.get(i);
- codes[i] = error.getCode();
- }
- return codes;
- }
- /**
- * Extract the error messages from the given ObjectError list.
- */
- private String[] getErrorMessages(List objectErrors) throws NoSuchMessageException {
- String[] messages = new String[objectErrors.size()];
- for (int i = 0; i < objectErrors.size(); i++) {
- ObjectError error = (ObjectError) objectErrors.get(i);
- messages[i] = this.requestContext.getMessage(error, this.htmlEscape);
- }
- return messages;
- }
- /**
- * Return the bean and property path for which values and errors
- * will be resolved (e.g. "customer.address.street").
- */
- public String getPath() {
- return path;
- }
- /**
- * Return a bind expression that can be used in HTML forms as input name
- * for the respective field, or null if not field-specific.
- * <p>Returns a bind path appropriate for resubmission, e.g. "address.street".
- * Note that the complete bind path as required by the bind tag is
- * "customer.address.street", if bound to a "customer" bean.
- */
- public String getExpression() {
- return expression;
- }
- /**
- * Return the current value of the field, i.e. either the property value
- * or a rejected update, or null if not field-specific.
- */
- public Object getValue() {
- return value;
- }
- /**
- * Return a suitable display value for the field, i.e. empty string
- * instead of a null value, or null if not field-specific.
- */
- public String getDisplayValue() {
- return (this.value != null) ? this.value.toString() : "";
- }
- /**
- * Return if this status represents a field or object error.
- */
- public boolean isError() {
- return (this.errorCodes != null && this.errorCodes.length > 0);
- }
- /**
- * Return the error codes for the field or object, if any.
- * Returns an empty array instead of null if none.
- */
- public String[] getErrorCodes() {
- return errorCodes;
- }
- /**
- * Return the first error codes for the field or object, if any.
- */
- public String getErrorCode() {
- return (this.errorCodes.length > 0 ? this.errorCodes[0] : "");
- }
- /**
- * Return the resolved error messages for the field or object,
- * if any. Returns an empty array instead of null if none.
- */
- public String[] getErrorMessages() {
- return errorMessages;
- }
- /**
- * Return the first error message for the field or object, if any.
- */
- public String getErrorMessage() {
- return (this.errorMessages.length > 0 ? this.errorMessages[0] : "");
- }
- /**
- * Return an error message string, concatenating all messages
- * separated by the given delimiter.
- * @param delimiter separator string, e.g. ", " or "<br>"
- * @return the error message string
- */
- public String getErrorMessagesAsString(String delimiter) {
- return StringUtils.arrayToDelimitedString(this.errorMessages, delimiter);
- }
- /**
- * Return the Errors instance that this bind status is currently bound to.
- * @return the current Errors instance, or null if none
- */
- public Errors getErrors() {
- return errors;
- }
- /**
- * Return the PropertyEditor for the property that this bind status
- * is currently bound to.
- * @return the current PropertyEditor, or null if none
- */
- public PropertyEditor getEditor() {
- return editor;
- }
- public String toString() {
- StringBuffer sb = new StringBuffer("BindStatus: ");
- sb.append("expression=[").append(this.expression).append("]; ");
- sb.append("value=[").append(this.value).append("]");
- if (isError()) {
- sb.append("; errorCodes='" + Arrays.asList(this.errorCodes) + "'; ");
- sb.append("errorMessages='" + Arrays.asList(this.errorMessages));
- }
- return sb.toString();
- }
- }