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