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