001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.bind; 018 019import java.util.ArrayList; 020import java.util.List; 021 022import org.springframework.util.Assert; 023import org.springframework.validation.Errors; 024import org.springframework.validation.FieldError; 025import org.springframework.validation.ObjectError; 026import org.springframework.web.util.HtmlUtils; 027 028/** 029 * Errors wrapper that adds automatic HTML escaping to the wrapped instance, 030 * for convenient usage in HTML views. Can be retrieved easily via 031 * RequestContext's {@code getErrors} method. 032 * 033 * <p>Note that BindTag does <i>not</i> use this class to avoid unnecessary 034 * creation of ObjectError instances. It just escapes the messages and values 035 * that get copied into the respective BindStatus instance. 036 * 037 * @author Juergen Hoeller 038 * @since 01.03.2003 039 * @see org.springframework.web.servlet.support.RequestContext#getErrors 040 * @see org.springframework.web.servlet.tags.BindTag 041 */ 042public class EscapedErrors implements Errors { 043 044 private final Errors source; 045 046 047 /** 048 * Create a new EscapedErrors instance for the given source instance. 049 */ 050 public EscapedErrors(Errors source) { 051 Assert.notNull(source, "Errors source must not be null"); 052 this.source = source; 053 } 054 055 public Errors getSource() { 056 return this.source; 057 } 058 059 060 @Override 061 public String getObjectName() { 062 return this.source.getObjectName(); 063 } 064 065 @Override 066 public void setNestedPath(String nestedPath) { 067 this.source.setNestedPath(nestedPath); 068 } 069 070 @Override 071 public String getNestedPath() { 072 return this.source.getNestedPath(); 073 } 074 075 @Override 076 public void pushNestedPath(String subPath) { 077 this.source.pushNestedPath(subPath); 078 } 079 080 @Override 081 public void popNestedPath() throws IllegalStateException { 082 this.source.popNestedPath(); 083 } 084 085 086 @Override 087 public void reject(String errorCode) { 088 this.source.reject(errorCode); 089 } 090 091 @Override 092 public void reject(String errorCode, String defaultMessage) { 093 this.source.reject(errorCode, defaultMessage); 094 } 095 096 @Override 097 public void reject(String errorCode, Object[] errorArgs, String defaultMessage) { 098 this.source.reject(errorCode, errorArgs, defaultMessage); 099 } 100 101 @Override 102 public void rejectValue(String field, String errorCode) { 103 this.source.rejectValue(field, errorCode); 104 } 105 106 @Override 107 public void rejectValue(String field, String errorCode, String defaultMessage) { 108 this.source.rejectValue(field, errorCode, defaultMessage); 109 } 110 111 @Override 112 public void rejectValue(String field, String errorCode, Object[] errorArgs, String defaultMessage) { 113 this.source.rejectValue(field, errorCode, errorArgs, defaultMessage); 114 } 115 116 @Override 117 public void addAllErrors(Errors errors) { 118 this.source.addAllErrors(errors); 119 } 120 121 122 @Override 123 public boolean hasErrors() { 124 return this.source.hasErrors(); 125 } 126 127 @Override 128 public int getErrorCount() { 129 return this.source.getErrorCount(); 130 } 131 132 @Override 133 public List<ObjectError> getAllErrors() { 134 return escapeObjectErrors(this.source.getAllErrors()); 135 } 136 137 @Override 138 public boolean hasGlobalErrors() { 139 return this.source.hasGlobalErrors(); 140 } 141 142 @Override 143 public int getGlobalErrorCount() { 144 return this.source.getGlobalErrorCount(); 145 } 146 147 @Override 148 public List<ObjectError> getGlobalErrors() { 149 return escapeObjectErrors(this.source.getGlobalErrors()); 150 } 151 152 @Override 153 public ObjectError getGlobalError() { 154 return escapeObjectError(this.source.getGlobalError()); 155 } 156 157 @Override 158 public boolean hasFieldErrors() { 159 return this.source.hasFieldErrors(); 160 } 161 162 @Override 163 public int getFieldErrorCount() { 164 return this.source.getFieldErrorCount(); 165 } 166 167 @Override 168 public List<FieldError> getFieldErrors() { 169 return this.source.getFieldErrors(); 170 } 171 172 @Override 173 public FieldError getFieldError() { 174 return this.source.getFieldError(); 175 } 176 177 @Override 178 public boolean hasFieldErrors(String field) { 179 return this.source.hasFieldErrors(field); 180 } 181 182 @Override 183 public int getFieldErrorCount(String field) { 184 return this.source.getFieldErrorCount(field); 185 } 186 187 @Override 188 public List<FieldError> getFieldErrors(String field) { 189 return escapeObjectErrors(this.source.getFieldErrors(field)); 190 } 191 192 @Override 193 public FieldError getFieldError(String field) { 194 return escapeObjectError(this.source.getFieldError(field)); 195 } 196 197 @Override 198 public Object getFieldValue(String field) { 199 Object value = this.source.getFieldValue(field); 200 return (value instanceof String ? HtmlUtils.htmlEscape((String) value) : value); 201 } 202 203 @Override 204 public Class<?> getFieldType(String field) { 205 return this.source.getFieldType(field); 206 } 207 208 @SuppressWarnings("unchecked") 209 private <T extends ObjectError> T escapeObjectError(T source) { 210 if (source == null) { 211 return null; 212 } 213 if (source instanceof FieldError) { 214 FieldError fieldError = (FieldError) source; 215 Object value = fieldError.getRejectedValue(); 216 if (value instanceof String) { 217 value = HtmlUtils.htmlEscape((String) value); 218 } 219 return (T) new FieldError( 220 fieldError.getObjectName(), fieldError.getField(), value, 221 fieldError.isBindingFailure(), fieldError.getCodes(), 222 fieldError.getArguments(), HtmlUtils.htmlEscape(fieldError.getDefaultMessage())); 223 } 224 else { 225 return (T) new ObjectError( 226 source.getObjectName(), source.getCodes(), source.getArguments(), 227 HtmlUtils.htmlEscape(source.getDefaultMessage())); 228 } 229 } 230 231 private <T extends ObjectError> List<T> escapeObjectErrors(List<T> source) { 232 List<T> escaped = new ArrayList<T>(source.size()); 233 for (T objectError : source) { 234 escaped.add(escapeObjectError(objectError)); 235 } 236 return escaped; 237 } 238 239}