001/* 002 * Copyright 2002-2012 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.support; 018 019import org.springframework.beans.PropertyEditorRegistrar; 020import org.springframework.core.convert.ConversionService; 021import org.springframework.validation.BindingErrorProcessor; 022import org.springframework.validation.MessageCodesResolver; 023import org.springframework.validation.Validator; 024import org.springframework.web.bind.WebDataBinder; 025import org.springframework.web.context.request.WebRequest; 026 027/** 028 * Convenient {@link WebBindingInitializer} for declarative configuration 029 * in a Spring application context. Allows for reusing pre-configured 030 * initializers with multiple controller/handlers. 031 * 032 * @author Juergen Hoeller 033 * @since 2.5 034 * @see #setDirectFieldAccess 035 * @see #setMessageCodesResolver 036 * @see #setBindingErrorProcessor 037 * @see #setValidator(Validator) 038 * @see #setConversionService(ConversionService) 039 * @see #setPropertyEditorRegistrar 040 */ 041public class ConfigurableWebBindingInitializer implements WebBindingInitializer { 042 043 private boolean autoGrowNestedPaths = true; 044 045 private boolean directFieldAccess = false; 046 047 private MessageCodesResolver messageCodesResolver; 048 049 private BindingErrorProcessor bindingErrorProcessor; 050 051 private Validator validator; 052 053 private ConversionService conversionService; 054 055 private PropertyEditorRegistrar[] propertyEditorRegistrars; 056 057 058 /** 059 * Set whether a binder should attempt to "auto-grow" a nested path that contains a null value. 060 * <p>If "true", a null path location will be populated with a default object value and traversed 061 * instead of resulting in an exception. This flag also enables auto-growth of collection elements 062 * when accessing an out-of-bounds index. 063 * <p>Default is "true" on a standard DataBinder. Note that this feature is only supported 064 * for bean property access (DataBinder's default mode), not for field access. 065 * @see org.springframework.validation.DataBinder#initBeanPropertyAccess() 066 * @see org.springframework.validation.DataBinder#setAutoGrowNestedPaths 067 */ 068 public void setAutoGrowNestedPaths(boolean autoGrowNestedPaths) { 069 this.autoGrowNestedPaths = autoGrowNestedPaths; 070 } 071 072 /** 073 * Return whether a binder should attempt to "auto-grow" a nested path that contains a null value. 074 */ 075 public boolean isAutoGrowNestedPaths() { 076 return this.autoGrowNestedPaths; 077 } 078 079 /** 080 * Set whether to use direct field access instead of bean property access. 081 * <p>Default is {@code false}, using bean property access. 082 * Switch this to {@code true} in order to enforce direct field access. 083 * @see org.springframework.validation.DataBinder#initDirectFieldAccess() 084 * @see org.springframework.validation.DataBinder#initBeanPropertyAccess() 085 */ 086 public final void setDirectFieldAccess(boolean directFieldAccess) { 087 this.directFieldAccess = directFieldAccess; 088 } 089 090 /** 091 * Return whether to use direct field access instead of bean property access. 092 */ 093 public boolean isDirectFieldAccess() { 094 return directFieldAccess; 095 } 096 097 /** 098 * Set the strategy to use for resolving errors into message codes. 099 * Applies the given strategy to all data binders used by this controller. 100 * <p>Default is {@code null}, i.e. using the default strategy of 101 * the data binder. 102 * @see org.springframework.validation.DataBinder#setMessageCodesResolver 103 */ 104 public final void setMessageCodesResolver(MessageCodesResolver messageCodesResolver) { 105 this.messageCodesResolver = messageCodesResolver; 106 } 107 108 /** 109 * Return the strategy to use for resolving errors into message codes. 110 */ 111 public final MessageCodesResolver getMessageCodesResolver() { 112 return this.messageCodesResolver; 113 } 114 115 /** 116 * Set the strategy to use for processing binding errors, that is, 117 * required field errors and {@code PropertyAccessException}s. 118 * <p>Default is {@code null}, that is, using the default strategy 119 * of the data binder. 120 * @see org.springframework.validation.DataBinder#setBindingErrorProcessor 121 */ 122 public final void setBindingErrorProcessor(BindingErrorProcessor bindingErrorProcessor) { 123 this.bindingErrorProcessor = bindingErrorProcessor; 124 } 125 126 /** 127 * Return the strategy to use for processing binding errors. 128 */ 129 public final BindingErrorProcessor getBindingErrorProcessor() { 130 return this.bindingErrorProcessor; 131 } 132 133 /** 134 * Set the Validator to apply after each binding step. 135 */ 136 public final void setValidator(Validator validator) { 137 this.validator = validator; 138 } 139 140 /** 141 * Return the Validator to apply after each binding step, if any. 142 */ 143 public final Validator getValidator() { 144 return this.validator; 145 } 146 147 /** 148 * Specify a ConversionService which will apply to every DataBinder. 149 * @since 3.0 150 */ 151 public final void setConversionService(ConversionService conversionService) { 152 this.conversionService = conversionService; 153 } 154 155 /** 156 * Return the ConversionService which will apply to every DataBinder. 157 */ 158 public final ConversionService getConversionService() { 159 return this.conversionService; 160 } 161 162 /** 163 * Specify a single PropertyEditorRegistrar to be applied to every DataBinder. 164 */ 165 public final void setPropertyEditorRegistrar(PropertyEditorRegistrar propertyEditorRegistrar) { 166 this.propertyEditorRegistrars = new PropertyEditorRegistrar[] {propertyEditorRegistrar}; 167 } 168 169 /** 170 * Specify multiple PropertyEditorRegistrars to be applied to every DataBinder. 171 */ 172 public final void setPropertyEditorRegistrars(PropertyEditorRegistrar[] propertyEditorRegistrars) { 173 this.propertyEditorRegistrars = propertyEditorRegistrars; 174 } 175 176 /** 177 * Return the PropertyEditorRegistrars to be applied to every DataBinder. 178 */ 179 public final PropertyEditorRegistrar[] getPropertyEditorRegistrars() { 180 return this.propertyEditorRegistrars; 181 } 182 183 184 @Override 185 public void initBinder(WebDataBinder binder, WebRequest request) { 186 binder.setAutoGrowNestedPaths(this.autoGrowNestedPaths); 187 if (this.directFieldAccess) { 188 binder.initDirectFieldAccess(); 189 } 190 if (this.messageCodesResolver != null) { 191 binder.setMessageCodesResolver(this.messageCodesResolver); 192 } 193 if (this.bindingErrorProcessor != null) { 194 binder.setBindingErrorProcessor(this.bindingErrorProcessor); 195 } 196 if (this.validator != null && binder.getTarget() != null && 197 this.validator.supports(binder.getTarget().getClass())) { 198 binder.setValidator(this.validator); 199 } 200 if (this.conversionService != null) { 201 binder.setConversionService(this.conversionService); 202 } 203 if (this.propertyEditorRegistrars != null) { 204 for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) { 205 propertyEditorRegistrar.registerCustomEditors(binder); 206 } 207 } 208 } 209 210}