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.servlet.mvc.support; 018 019import java.util.Collection; 020import java.util.Map; 021 022import org.springframework.ui.ModelMap; 023import org.springframework.validation.DataBinder; 024 025/** 026 * A {@link ModelMap} implementation of {@link RedirectAttributes} that formats 027 * values as Strings using a {@link DataBinder}. Also provides a place to store 028 * flash attributes so they can survive a redirect without the need to be 029 * embedded in the redirect URL. 030 * 031 * @author Rossen Stoyanchev 032 * @since 3.1 033 */ 034@SuppressWarnings("serial") 035public class RedirectAttributesModelMap extends ModelMap implements RedirectAttributes { 036 037 private final DataBinder dataBinder; 038 039 private final ModelMap flashAttributes = new ModelMap(); 040 041 042 /** 043 * Default constructor without a DataBinder. 044 * Attribute values are converted to String via {@link #toString()}. 045 */ 046 public RedirectAttributesModelMap() { 047 this(null); 048 } 049 050 /** 051 * Constructor with a DataBinder. 052 * @param dataBinder used to format attribute values as Strings 053 */ 054 public RedirectAttributesModelMap(DataBinder dataBinder) { 055 this.dataBinder = dataBinder; 056 } 057 058 059 /** 060 * Return the attributes candidate for flash storage or an empty Map. 061 */ 062 @Override 063 public Map<String, ?> getFlashAttributes() { 064 return this.flashAttributes; 065 } 066 067 /** 068 * {@inheritDoc} 069 * <p>Formats the attribute value as a String before adding it. 070 */ 071 @Override 072 public RedirectAttributesModelMap addAttribute(String attributeName, Object attributeValue) { 073 super.addAttribute(attributeName, formatValue(attributeValue)); 074 return this; 075 } 076 077 private String formatValue(Object value) { 078 if (value == null) { 079 return null; 080 } 081 return (this.dataBinder != null ? this.dataBinder.convertIfNecessary(value, String.class) : value.toString()); 082 } 083 084 /** 085 * {@inheritDoc} 086 * <p>Formats the attribute value as a String before adding it. 087 */ 088 @Override 089 public RedirectAttributesModelMap addAttribute(Object attributeValue) { 090 super.addAttribute(attributeValue); 091 return this; 092 } 093 094 /** 095 * {@inheritDoc} 096 * <p>Each attribute value is formatted as a String before being added. 097 */ 098 @Override 099 public RedirectAttributesModelMap addAllAttributes(Collection<?> attributeValues) { 100 super.addAllAttributes(attributeValues); 101 return this; 102 } 103 104 /** 105 * {@inheritDoc} 106 * <p>Each attribute value is formatted as a String before being added. 107 */ 108 @Override 109 public RedirectAttributesModelMap addAllAttributes(Map<String, ?> attributes) { 110 if (attributes != null) { 111 for (String key : attributes.keySet()) { 112 addAttribute(key, attributes.get(key)); 113 } 114 } 115 return this; 116 } 117 118 /** 119 * {@inheritDoc} 120 * <p>Each attribute value is formatted as a String before being merged. 121 */ 122 @Override 123 public RedirectAttributesModelMap mergeAttributes(Map<String, ?> attributes) { 124 if (attributes != null) { 125 for (String key : attributes.keySet()) { 126 if (!containsKey(key)) { 127 addAttribute(key, attributes.get(key)); 128 } 129 } 130 } 131 return this; 132 } 133 134 @Override 135 public Map<String, Object> asMap() { 136 return this; 137 } 138 139 /** 140 * {@inheritDoc} 141 * <p>The value is formatted as a String before being added. 142 */ 143 @Override 144 public Object put(String key, Object value) { 145 return super.put(key, formatValue(value)); 146 } 147 148 /** 149 * {@inheritDoc} 150 * <p>Each value is formatted as a String before being added. 151 */ 152 @Override 153 public void putAll(Map<? extends String, ? extends Object> map) { 154 if (map != null) { 155 for (String key : map.keySet()) { 156 put(key, formatValue(map.get(key))); 157 } 158 } 159 } 160 161 @Override 162 public RedirectAttributes addFlashAttribute(String attributeName, Object attributeValue) { 163 this.flashAttributes.addAttribute(attributeName, attributeValue); 164 return this; 165 } 166 167 @Override 168 public RedirectAttributes addFlashAttribute(Object attributeValue) { 169 this.flashAttributes.addAttribute(attributeValue); 170 return this; 171 } 172 173}