001/*
002 * Copyright 2002-2019 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 java.util.Map;
020
021import org.springframework.core.MethodParameter;
022import org.springframework.core.ReactiveAdapterRegistry;
023import org.springframework.ui.Model;
024import org.springframework.web.reactive.BindingContext;
025import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverSupport;
026import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver;
027import org.springframework.web.server.ServerWebExchange;
028
029/**
030 * Resolver for a controller method argument of type {@link Model} that can
031 * also be resolved as a {@link java.util.Map}.
032 *
033 * <p>A Map return value can be interpreted in more than one ways depending
034 * on the presence of annotations like {@code @ModelAttribute} or
035 * {@code @ResponseBody}. As of 5.2 this resolver returns false if a
036 * parameter of type {@code Map} is also annotated.
037 *
038 * @author Rossen Stoyanchev
039 * @since 5.2
040 */
041public class ModelMethodArgumentResolver extends HandlerMethodArgumentResolverSupport
042                implements SyncHandlerMethodArgumentResolver {
043
044        public ModelMethodArgumentResolver(ReactiveAdapterRegistry adapterRegistry) {
045                super(adapterRegistry);
046        }
047
048
049        @Override
050        public boolean supportsParameter(MethodParameter param) {
051                return checkParameterTypeNoReactiveWrapper(param, type ->
052                                Model.class.isAssignableFrom(type) ||
053                                                (Map.class.isAssignableFrom(type) && param.getParameterAnnotations().length == 0));
054        }
055
056        @Override
057        public Object resolveArgumentValue(
058                        MethodParameter parameter, BindingContext context, ServerWebExchange exchange) {
059
060                Class<?> type = parameter.getParameterType();
061                if (Model.class.isAssignableFrom(type)) {
062                        return context.getModel();
063                }
064                else if (Map.class.isAssignableFrom(type)) {
065                        return context.getModel().asMap();
066                }
067                else {
068                        // Should never happen..
069                        throw new IllegalStateException("Unexpected method parameter type: " + type);
070                }
071        }
072
073}