001/* 002 * Copyright 2002-2018 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.method.annotation; 018 019import java.util.Map; 020 021import org.springframework.beans.factory.config.ConfigurableBeanFactory; 022import org.springframework.core.MethodParameter; 023import org.springframework.lang.Nullable; 024import org.springframework.util.Assert; 025import org.springframework.web.bind.MissingRequestHeaderException; 026import org.springframework.web.bind.ServletRequestBindingException; 027import org.springframework.web.bind.WebDataBinder; 028import org.springframework.web.bind.annotation.RequestHeader; 029import org.springframework.web.context.request.NativeWebRequest; 030 031/** 032 * Resolves method arguments annotated with {@code @RequestHeader} except for 033 * {@link Map} arguments. See {@link RequestHeaderMapMethodArgumentResolver} for 034 * details on {@link Map} arguments annotated with {@code @RequestHeader}. 035 * 036 * <p>An {@code @RequestHeader} is a named value resolved from a request header. 037 * It has a required flag and a default value to fall back on when the request 038 * header does not exist. 039 * 040 * <p>A {@link WebDataBinder} is invoked to apply type conversion to resolved 041 * request header values that don't yet match the method parameter type. 042 * 043 * @author Arjen Poutsma 044 * @author Rossen Stoyanchev 045 * @since 3.1 046 */ 047public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { 048 049 /** 050 * Create a new {@link RequestHeaderMethodArgumentResolver} instance. 051 * @param beanFactory a bean factory to use for resolving ${...} 052 * placeholder and #{...} SpEL expressions in default values; 053 * or {@code null} if default values are not expected to have expressions 054 */ 055 public RequestHeaderMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory) { 056 super(beanFactory); 057 } 058 059 060 @Override 061 public boolean supportsParameter(MethodParameter parameter) { 062 return (parameter.hasParameterAnnotation(RequestHeader.class) && 063 !Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())); 064 } 065 066 @Override 067 protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) { 068 RequestHeader ann = parameter.getParameterAnnotation(RequestHeader.class); 069 Assert.state(ann != null, "No RequestHeader annotation"); 070 return new RequestHeaderNamedValueInfo(ann); 071 } 072 073 @Override 074 @Nullable 075 protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception { 076 String[] headerValues = request.getHeaderValues(name); 077 if (headerValues != null) { 078 return (headerValues.length == 1 ? headerValues[0] : headerValues); 079 } 080 else { 081 return null; 082 } 083 } 084 085 @Override 086 protected void handleMissingValue(String name, MethodParameter parameter) throws ServletRequestBindingException { 087 throw new MissingRequestHeaderException(name, parameter); 088 } 089 090 091 private static final class RequestHeaderNamedValueInfo extends NamedValueInfo { 092 093 private RequestHeaderNamedValueInfo(RequestHeader annotation) { 094 super(annotation.name(), annotation.required(), annotation.defaultValue()); 095 } 096 } 097 098}