20
20
import java .util .List ;
21
21
import java .util .Map ;
22
22
23
+ import org .reactivestreams .Publisher ;
24
+
25
+ import org .springframework .core .ParameterizedTypeReference ;
26
+ import org .springframework .core .ResolvableType ;
23
27
import org .springframework .http .HttpEntity ;
24
28
import org .springframework .http .HttpHeaders ;
25
29
import org .springframework .http .MediaType ;
@@ -96,6 +100,11 @@ public PartBuilder part(String name, Object part, @Nullable MediaType contentTyp
96
100
Assert .hasLength (name , "'name' must not be empty" );
97
101
Assert .notNull (part , "'part' must not be null" );
98
102
103
+ if (part instanceof Publisher ) {
104
+ throw new IllegalArgumentException ("Use publisher(String, Publisher, Class) or " +
105
+ "publisher(String, Publisher, ParameterizedTypeReference) for adding Publisher parts" );
106
+ }
107
+
99
108
Object partBody ;
100
109
HttpHeaders partHeaders = new HttpHeaders ();
101
110
@@ -116,6 +125,54 @@ public PartBuilder part(String name, Object part, @Nullable MediaType contentTyp
116
125
return builder ;
117
126
}
118
127
128
+ /**
129
+ * Adds a {@link Publisher} part to this builder, allowing for further header customization with
130
+ * the returned {@link PartBuilder}.
131
+ * @param name the name of the part to add (may not be empty)
132
+ * @param publisher the contents of the part to add
133
+ * @param elementClass the class of elements contained in the publisher
134
+ * @return a builder that allows for further header customization
135
+ */
136
+ public <T , P extends Publisher <T >> PartBuilder asyncPart (String name , P publisher ,
137
+ Class <T > elementClass ) {
138
+
139
+ Assert .notNull (elementClass , "'elementClass' must not be null" );
140
+ ResolvableType elementType = ResolvableType .forClass (elementClass );
141
+ Assert .hasLength (name , "'name' must not be empty" );
142
+ Assert .notNull (publisher , "'publisher' must not be null" );
143
+ Assert .notNull (elementType , "'elementType' must not be null" );
144
+
145
+ HttpHeaders partHeaders = new HttpHeaders ();
146
+ PublisherClassPartBuilder <T , P > builder =
147
+ new PublisherClassPartBuilder <>(publisher , elementClass , partHeaders );
148
+ this .parts .add (name , builder );
149
+ return builder ;
150
+
151
+ }
152
+
153
+ /**
154
+ * Adds a {@link Publisher} part to this builder, allowing for further header customization with
155
+ * the returned {@link PartBuilder}.
156
+ * @param name the name of the part to add (may not be empty)
157
+ * @param publisher the contents of the part to add
158
+ * @param elementType the type of elements contained in the publisher
159
+ * @return a builder that allows for further header customization
160
+ */
161
+ public <T , P extends Publisher <T >> PartBuilder asyncPart (String name , P publisher ,
162
+ ParameterizedTypeReference <T > elementType ) {
163
+
164
+ Assert .notNull (elementType , "'elementType' must not be null" );
165
+ ResolvableType elementType1 = ResolvableType .forType (elementType );
166
+ Assert .hasLength (name , "'name' must not be empty" );
167
+ Assert .notNull (publisher , "'publisher' must not be null" );
168
+ Assert .notNull (elementType1 , "'elementType' must not be null" );
169
+
170
+ HttpHeaders partHeaders = new HttpHeaders ();
171
+ PublisherTypReferencePartBuilder <T , P > builder =
172
+ new PublisherTypReferencePartBuilder <>(publisher , elementType , partHeaders );
173
+ this .parts .add (name , builder );
174
+ return builder ;
175
+ }
119
176
120
177
/**
121
178
* Builder interface that allows for customization of part headers.
@@ -136,10 +193,9 @@ public interface PartBuilder {
136
193
private static class DefaultPartBuilder implements PartBuilder {
137
194
138
195
@ Nullable
139
- private final Object body ;
140
-
141
- private final HttpHeaders headers ;
196
+ protected final Object body ;
142
197
198
+ protected final HttpHeaders headers ;
143
199
144
200
public DefaultPartBuilder (@ Nullable Object body , HttpHeaders headers ) {
145
201
this .body = body ;
@@ -157,4 +213,44 @@ public HttpEntity<?> build() {
157
213
}
158
214
}
159
215
216
+ private static class PublisherClassPartBuilder <S , P extends Publisher <S >>
217
+ extends DefaultPartBuilder {
218
+
219
+ private final Class <S > bodyType ;
220
+
221
+ public PublisherClassPartBuilder (P body , Class <S > bodyType , HttpHeaders headers ) {
222
+ super (body , headers );
223
+ this .bodyType = bodyType ;
224
+ }
225
+
226
+ @ Override
227
+ @ SuppressWarnings ("unchecked" )
228
+ public HttpEntity <?> build () {
229
+ P body = (P ) this .body ;
230
+ Assert .state (body != null , "'body' must not be null" );
231
+ return HttpEntity .fromPublisher (body , this .bodyType , this .headers );
232
+ }
233
+ }
234
+
235
+ private static class PublisherTypReferencePartBuilder <S , P extends Publisher <S >>
236
+ extends DefaultPartBuilder {
237
+
238
+ private final ParameterizedTypeReference <S > bodyType ;
239
+
240
+ public PublisherTypReferencePartBuilder (P body , ParameterizedTypeReference <S > bodyType ,
241
+ HttpHeaders headers ) {
242
+
243
+ super (body , headers );
244
+ this .bodyType = bodyType ;
245
+ }
246
+
247
+ @ Override
248
+ @ SuppressWarnings ("unchecked" )
249
+ public HttpEntity <?> build () {
250
+ P body = (P ) this .body ;
251
+ Assert .state (body != null , "'body' must not be null" );
252
+ return HttpEntity .fromPublisher (body , this .bodyType , this .headers );
253
+ }
254
+ }
255
+
160
256
}
0 commit comments