27
27
28
28
import org .reactivestreams .Publisher ;
29
29
import reactor .core .publisher .Flux ;
30
- import reactor .core .publisher .Mono ;
31
30
32
31
import org .springframework .core .ResolvableType ;
33
32
import org .springframework .core .io .buffer .DataBuffer ;
36
35
import org .springframework .core .io .buffer .PooledDataBuffer ;
37
36
import org .springframework .core .log .LogFormatUtils ;
38
37
import org .springframework .lang .Nullable ;
39
- import org .springframework .util .Assert ;
40
38
import org .springframework .util .MimeType ;
41
39
import org .springframework .util .MimeTypeUtils ;
42
40
@@ -59,25 +57,26 @@ public final class StringDecoder extends AbstractDataBufferDecoder<String> {
59
57
60
58
private static final DataBuffer END_FRAME = new DefaultDataBufferFactory ().wrap (new byte [0 ]);
61
59
62
- /**
63
- * The default charset to use, i.e. "UTF-8".
64
- */
60
+ /** The default charset to use, i.e. "UTF-8". */
65
61
public static final Charset DEFAULT_CHARSET = StandardCharsets .UTF_8 ;
66
62
67
- /**
68
- * The default delimiter strings to use, i.e. {@code \n} and {@code \r\n}.
69
- */
63
+ /** The default delimiter strings to use, i.e. {@code \r\n} and {@code \n}. */
70
64
public static final List <String > DEFAULT_DELIMITERS = Arrays .asList ("\r \n " , "\n " );
71
65
66
+ private static final List <byte []> DEFAULT_DELIMITER_BYTES = DEFAULT_DELIMITERS .stream ()
67
+ .map (s -> s .getBytes (StandardCharsets .UTF_8 ))
68
+ .collect (Collectors .toList ());
72
69
70
+
71
+ @ Nullable
73
72
private final List <String > delimiters ;
74
73
75
74
private final boolean stripDelimiter ;
76
75
77
- private StringDecoder (List <String > delimiters , boolean stripDelimiter , MimeType ... mimeTypes ) {
76
+
77
+ private StringDecoder (@ Nullable List <String > delimiters , boolean stripDelimiter , MimeType ... mimeTypes ) {
78
78
super (mimeTypes );
79
- Assert .notEmpty (delimiters , "'delimiters' must not be empty" );
80
- this .delimiters = new ArrayList <>(delimiters );
79
+ this .delimiters = delimiters != null ? new ArrayList <>(delimiters ) : null ;
81
80
this .stripDelimiter = stripDelimiter ;
82
81
}
83
82
@@ -92,36 +91,32 @@ public boolean canDecode(ResolvableType elementType, @Nullable MimeType mimeType
92
91
public Flux <String > decode (Publisher <DataBuffer > inputStream , ResolvableType elementType ,
93
92
@ Nullable MimeType mimeType , @ Nullable Map <String , Object > hints ) {
94
93
95
- List <byte []> delimiterBytes = getDelimiterBytes (mimeType );
94
+ List <byte []> delimiterBytes = this .delimiters != null ?
95
+ this .delimiters .stream ().map (s -> s .getBytes (getCharset (mimeType ))).collect (Collectors .toList ()) :
96
+ DEFAULT_DELIMITER_BYTES ;
96
97
97
98
Flux <DataBuffer > inputFlux = Flux .from (inputStream )
98
- .flatMap (dataBuffer -> splitOnDelimiter (dataBuffer , delimiterBytes ))
99
+ .flatMapIterable (dataBuffer -> splitOnDelimiter (dataBuffer , delimiterBytes ))
99
100
.bufferUntil (StringDecoder ::isEndFrame )
100
- .flatMap (StringDecoder ::joinUntilEndFrame )
101
+ .map (StringDecoder ::joinUntilEndFrame )
101
102
.doOnDiscard (PooledDataBuffer .class , DataBufferUtils ::release );
102
- return super .decode (inputFlux , elementType , mimeType , hints );
103
- }
104
103
105
- private List <byte []> getDelimiterBytes (@ Nullable MimeType mimeType ) {
106
- Charset charset = getCharset (mimeType );
107
- return this .delimiters .stream ()
108
- .map (s -> s .getBytes (charset ))
109
- .collect (Collectors .toList ());
104
+ return super .decode (inputFlux , elementType , mimeType , hints );
110
105
}
111
106
112
107
/**
113
108
* Splits the given data buffer on delimiter boundaries. The returned Flux contains a
114
109
* {@link #END_FRAME} buffer after each delimiter.
115
110
*/
116
- private Flux <DataBuffer > splitOnDelimiter (DataBuffer dataBuffer , List <byte []> delimiterBytes ) {
111
+ private List <DataBuffer > splitOnDelimiter (DataBuffer dataBuffer , List <byte []> delimiterBytes ) {
117
112
List <DataBuffer > frames = new ArrayList <>();
118
113
do {
119
114
int length = Integer .MAX_VALUE ;
120
115
byte [] matchingDelimiter = null ;
121
116
for (byte [] delimiter : delimiterBytes ) {
122
- int idx = indexOf (dataBuffer , delimiter );
123
- if (idx >= 0 && idx < length ) {
124
- length = idx ;
117
+ int index = indexOf (dataBuffer , delimiter );
118
+ if (index >= 0 && index < length ) {
119
+ length = index ;
125
120
matchingDelimiter = delimiter ;
126
121
}
127
122
}
@@ -148,12 +143,12 @@ private Flux<DataBuffer> splitOnDelimiter(DataBuffer dataBuffer, List<byte[]> de
148
143
while (dataBuffer .readableByteCount () > 0 );
149
144
150
145
DataBufferUtils .release (dataBuffer );
151
- return Flux . fromIterable ( frames ) ;
146
+ return frames ;
152
147
}
153
148
154
149
/**
155
- * Finds the given delimiter in the given data buffer. Return the index of the delimiter, or
156
- * -1 if not found.
150
+ * Find the given delimiter in the given data buffer.
151
+ * @return the index of the delimiter, or -1 if not found.
157
152
*/
158
153
private static int indexOf (DataBuffer dataBuffer , byte [] delimiter ) {
159
154
for (int i = dataBuffer .readPosition (); i < dataBuffer .writePosition (); i ++) {
@@ -172,7 +167,6 @@ private static int indexOf(DataBuffer dataBuffer, byte[] delimiter) {
172
167
}
173
168
delimiterPos ++;
174
169
}
175
-
176
170
if (delimiterPos == delimiter .length ) {
177
171
return i - dataBuffer .readPosition ();
178
172
}
@@ -188,17 +182,17 @@ private static boolean isEndFrame(DataBuffer dataBuffer) {
188
182
}
189
183
190
184
/**
191
- * Joins the given list of buffers into a single buffer.
185
+ * Joins the given list of buffers into a single buffer, also removing
186
+ * the (inserted) {@link #END_FRAME}.
192
187
*/
193
- private static Mono < DataBuffer > joinUntilEndFrame (List <DataBuffer > dataBuffers ) {
188
+ private static DataBuffer joinUntilEndFrame (List <DataBuffer > dataBuffers ) {
194
189
if (!dataBuffers .isEmpty ()) {
195
190
int lastIdx = dataBuffers .size () - 1 ;
196
191
if (isEndFrame (dataBuffers .get (lastIdx ))) {
197
192
dataBuffers .remove (lastIdx );
198
193
}
199
194
}
200
- Flux <DataBuffer > flux = Flux .fromIterable (dataBuffers );
201
- return DataBufferUtils .join (flux );
195
+ return dataBuffers .get (0 ).factory ().join (dataBuffers );
202
196
}
203
197
204
198
@ Override
@@ -241,15 +235,18 @@ public static StringDecoder textPlainOnly(boolean ignored) {
241
235
* Create a {@code StringDecoder} for {@code "text/plain"}.
242
236
*/
243
237
public static StringDecoder textPlainOnly () {
244
- return textPlainOnly (DEFAULT_DELIMITERS , true );
238
+ return textPlainOnly (null , true );
245
239
}
246
240
247
241
/**
248
242
* Create a {@code StringDecoder} for {@code "text/plain"}.
243
+ * @param delimiters delimiter strings to use to split the input stream, if
244
+ * {@code null} by default {@link #DEFAULT_DELIMITERS} is used.
245
+ * @param stripDelimiter whether to remove delimiters from the resulting
246
+ * input strings.
249
247
*/
250
- public static StringDecoder textPlainOnly (List <String > delimiters , boolean stripDelimiter ) {
251
- return new StringDecoder (delimiters , stripDelimiter ,
252
- new MimeType ("text" , "plain" , DEFAULT_CHARSET ));
248
+ public static StringDecoder textPlainOnly (@ Nullable List <String > delimiters , boolean stripDelimiter ) {
249
+ return new StringDecoder (delimiters , stripDelimiter , new MimeType ("text" , "plain" , DEFAULT_CHARSET ));
253
250
}
254
251
255
252
/**
@@ -267,16 +264,19 @@ public static StringDecoder allMimeTypes(boolean ignored) {
267
264
* Create a {@code StringDecoder} that supports all MIME types.
268
265
*/
269
266
public static StringDecoder allMimeTypes () {
270
- return allMimeTypes (DEFAULT_DELIMITERS , true );
267
+ return allMimeTypes (null , true );
271
268
}
272
269
273
270
/**
274
271
* Create a {@code StringDecoder} that supports all MIME types.
272
+ * @param delimiters delimiter strings to use to split the input stream, if
273
+ * {@code null} by default {@link #DEFAULT_DELIMITERS} is used.
274
+ * @param stripDelimiter whether to remove delimiters from the resulting
275
+ * input strings.
275
276
*/
276
- public static StringDecoder allMimeTypes (List <String > delimiters , boolean stripDelimiter ) {
277
+ public static StringDecoder allMimeTypes (@ Nullable List <String > delimiters , boolean stripDelimiter ) {
277
278
return new StringDecoder (delimiters , stripDelimiter ,
278
279
new MimeType ("text" , "plain" , DEFAULT_CHARSET ), MimeTypeUtils .ALL );
279
280
}
280
281
281
-
282
282
}
0 commit comments