001/*
002 * Copyright 2002-2016 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.messaging.handler.annotation.support;
018
019import java.lang.reflect.Method;
020import java.util.ArrayList;
021import java.util.List;
022
023import org.springframework.beans.factory.BeanFactory;
024import org.springframework.beans.factory.BeanFactoryAware;
025import org.springframework.beans.factory.InitializingBean;
026import org.springframework.beans.factory.config.ConfigurableBeanFactory;
027import org.springframework.core.convert.ConversionService;
028import org.springframework.format.support.DefaultFormattingConversionService;
029import org.springframework.messaging.converter.GenericMessageConverter;
030import org.springframework.messaging.converter.MessageConverter;
031import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
032import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite;
033import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
034import org.springframework.validation.Validator;
035
036/**
037 * The default {@link MessageHandlerMethodFactory} implementation creating an
038 * {@link InvocableHandlerMethod} with the necessary
039 * {@link HandlerMethodArgumentResolver} instances to detect and process
040 * most of the use cases defined by
041 * {@link org.springframework.messaging.handler.annotation.MessageMapping MessageMapping}.
042 *
043 * <p>Extra method argument resolvers can be added to customize the method
044 * signature that can be handled.
045 *
046 * <p>By default, the validation process redirects to a no-op implementation, see
047 * {@link #setValidator(Validator)} to customize it. The {@link ConversionService}
048 * can be customized in a similar manner to tune how the message payload
049 * can be converted
050 *
051 * @author Stephane Nicoll
052 * @author Juergen Hoeller
053 * @since 4.1
054 * @see #setConversionService
055 * @see #setValidator
056 * @see #setCustomArgumentResolvers
057 */
058public class DefaultMessageHandlerMethodFactory implements MessageHandlerMethodFactory, BeanFactoryAware, InitializingBean {
059
060        private ConversionService conversionService = new DefaultFormattingConversionService();
061
062        private MessageConverter messageConverter;
063
064        private Validator validator;
065
066        private List<HandlerMethodArgumentResolver> customArgumentResolvers;
067
068        private final HandlerMethodArgumentResolverComposite argumentResolvers =
069                        new HandlerMethodArgumentResolverComposite();
070
071        private BeanFactory beanFactory;
072
073
074        /**
075         * Set the {@link ConversionService} to use to convert the original
076         * message payload or headers.
077         * @see HeaderMethodArgumentResolver
078         * @see GenericMessageConverter
079         */
080        public void setConversionService(ConversionService conversionService) {
081                this.conversionService = conversionService;
082        }
083
084        /**
085         * Set the {@link MessageConverter} to use. By default a {@link GenericMessageConverter}
086         * is used.
087         * @see GenericMessageConverter
088         */
089        public void setMessageConverter(MessageConverter messageConverter) {
090                this.messageConverter = messageConverter;
091        }
092
093        /**
094         * Set the Validator instance used for validating @Payload arguments
095         * @see org.springframework.validation.annotation.Validated
096         * @see org.springframework.messaging.handler.annotation.support.PayloadArgumentResolver
097         */
098        public void setValidator(Validator validator) {
099                this.validator = validator;
100        }
101
102        /**
103         * Set the list of custom {@code HandlerMethodArgumentResolver}s that will be used
104         * after resolvers for supported argument type.
105         * @param customArgumentResolvers the list of resolvers (never {@code null})
106         */
107        public void setCustomArgumentResolvers(List<HandlerMethodArgumentResolver> customArgumentResolvers) {
108                this.customArgumentResolvers = customArgumentResolvers;
109        }
110
111        /**
112         * Configure the complete list of supported argument types effectively overriding
113         * the ones configured by default. This is an advanced option. For most use cases
114         * it should be sufficient to use {@link #setCustomArgumentResolvers(java.util.List)}.
115         */
116        public void setArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
117                if (argumentResolvers == null) {
118                        this.argumentResolvers.clear();
119                        return;
120                }
121                this.argumentResolvers.addResolvers(argumentResolvers);
122        }
123
124        /**
125         * A {@link BeanFactory} only needs to be available for placeholder resolution
126         * in handler method arguments; it's optional otherwise.
127         */
128        @Override
129        public void setBeanFactory(BeanFactory beanFactory) {
130                this.beanFactory = beanFactory;
131        }
132
133        @Override
134        public void afterPropertiesSet() {
135                if (this.messageConverter == null) {
136                        this.messageConverter = new GenericMessageConverter(this.conversionService);
137                }
138                if (this.argumentResolvers.getResolvers().isEmpty()) {
139                        this.argumentResolvers.addResolvers(initArgumentResolvers());
140                }
141        }
142
143
144        @Override
145        public InvocableHandlerMethod createInvocableHandlerMethod(Object bean, Method method) {
146                InvocableHandlerMethod handlerMethod = new InvocableHandlerMethod(bean, method);
147                handlerMethod.setMessageMethodArgumentResolvers(this.argumentResolvers);
148                return handlerMethod;
149        }
150
151        protected List<HandlerMethodArgumentResolver> initArgumentResolvers() {
152                List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
153                ConfigurableBeanFactory cbf = (this.beanFactory instanceof ConfigurableBeanFactory ?
154                                (ConfigurableBeanFactory) this.beanFactory : null);
155
156                // Annotation-based argument resolution
157                resolvers.add(new HeaderMethodArgumentResolver(this.conversionService, cbf));
158                resolvers.add(new HeadersMethodArgumentResolver());
159
160                // Type-based argument resolution
161                resolvers.add(new MessageMethodArgumentResolver(this.messageConverter));
162
163                if (this.customArgumentResolvers != null) {
164                        resolvers.addAll(this.customArgumentResolvers);
165                }
166                resolvers.add(new PayloadArgumentResolver(this.messageConverter, this.validator));
167
168                return resolvers;
169        }
170
171}