1
1
/*
2
- * Copyright 2014-2019 the original author or authors.
2
+ * Copyright 2014-2021 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
18
18
19
19
import java .beans .Introspector ;
20
20
import java .util .ArrayList ;
21
+ import java .util .HashMap ;
21
22
import java .util .List ;
22
23
import java .util .Map ;
23
24
import java .util .Map .Entry ;
24
25
import java .util .Set ;
26
+ import java .util .concurrent .Executor ;
27
+ import java .util .stream .Collectors ;
25
28
26
29
import org .springframework .beans .factory .BeanDefinitionStoreException ;
27
30
import org .springframework .beans .factory .FactoryBean ;
28
31
import org .springframework .beans .factory .config .BeanDefinition ;
29
32
import org .springframework .beans .factory .config .BeanDefinitionHolder ;
33
+ import org .springframework .beans .factory .config .ConfigurableBeanFactory ;
34
+ import org .springframework .beans .factory .config .EmbeddedValueResolver ;
30
35
import org .springframework .beans .factory .support .AbstractBeanDefinition ;
31
- import org .springframework .beans .factory .support .BeanDefinitionBuilder ;
32
36
import org .springframework .beans .factory .support .BeanDefinitionReaderUtils ;
33
37
import org .springframework .beans .factory .support .BeanDefinitionRegistry ;
34
- import org .springframework .beans .factory .support .ManagedMap ;
35
38
import org .springframework .beans .factory .support .RootBeanDefinition ;
39
+ import org .springframework .context .ConfigurableApplicationContext ;
36
40
import org .springframework .context .annotation .ImportBeanDefinitionRegistrar ;
37
41
import org .springframework .core .type .AnnotationMetadata ;
42
+ import org .springframework .expression .Expression ;
43
+ import org .springframework .expression .ExpressionParser ;
38
44
import org .springframework .expression .common .LiteralExpression ;
45
+ import org .springframework .expression .spel .standard .SpelExpressionParser ;
39
46
import org .springframework .integration .annotation .AnnotationConstants ;
40
47
import org .springframework .integration .annotation .MessagingGateway ;
41
48
import org .springframework .integration .gateway .GatewayMethodMetadata ;
42
49
import org .springframework .integration .gateway .GatewayProxyFactoryBean ;
50
+ import org .springframework .integration .gateway .MethodArgsMessageMapper ;
43
51
import org .springframework .integration .util .MessagingAnnotationUtils ;
44
52
import org .springframework .util .Assert ;
53
+ import org .springframework .util .ClassUtils ;
45
54
import org .springframework .util .MultiValueMap ;
46
55
import org .springframework .util .ObjectUtils ;
47
56
import org .springframework .util .StringUtils ;
58
67
*/
59
68
public class MessagingGatewayRegistrar implements ImportBeanDefinitionRegistrar {
60
69
70
+ private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser ();
71
+
61
72
private static final String PROXY_DEFAULT_METHODS_ATTR = "proxyDefaultMethods" ;
62
73
63
74
@ Override
@@ -72,11 +83,14 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B
72
83
annotationAttributes .put ("serviceInterface" , importingClassMetadata .getClassName ());
73
84
annotationAttributes .put (PROXY_DEFAULT_METHODS_ATTR ,
74
85
"" + annotationAttributes .remove (PROXY_DEFAULT_METHODS_ATTR ));
75
- BeanDefinitionReaderUtils .registerBeanDefinition (parse (annotationAttributes ), registry );
86
+ BeanDefinitionReaderUtils .registerBeanDefinition (gatewayProxyBeanDefinition (annotationAttributes , registry ),
87
+ registry );
76
88
}
77
89
}
78
90
79
- public BeanDefinitionHolder parse (Map <String , Object > gatewayAttributes ) { // NOSONAR complexity
91
+ public BeanDefinitionHolder gatewayProxyBeanDefinition (Map <String , Object > gatewayAttributes ,
92
+ BeanDefinitionRegistry registry ) {
93
+
80
94
String defaultPayloadExpression = (String ) gatewayAttributes .get ("defaultPayloadExpression" );
81
95
82
96
@ SuppressWarnings ("unchecked" )
@@ -98,89 +112,143 @@ public BeanDefinitionHolder parse(Map<String, Object> gatewayAttributes) { // NO
98
112
Assert .state (!hasMapper || !hasDefaultHeaders ,
99
113
"'defaultHeaders' are not allowed when a 'mapper' is provided" );
100
114
101
- BeanDefinitionBuilder gatewayProxyBuilder =
102
- BeanDefinitionBuilder .genericBeanDefinition (GatewayProxyFactoryBean .class );
103
-
104
- if (hasDefaultHeaders || hasDefaultPayloadExpression ) {
105
- BeanDefinitionBuilder methodMetadataBuilder =
106
- BeanDefinitionBuilder .genericBeanDefinition (GatewayMethodMetadata .class );
115
+ ConfigurableBeanFactory beanFactory = obtainBeanFactory (registry );
116
+ EmbeddedValueResolver embeddedValueResolver = new EmbeddedValueResolver (beanFactory );
117
+ Class <?> serviceInterface = getServiceInterface ((String ) gatewayAttributes .get ("serviceInterface" ), beanFactory );
107
118
108
- if (hasDefaultPayloadExpression ) {
109
- methodMetadataBuilder .addPropertyValue ("payloadExpression" ,
110
- BeanDefinitionBuilder .genericBeanDefinition (ExpressionFactoryBean .class )
111
- .addConstructorArgValue (defaultPayloadExpression )
112
- .getBeanDefinition ());
113
- }
119
+ @ SuppressWarnings ("unchecked" )
120
+ AbstractBeanDefinition beanDefinition = new RootBeanDefinition (GatewayProxyFactoryBean .class ,
121
+ () -> {
122
+ GatewayProxyFactoryBean proxyFactoryBean = new GatewayProxyFactoryBean (serviceInterface );
123
+ if (StringUtils .hasText (defaultRequestChannel )) {
124
+ proxyFactoryBean .setDefaultRequestChannelName (defaultRequestChannel );
125
+ }
126
+ if (StringUtils .hasText (defaultReplyChannel )) {
127
+ proxyFactoryBean .setDefaultReplyChannelName (defaultReplyChannel );
128
+ }
129
+ if (StringUtils .hasText (errorChannel )) {
130
+ proxyFactoryBean .setErrorChannelName (errorChannel );
131
+ }
132
+ if (StringUtils .hasText (proxyDefaultMethods )) {
133
+ boolean actualProxyDefaultMethods =
134
+ Boolean .parseBoolean (embeddedValueResolver .resolveStringValue (proxyDefaultMethods ));
135
+ proxyFactoryBean .setProxyDefaultMethods (actualProxyDefaultMethods );
136
+ }
137
+ if (StringUtils .hasText (mapper )) {
138
+ proxyFactoryBean .setMapper (beanFactory .getBean (mapper , MethodArgsMessageMapper .class ));
139
+ }
114
140
115
- if (hasDefaultHeaders ) {
116
- Map < String , Object > headerExpressions = new ManagedMap <>( );
117
- for ( Map < String , Object > header : defaultHeaders ) {
118
- String headerValue = ( String ) header . get ( "value" );
119
- String headerExpression = ( String ) header . get ( "expression" );
120
- boolean hasValue = StringUtils . hasText ( headerValue );
141
+ if (asyncExecutor == null || AnnotationConstants . NULL . equals ( asyncExecutor ) ) {
142
+ proxyFactoryBean . setAsyncExecutor ( null );
143
+ }
144
+ else if ( StringUtils . hasText ( asyncExecutor )) {
145
+ proxyFactoryBean . setAsyncExecutor ( beanFactory . getBean ( asyncExecutor , Executor . class ) );
146
+ }
121
147
122
- if (hasValue == StringUtils .hasText (headerExpression )) {
123
- throw new BeanDefinitionStoreException ("exactly one of 'value' or 'expression' " +
124
- "is required on a gateway's header." );
148
+ if (hasDefaultHeaders || hasDefaultPayloadExpression ) {
149
+ GatewayMethodMetadata globalMethodMetadata =
150
+ createGlobalMethodMetadata (defaultPayloadExpression , defaultHeaders ,
151
+ hasDefaultPayloadExpression , hasDefaultHeaders , embeddedValueResolver );
152
+ proxyFactoryBean .setGlobalMethodMetadata (globalMethodMetadata );
125
153
}
126
154
127
- BeanDefinition expressionDef =
128
- new RootBeanDefinition (hasValue ? LiteralExpression .class : ExpressionFactoryBean .class );
129
- expressionDef .getConstructorArgumentValues ()
130
- .addGenericArgumentValue (hasValue ? headerValue : headerExpression );
155
+ Map <String , AbstractBeanDefinition > methodDefinitions =
156
+ (Map <String , AbstractBeanDefinition >) gatewayAttributes .get ("methods" );
131
157
132
- headerExpressions .put ((String ) header .get ("name" ), expressionDef );
133
- }
134
- methodMetadataBuilder .addPropertyValue ("headerExpressions" , headerExpressions );
135
- }
158
+ if (methodDefinitions != null ) {
159
+ Map <String , GatewayMethodMetadata > methodMetadataMap =
160
+ methodDefinitions .entrySet ()
161
+ .stream ()
162
+ .collect (Collectors .toMap (Entry ::getKey ,
163
+ entry -> (GatewayMethodMetadata ) entry .getValue ().getInstanceSupplier ().get ()));
136
164
137
- gatewayProxyBuilder . addPropertyValue ( "globalMethodMetadata" , methodMetadataBuilder . getBeanDefinition () );
138
- }
165
+ proxyFactoryBean . setMethodMetadataMap ( methodMetadataMap );
166
+ }
139
167
168
+ String actualDefaultRequestTimeout =
169
+ embeddedValueResolver .resolveStringValue (
170
+ (String ) gatewayAttributes .get ("defaultRequestTimeout" ));
171
+ if (actualDefaultRequestTimeout != null ) {
172
+ proxyFactoryBean .setDefaultRequestTimeoutExpressionString (actualDefaultRequestTimeout );
173
+ }
174
+ String actualDefaultReplyTimeout =
175
+ embeddedValueResolver .resolveStringValue (
176
+ (String ) gatewayAttributes .get ("defaultReplyTimeout" ));
177
+ if (actualDefaultReplyTimeout != null ) {
178
+ proxyFactoryBean .setDefaultReplyTimeoutExpressionString (actualDefaultReplyTimeout );
179
+ }
180
+ return proxyFactoryBean ;
181
+ });
140
182
141
- if (StringUtils .hasText (defaultRequestChannel )) {
142
- gatewayProxyBuilder .addPropertyValue ("defaultRequestChannelName" , defaultRequestChannel );
143
- }
144
- if (StringUtils .hasText (defaultReplyChannel )) {
145
- gatewayProxyBuilder .addPropertyValue ("defaultReplyChannelName" , defaultReplyChannel );
183
+ String id = (String ) gatewayAttributes .get ("name" );
184
+ if (!StringUtils .hasText (id )) {
185
+ String serviceInterfaceName = serviceInterface .getName ();
186
+ id = Introspector .decapitalize (serviceInterfaceName .substring (serviceInterfaceName .lastIndexOf ('.' ) + 1 ));
146
187
}
147
- if (StringUtils .hasText (errorChannel )) {
148
- gatewayProxyBuilder .addPropertyValue ("errorChannelName" , errorChannel );
188
+
189
+ beanDefinition .setAttribute (FactoryBean .OBJECT_TYPE_ATTRIBUTE , serviceInterface );
190
+ return new BeanDefinitionHolder (beanDefinition , id );
191
+ }
192
+
193
+ private static ConfigurableBeanFactory obtainBeanFactory (BeanDefinitionRegistry registry ) {
194
+ if (registry instanceof ConfigurableBeanFactory ) {
195
+ return (ConfigurableBeanFactory ) registry ;
149
196
}
150
- if (asyncExecutor == null || AnnotationConstants . NULL . equals ( asyncExecutor ) ) {
151
- gatewayProxyBuilder . addPropertyValue ( "asyncExecutor" , null );
197
+ else if (registry instanceof ConfigurableApplicationContext ) {
198
+ return (( ConfigurableApplicationContext ) registry ). getBeanFactory ( );
152
199
}
153
- else if (StringUtils .hasText (asyncExecutor )) {
154
- gatewayProxyBuilder .addPropertyReference ("asyncExecutor" , asyncExecutor );
200
+ throw new IllegalArgumentException ("The provided 'BeanDefinitionRegistry' must be an instance " +
201
+ "of 'ConfigurableBeanFactory' or 'ConfigurableApplicationContext', but given is: "
202
+ + registry .getClass ());
203
+ }
204
+
205
+ private static Class <?> getServiceInterface (String serviceInterface , ConfigurableBeanFactory beanFactory ) {
206
+ String actualServiceInterface = beanFactory .resolveEmbeddedValue (serviceInterface );
207
+ if (!StringUtils .hasText (actualServiceInterface )) {
208
+ return org .springframework .integration .gateway .RequestReplyExchanger .class ;
155
209
}
156
- if ( StringUtils . hasText ( mapper )) {
157
- gatewayProxyBuilder . addPropertyReference ( "mapper" , mapper );
210
+ try {
211
+ return ClassUtils . forName ( actualServiceInterface , beanFactory . getBeanClassLoader () );
158
212
}
159
- if ( StringUtils . hasText ( proxyDefaultMethods ) ) {
160
- gatewayProxyBuilder . addPropertyValue ( PROXY_DEFAULT_METHODS_ATTR , proxyDefaultMethods );
213
+ catch ( ClassNotFoundException ex ) {
214
+ throw new BeanDefinitionStoreException ( "Cannot parse class for service interface" , ex );
161
215
}
216
+ }
162
217
163
- gatewayProxyBuilder .addPropertyValue ("defaultRequestTimeoutExpressionString" ,
164
- gatewayAttributes .get ("defaultRequestTimeout" ));
165
- gatewayProxyBuilder .addPropertyValue ("defaultReplyTimeoutExpressionString" ,
166
- gatewayAttributes .get ("defaultReplyTimeout" ));
167
- gatewayProxyBuilder .addPropertyValue ("methodMetadataMap" , gatewayAttributes .get ("methods" ));
218
+ private static GatewayMethodMetadata createGlobalMethodMetadata (String defaultPayloadExpression ,
219
+ Map <String , Object >[] defaultHeaders , boolean hasDefaultPayloadExpression ,
220
+ boolean hasDefaultHeaders , EmbeddedValueResolver embeddedValueResolver ) {
168
221
222
+ GatewayMethodMetadata gatewayMethodMetadata = new GatewayMethodMetadata ();
169
223
170
- String serviceInterface = (String ) gatewayAttributes .get ("serviceInterface" );
171
- if (!StringUtils .hasText (serviceInterface )) {
172
- serviceInterface = "org.springframework.integration.gateway.RequestReplyExchanger" ;
173
- }
174
- String id = (String ) gatewayAttributes .get ("name" );
175
- if (!StringUtils .hasText (id )) {
176
- id = Introspector .decapitalize (serviceInterface .substring (serviceInterface .lastIndexOf ('.' ) + 1 ));
224
+ if (hasDefaultPayloadExpression ) {
225
+ String actualPayloadExpression = embeddedValueResolver .resolveStringValue (defaultPayloadExpression );
226
+ gatewayMethodMetadata .setPayloadExpression (EXPRESSION_PARSER .parseExpression (actualPayloadExpression ));
177
227
}
178
228
179
- gatewayProxyBuilder .addConstructorArgValue (serviceInterface );
229
+ if (hasDefaultHeaders ) {
230
+ Map <String , Expression > headerExpressions = new HashMap <>();
231
+ for (Map <String , Object > header : defaultHeaders ) {
232
+ String headerValue = (String ) header .get ("value" );
233
+ String headerExpression = (String ) header .get ("expression" );
234
+ boolean hasValue = StringUtils .hasText (headerValue );
180
235
181
- AbstractBeanDefinition beanDefinition = gatewayProxyBuilder .getBeanDefinition ();
182
- beanDefinition .setAttribute (FactoryBean .OBJECT_TYPE_ATTRIBUTE , serviceInterface );
183
- return new BeanDefinitionHolder (beanDefinition , id );
236
+ if (hasValue == StringUtils .hasText (headerExpression )) {
237
+ throw new BeanDefinitionStoreException ("exactly one of 'value' or 'expression' " +
238
+ "is required on a gateway's header." );
239
+ }
240
+
241
+ Expression expression =
242
+ hasValue
243
+ ? new LiteralExpression (embeddedValueResolver .resolveStringValue (headerValue ))
244
+ : EXPRESSION_PARSER .parseExpression (
245
+ embeddedValueResolver .resolveStringValue (headerExpression ));
246
+
247
+ headerExpressions .put ((String ) header .get ("name" ), expression );
248
+ }
249
+ gatewayMethodMetadata .setHeaderExpressions (headerExpressions );
250
+ }
251
+ return gatewayMethodMetadata ;
184
252
}
185
253
186
254
/**
0 commit comments