17
17
18
18
import java .nio .charset .StandardCharsets ;
19
19
import java .util .ArrayList ;
20
+ import java .util .Arrays ;
20
21
import java .util .Collections ;
21
22
import java .util .HashMap ;
22
23
import java .util .List ;
34
35
import org .springframework .core .io .buffer .NettyDataBuffer ;
35
36
import org .springframework .core .io .buffer .NettyDataBufferFactory ;
36
37
import org .springframework .lang .Nullable ;
37
- import org .springframework .util .Assert ;
38
38
import org .springframework .util .MimeType ;
39
39
40
40
/**
51
51
*/
52
52
public class DefaultMetadataExtractor implements MetadataExtractor {
53
53
54
- private final List <Decoder <?>> decoders = new ArrayList <>() ;
54
+ private final List <Decoder <?>> decoders ;
55
55
56
- private final Map <String , MetadataProcessor <?>> processors = new HashMap <>();
56
+ private final Map <String , EntryExtractor <?>> registrations = new HashMap <>();
57
57
58
58
59
59
/**
60
- * Configure the decoders to use for de-serializing metadata entries.
61
- * <p>By default this is not set.
60
+ * Constructor with decoders for de-serializing metadata entries.
62
61
*/
63
- public void setDecoders (List <? extends Decoder <?>> decoders ) {
64
- this .decoders .clear ();
65
- if (!decoders .isEmpty ()) {
66
- this .decoders .addAll (decoders );
67
- updateProcessors ();
68
- }
62
+ public DefaultMetadataExtractor (Decoder <?>... decoders ) {
63
+ this (Arrays .asList (decoders ));
69
64
}
70
65
71
- @ SuppressWarnings ("unchecked" )
72
- private <T > void updateProcessors () {
73
- for (MetadataProcessor <?> info : this .processors .values ()) {
74
- Decoder <T > decoder = decoderFor (info .mimeType (), info .targetType ());
75
- Assert .isTrue (decoder != null , "No decoder for " + info );
76
- info = ((MetadataProcessor <T >) info ).setDecoder (decoder );
77
- this .processors .put (info .mimeType ().toString (), info );
78
- }
66
+ /**
67
+ * Constructor with list of decoders for de-serializing metadata entries.
68
+ */
69
+ public DefaultMetadataExtractor (List <Decoder <?>> decoders ) {
70
+ this .decoders = Collections .unmodifiableList (new ArrayList <>(decoders ));
79
71
}
80
72
81
- @ Nullable
82
- @ SuppressWarnings ("unchecked" )
83
- private <T > Decoder <T > decoderFor (MimeType mimeType , ResolvableType type ) {
84
- for (Decoder <?> decoder : this .decoders ) {
85
- if (decoder .canDecode (type , mimeType )) {
86
- return (Decoder <T >) decoder ;
87
- }
88
- }
89
- return null ;
90
- }
91
73
92
74
/**
93
- * Return the {@link #setDecoders(List) configured} decoders.
75
+ * Return a read-only list with the configured decoders.
94
76
*/
95
77
public List <? extends Decoder <?>> getDecoders () {
96
78
return this .decoders ;
@@ -106,9 +88,7 @@ public List<? extends Decoder<?>> getDecoders() {
106
88
* @param name assign a name for the decoded value; if not provided, then
107
89
* the mime type is used as the key
108
90
*/
109
- public void metadataToExtract (
110
- MimeType mimeType , Class <?> targetType , @ Nullable String name ) {
111
-
91
+ public void metadataToExtract (MimeType mimeType , Class <?> targetType , @ Nullable String name ) {
112
92
String key = name != null ? name : mimeType .toString ();
113
93
metadataToExtract (mimeType , targetType , (value , map ) -> map .put (key , value ));
114
94
}
@@ -117,6 +97,8 @@ public void metadataToExtract(
117
97
* Variant of {@link #metadataToExtract(MimeType, Class, String)} that accepts
118
98
* {@link ParameterizedTypeReference} instead of {@link Class} for
119
99
* specifying a target type with generic parameters.
100
+ * @param mimeType the mime type of metadata entries to extract
101
+ * @param targetType the target value type to decode to
120
102
*/
121
103
public void metadataToExtract (
122
104
MimeType mimeType , ParameterizedTypeReference <?> targetType , @ Nullable String name ) {
@@ -137,32 +119,36 @@ public void metadataToExtract(
137
119
public <T > void metadataToExtract (
138
120
MimeType mimeType , Class <T > targetType , BiConsumer <T , Map <String , Object >> mapper ) {
139
121
140
- metadataToExtract (mimeType , mapper , ResolvableType .forClass (targetType ));
122
+ registerMetadata (mimeType , ResolvableType .forClass (targetType ), mapper );
141
123
}
142
124
143
125
/**
144
126
* Variant of {@link #metadataToExtract(MimeType, Class, BiConsumer)} that
145
127
* accepts {@link ParameterizedTypeReference} instead of {@link Class} for
146
128
* specifying a target type with generic parameters.
147
129
* @param mimeType the mime type of metadata entries to extract
148
- * @param targetType the target value type to decode to
130
+ * @param type the target value type to decode to
149
131
* @param mapper custom logic to add the decoded value to the output map
150
132
* @param <T> the target value type
151
133
*/
152
134
public <T > void metadataToExtract (
153
- MimeType mimeType , ParameterizedTypeReference <T > targetType ,
154
- BiConsumer <T , Map <String , Object >> mapper ) {
135
+ MimeType mimeType , ParameterizedTypeReference <T > type , BiConsumer <T , Map <String , Object >> mapper ) {
155
136
156
- metadataToExtract (mimeType , mapper , ResolvableType .forType (targetType ) );
137
+ registerMetadata (mimeType , ResolvableType .forType (type ), mapper );
157
138
}
158
139
159
- private <T > void metadataToExtract (
160
- MimeType mimeType , BiConsumer <T , Map <String , Object >> mapper , ResolvableType elementType ) {
140
+ @ SuppressWarnings ("unchecked" )
141
+ private <T > void registerMetadata (
142
+ MimeType mimeType , ResolvableType targetType , BiConsumer <T , Map <String , Object >> mapper ) {
161
143
162
- Decoder <T > decoder = decoderFor (mimeType , elementType );
163
- Assert .isTrue (this .decoders .isEmpty () || decoder != null , () -> "No decoder for " + mimeType );
164
- MetadataProcessor <T > info = new MetadataProcessor <>(mimeType , elementType , mapper , decoder );
165
- this .processors .put (mimeType .toString (), info );
144
+ for (Decoder <?> decoder : this .decoders ) {
145
+ if (decoder .canDecode (targetType , mimeType )) {
146
+ this .registrations .put (mimeType .toString (),
147
+ new EntryExtractor <>((Decoder <T >) decoder , mimeType , targetType , mapper ));
148
+ return ;
149
+ }
150
+ }
151
+ throw new IllegalArgumentException ("No decoder for " + mimeType + " and " + targetType );
166
152
}
167
153
168
154
@@ -171,20 +157,19 @@ public Map<String, Object> extract(Payload payload, MimeType metadataMimeType) {
171
157
Map <String , Object > result = new HashMap <>();
172
158
if (metadataMimeType .equals (COMPOSITE_METADATA )) {
173
159
for (CompositeMetadata .Entry entry : new CompositeMetadata (payload .metadata (), false )) {
174
- processEntry (entry .getContent (), entry .getMimeType (), result );
160
+ extractEntry (entry .getContent (), entry .getMimeType (), result );
175
161
}
176
162
}
177
163
else {
178
- processEntry (payload .metadata (), metadataMimeType .toString (), result );
164
+ extractEntry (payload .metadata (), metadataMimeType .toString (), result );
179
165
}
180
166
return result ;
181
167
}
182
168
183
- @ SuppressWarnings ("unchecked" )
184
- private <T > void processEntry (ByteBuf content , @ Nullable String mimeType , Map <String , Object > result ) {
185
- MetadataProcessor <T > info = (MetadataProcessor <T >) this .processors .get (mimeType );
186
- if (info != null ) {
187
- info .process (content , result );
169
+ private void extractEntry (ByteBuf content , @ Nullable String mimeType , Map <String , Object > result ) {
170
+ EntryExtractor <?> extractor = this .registrations .get (mimeType );
171
+ if (extractor != null ) {
172
+ extractor .extract (content , result );
188
173
return ;
189
174
}
190
175
if (MetadataExtractor .ROUTING .toString ().equals (mimeType )) {
@@ -194,56 +179,32 @@ private <T> void processEntry(ByteBuf content, @Nullable String mimeType, Map<St
194
179
}
195
180
196
181
197
- private static class MetadataProcessor <T > {
182
+ private static class EntryExtractor <T > {
198
183
199
184
private final static NettyDataBufferFactory bufferFactory =
200
185
new NettyDataBufferFactory (PooledByteBufAllocator .DEFAULT );
201
186
202
187
188
+ private final Decoder <T > decoder ;
189
+
203
190
private final MimeType mimeType ;
204
191
205
192
private final ResolvableType targetType ;
206
193
207
194
private final BiConsumer <T , Map <String , Object >> accumulator ;
208
195
209
- @ Nullable
210
- private final Decoder <T > decoder ;
211
-
212
196
213
- MetadataProcessor ( MimeType mimeType , ResolvableType targetType ,
214
- BiConsumer <T , Map <String , Object >> accumulator , @ Nullable Decoder < T > decoder ) {
197
+ EntryExtractor ( Decoder < T > decoder , MimeType mimeType , ResolvableType targetType ,
198
+ BiConsumer <T , Map <String , Object >> accumulator ) {
215
199
200
+ this .decoder = decoder ;
216
201
this .mimeType = mimeType ;
217
202
this .targetType = targetType ;
218
203
this .accumulator = accumulator ;
219
- this .decoder = decoder ;
220
- }
221
-
222
- MetadataProcessor (MetadataProcessor <T > other , Decoder <T > decoder ) {
223
- this .mimeType = other .mimeType ;
224
- this .targetType = other .targetType ;
225
- this .accumulator = other .accumulator ;
226
- this .decoder = decoder ;
227
204
}
228
205
229
206
230
- public MimeType mimeType () {
231
- return this .mimeType ;
232
- }
233
-
234
- public ResolvableType targetType () {
235
- return this .targetType ;
236
- }
237
-
238
- public MetadataProcessor <T > setDecoder (Decoder <T > decoder ) {
239
- return this .decoder != decoder ? new MetadataProcessor <>(this , decoder ) : this ;
240
- }
241
-
242
-
243
- public void process (ByteBuf content , Map <String , Object > result ) {
244
- if (this .decoder == null ) {
245
- throw new IllegalStateException ("No decoder for " + this );
246
- }
207
+ public void extract (ByteBuf content , Map <String , Object > result ) {
247
208
NettyDataBuffer dataBuffer = bufferFactory .wrap (content .retain ());
248
209
T value = this .decoder .decode (dataBuffer , this .targetType , this .mimeType , Collections .emptyMap ());
249
210
this .accumulator .accept (value , result );
@@ -252,7 +213,7 @@ public void process(ByteBuf content, Map<String, Object> result) {
252
213
253
214
@ Override
254
215
public String toString () {
255
- return "MetadataProcessor mimeType=" + this .mimeType + ", targetType=" + this .targetType ;
216
+ return "mimeType=" + this .mimeType + ", targetType=" + this .targetType ;
256
217
}
257
218
}
258
219
0 commit comments