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.multipart.support; 018 019import java.util.ArrayList; 020import java.util.Collection; 021import java.util.List; 022import javax.servlet.http.HttpServletRequest; 023import javax.servlet.http.Part; 024 025import org.springframework.core.MethodParameter; 026import org.springframework.core.ResolvableType; 027import org.springframework.util.ClassUtils; 028import org.springframework.web.multipart.MultipartException; 029import org.springframework.web.multipart.MultipartFile; 030import org.springframework.web.multipart.MultipartHttpServletRequest; 031import org.springframework.web.util.WebUtils; 032 033/** 034 * A common delegate for {@code HandlerMethodArgumentResolver} implementations 035 * which need to resolve {@link MultipartFile} and {@link Part} arguments. 036 * 037 * @author Juergen Hoeller 038 * @since 4.3 039 */ 040public abstract class MultipartResolutionDelegate { 041 042 public static final Object UNRESOLVABLE = new Object(); 043 044 045 private static Class<?> servletPartClass = null; 046 047 static { 048 try { 049 servletPartClass = ClassUtils.forName("javax.servlet.http.Part", 050 MultipartResolutionDelegate.class.getClassLoader()); 051 } 052 catch (ClassNotFoundException ex) { 053 // Servlet 3.0 javax.servlet.http.Part type not available - 054 // Part references simply not supported then. 055 } 056 } 057 058 059 public static boolean isMultipartRequest(HttpServletRequest request) { 060 return (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null || 061 isMultipartContent(request)); 062 } 063 064 private static boolean isMultipartContent(HttpServletRequest request) { 065 String contentType = request.getContentType(); 066 return (contentType != null && contentType.toLowerCase().startsWith("multipart/")); 067 } 068 069 static MultipartHttpServletRequest asMultipartHttpServletRequest(HttpServletRequest request) { 070 MultipartHttpServletRequest unwrapped = WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class); 071 if (unwrapped != null) { 072 return unwrapped; 073 } 074 return adaptToMultipartHttpServletRequest(request); 075 } 076 077 private static MultipartHttpServletRequest adaptToMultipartHttpServletRequest(HttpServletRequest request) { 078 if (servletPartClass != null) { 079 // Servlet 3.0 available .. 080 return new StandardMultipartHttpServletRequest(request); 081 } 082 throw new MultipartException("Expected MultipartHttpServletRequest: is a MultipartResolver configured?"); 083 } 084 085 086 public static boolean isMultipartArgument(MethodParameter parameter) { 087 Class<?> paramType = parameter.getNestedParameterType(); 088 return (MultipartFile.class == paramType || 089 isMultipartFileCollection(parameter) || isMultipartFileArray(parameter) || 090 (servletPartClass != null && (servletPartClass == paramType || 091 isPartCollection(parameter) || isPartArray(parameter)))); 092 } 093 094 public static Object resolveMultipartArgument(String name, MethodParameter parameter, HttpServletRequest request) 095 throws Exception { 096 097 MultipartHttpServletRequest multipartRequest = 098 WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class); 099 boolean isMultipart = (multipartRequest != null || isMultipartContent(request)); 100 101 if (MultipartFile.class == parameter.getNestedParameterType()) { 102 if (multipartRequest == null && isMultipart) { 103 multipartRequest = adaptToMultipartHttpServletRequest(request); 104 } 105 return (multipartRequest != null ? multipartRequest.getFile(name) : null); 106 } 107 else if (isMultipartFileCollection(parameter)) { 108 if (multipartRequest == null && isMultipart) { 109 multipartRequest = adaptToMultipartHttpServletRequest(request); 110 } 111 return (multipartRequest != null ? multipartRequest.getFiles(name) : null); 112 } 113 else if (isMultipartFileArray(parameter)) { 114 if (multipartRequest == null && isMultipart) { 115 multipartRequest = adaptToMultipartHttpServletRequest(request); 116 } 117 if (multipartRequest != null) { 118 List<MultipartFile> multipartFiles = multipartRequest.getFiles(name); 119 return multipartFiles.toArray(new MultipartFile[multipartFiles.size()]); 120 } 121 else { 122 return null; 123 } 124 } 125 else if (servletPartClass != null) { 126 if (servletPartClass == parameter.getNestedParameterType()) { 127 return (isMultipart ? RequestPartResolver.resolvePart(request, name) : null); 128 } 129 else if (isPartCollection(parameter)) { 130 return (isMultipart ? RequestPartResolver.resolvePartList(request, name) : null); 131 } 132 else if (isPartArray(parameter)) { 133 return (isMultipart ? RequestPartResolver.resolvePartArray(request, name) : null); 134 } 135 } 136 return UNRESOLVABLE; 137 } 138 139 private static boolean isMultipartFileCollection(MethodParameter methodParam) { 140 return (MultipartFile.class == getCollectionParameterType(methodParam)); 141 } 142 143 private static boolean isMultipartFileArray(MethodParameter methodParam) { 144 return (MultipartFile.class == methodParam.getNestedParameterType().getComponentType()); 145 } 146 147 private static boolean isPartCollection(MethodParameter methodParam) { 148 return (servletPartClass == getCollectionParameterType(methodParam)); 149 } 150 151 private static boolean isPartArray(MethodParameter methodParam) { 152 return (servletPartClass == methodParam.getNestedParameterType().getComponentType()); 153 } 154 155 private static Class<?> getCollectionParameterType(MethodParameter methodParam) { 156 Class<?> paramType = methodParam.getNestedParameterType(); 157 if (Collection.class == paramType || List.class.isAssignableFrom(paramType)){ 158 Class<?> valueType = ResolvableType.forMethodParameter(methodParam).asCollection().resolveGeneric(); 159 if (valueType != null) { 160 return valueType; 161 } 162 } 163 return null; 164 } 165 166 167 /** 168 * Inner class to avoid hard-coded dependency on Servlet 3.0 Part type... 169 */ 170 private static class RequestPartResolver { 171 172 public static Object resolvePart(HttpServletRequest servletRequest, String name) throws Exception { 173 return servletRequest.getPart(name); 174 } 175 176 public static Object resolvePartList(HttpServletRequest servletRequest, String name) throws Exception { 177 Collection<Part> parts = servletRequest.getParts(); 178 List<Part> result = new ArrayList<Part>(parts.size()); 179 for (Part part : parts) { 180 if (part.getName().equals(name)) { 181 result.add(part); 182 } 183 } 184 return result; 185 } 186 187 public static Object resolvePartArray(HttpServletRequest servletRequest, String name) throws Exception { 188 Collection<Part> parts = servletRequest.getParts(); 189 List<Part> result = new ArrayList<Part>(parts.size()); 190 for (Part part : parts) { 191 if (part.getName().equals(name)) { 192 result.add(part); 193 } 194 } 195 return result.toArray(new Part[result.size()]); 196 } 197 } 198 199}