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}