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.reactive.result.method.annotation;
018
019import org.springframework.beans.factory.config.ConfigurableBeanFactory;
020import org.springframework.core.MethodParameter;
021import org.springframework.core.ReactiveAdapterRegistry;
022import org.springframework.http.HttpCookie;
023import org.springframework.lang.Nullable;
024import org.springframework.util.Assert;
025import org.springframework.web.bind.annotation.CookieValue;
026import org.springframework.web.server.ServerWebExchange;
027import org.springframework.web.server.ServerWebInputException;
028
029/**
030 * Resolve method arguments annotated with {@code @CookieValue}.
031 *
032 * <p>An {@code @CookieValue} is a named value that is resolved from a cookie.
033 * It has a required flag and a default value to fall back on when the cookie
034 * does not exist.
035 *
036 * @author Rossen Stoyanchev
037 * @since 5.0
038 */
039public class CookieValueMethodArgumentResolver extends AbstractNamedValueSyncArgumentResolver {
040
041        /**
042         * Create a new {@link CookieValueMethodArgumentResolver} instance.
043         * @param factory a bean factory to use for resolving {@code ${...}}
044         * placeholder and {@code #{...}} SpEL expressions in default values;
045         * or {@code null} if default values are not expected to contain expressions
046         * @param registry for checking reactive type wrappers
047         */
048        public CookieValueMethodArgumentResolver(@Nullable ConfigurableBeanFactory factory,
049                        ReactiveAdapterRegistry registry) {
050
051                super(factory, registry);
052        }
053
054
055        @Override
056        public boolean supportsParameter(MethodParameter param) {
057                return checkAnnotatedParamNoReactiveWrapper(param, CookieValue.class, (annot, type) -> true);
058        }
059
060        @Override
061        protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
062                CookieValue ann = parameter.getParameterAnnotation(CookieValue.class);
063                Assert.state(ann != null, "No CookieValue annotation");
064                return new CookieValueNamedValueInfo(ann);
065        }
066
067        @Override
068        protected Object resolveNamedValue(String name, MethodParameter parameter, ServerWebExchange exchange) {
069                HttpCookie cookie = exchange.getRequest().getCookies().getFirst(name);
070                Class<?> paramType = parameter.getNestedParameterType();
071                if (HttpCookie.class.isAssignableFrom(paramType)) {
072                        return cookie;
073                }
074                return (cookie != null ? cookie.getValue() : null);
075        }
076
077        @Override
078        protected void handleMissingValue(String name, MethodParameter parameter) {
079                String type = parameter.getNestedParameterType().getSimpleName();
080                String reason = "Missing cookie '" + name + "' for method parameter of type " + type;
081                throw new ServerWebInputException(reason, parameter);
082        }
083
084
085        private static final class CookieValueNamedValueInfo extends NamedValueInfo {
086
087                private CookieValueNamedValueInfo(CookieValue annotation) {
088                        super(annotation.name(), annotation.required(), annotation.defaultValue());
089                }
090        }
091
092}