diff --git a/spring-web-reactive/src/main/java/org/springframework/web/client/reactive/DefaultHttpRequestBuilder.java b/spring-web-reactive/src/main/java/org/springframework/web/client/reactive/DefaultHttpRequestBuilder.java
new file mode 100644
index 00000000000..5ee4731a12b
--- /dev/null
+++ b/spring-web-reactive/src/main/java/org/springframework/web/client/reactive/DefaultHttpRequestBuilder.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2002-2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.web.client.reactive;
+
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.reactivestreams.Publisher;
+import reactor.core.publisher.Flux;
+
+import org.springframework.core.ResolvableType;
+import org.springframework.core.codec.Encoder;
+import org.springframework.http.HttpCookie;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.MediaType;
+import org.springframework.http.client.reactive.ClientHttpRequest;
+import org.springframework.http.client.reactive.ClientHttpRequestFactory;
+import org.springframework.web.client.RestClientException;
+
+/**
+ * Builds a {@link ClientHttpRequest}
+ *
+ *
See static factory methods in {@link HttpRequestBuilders}
+ *
+ * @author Brian Clozel
+ * @see HttpRequestBuilders
+ */
+public class DefaultHttpRequestBuilder implements HttpRequestBuilder {
+
+ protected HttpMethod httpMethod;
+
+ protected HttpHeaders httpHeaders;
+
+ protected URI url;
+
+ protected Flux contentPublisher;
+
+ protected List> messageEncoders;
+
+ protected final List cookies = new ArrayList();
+
+ protected DefaultHttpRequestBuilder() {
+ }
+
+ public DefaultHttpRequestBuilder(HttpMethod httpMethod, String urlTemplate, Object... urlVariables) throws RestClientException {
+ this.httpMethod = httpMethod;
+ this.httpHeaders = new HttpHeaders();
+ this.url = parseURI(urlTemplate);
+ }
+
+ public DefaultHttpRequestBuilder(HttpMethod httpMethod, URI url) {
+ this.httpMethod = httpMethod;
+ this.httpHeaders = new HttpHeaders();
+ this.url = url;
+ }
+
+ protected DefaultHttpRequestBuilder setMessageEncoders(List> messageEncoders) {
+ this.messageEncoders = messageEncoders;
+ return this;
+ }
+
+ private URI parseURI(String uri) throws RestClientException {
+ try {
+ return new URI(uri);
+ }
+ catch (URISyntaxException e) {
+ throw new RestClientException("could not parse URL template", e);
+ }
+ }
+
+ public DefaultHttpRequestBuilder param(String name, String... values) {
+ return this;
+ }
+
+ public DefaultHttpRequestBuilder header(String name, String... values) {
+ Arrays.stream(values).forEach(value -> this.httpHeaders.add(name, value));
+ return this;
+ }
+
+ public DefaultHttpRequestBuilder headers(HttpHeaders httpHeaders) {
+ this.httpHeaders = httpHeaders;
+ return this;
+ }
+
+ public DefaultHttpRequestBuilder contentType(MediaType contentType) {
+ this.httpHeaders.setContentType(contentType);
+ return this;
+ }
+
+ public DefaultHttpRequestBuilder contentType(String contentType) {
+ this.httpHeaders.setContentType(MediaType.parseMediaType(contentType));
+ return this;
+ }
+
+ public DefaultHttpRequestBuilder accept(MediaType... mediaTypes) {
+ this.httpHeaders.setAccept(Arrays.asList(mediaTypes));
+ return this;
+ }
+
+ public DefaultHttpRequestBuilder accept(String... mediaTypes) {
+ this.httpHeaders.setAccept(Arrays.stream(mediaTypes)
+ .map(type -> MediaType.parseMediaType(type))
+ .collect(Collectors.toList()));
+ return this;
+ }
+
+ public DefaultHttpRequestBuilder content(Object content) {
+ this.contentPublisher = Flux.just(content);
+ return this;
+ }
+
+ public DefaultHttpRequestBuilder contentStream(Publisher content) {
+ this.contentPublisher = Flux.from(content);
+ return this;
+ }
+
+ public ClientHttpRequest build(ClientHttpRequestFactory factory) {
+ ClientHttpRequest request = factory.createRequest(this.httpMethod, this.url, this.httpHeaders);
+ request.getHeaders().putAll(this.httpHeaders);
+
+ if (this.contentPublisher != null) {
+ ResolvableType requestBodyType = ResolvableType.forInstance(this.contentPublisher);
+ MediaType mediaType = request.getHeaders().getContentType();
+
+ Optional> messageEncoder = resolveEncoder(requestBodyType, mediaType);
+
+ if (messageEncoder.isPresent()) {
+ request.setBody(messageEncoder.get().encode(this.contentPublisher, requestBodyType, mediaType));
+ }
+ else {
+ // TODO: wrap with client exception?
+ request.setBody(Flux.error(new IllegalStateException("Can't write request body" +
+ "of type '" + requestBodyType.toString() +
+ "' for content-type '" + mediaType.toString() + "'")));
+ }
+ }
+
+ return request;
+ }
+
+ protected Optional> resolveEncoder(ResolvableType type, MediaType mediaType) {
+ return this.messageEncoders.stream()
+ .filter(e -> e.canEncode(type, mediaType)).findFirst();
+ }
+
+}
\ No newline at end of file
diff --git a/spring-web-reactive/src/main/java/org/springframework/web/client/HttpRequestBuilder.java b/spring-web-reactive/src/main/java/org/springframework/web/client/reactive/HttpRequestBuilder.java
similarity index 95%
rename from spring-web-reactive/src/main/java/org/springframework/web/client/HttpRequestBuilder.java
rename to spring-web-reactive/src/main/java/org/springframework/web/client/reactive/HttpRequestBuilder.java
index a9717445b9b..55d5e182294 100644
--- a/spring-web-reactive/src/main/java/org/springframework/web/client/HttpRequestBuilder.java
+++ b/spring-web-reactive/src/main/java/org/springframework/web/client/reactive/HttpRequestBuilder.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.web.client;
+package org.springframework.web.client.reactive;
import org.springframework.http.client.reactive.ClientHttpRequest;
import org.springframework.http.client.reactive.ClientHttpRequestFactory;
diff --git a/spring-web-reactive/src/main/java/org/springframework/web/client/reactive/HttpRequestBuilders.java b/spring-web-reactive/src/main/java/org/springframework/web/client/reactive/HttpRequestBuilders.java
new file mode 100644
index 00000000000..13009f3651c
--- /dev/null
+++ b/spring-web-reactive/src/main/java/org/springframework/web/client/reactive/HttpRequestBuilders.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2002-2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.web.client.reactive;
+
+import org.springframework.http.HttpMethod;
+
+/**
+ * Static factory methods for {@link DefaultHttpRequestBuilder RequestBuilders}.
+ *
+ * @author Brian Clozel
+ */
+public abstract class HttpRequestBuilders {
+
+ /**
+ * Create a {@link DefaultHttpRequestBuilder} for a GET request.
+ *
+ * @param urlTemplate a URL template; the resulting URL will be encoded
+ * @param urlVariables zero or more URL variables
+ */
+ public static DefaultHttpRequestBuilder get(String urlTemplate, Object... urlVariables) {
+ return new DefaultHttpRequestBuilder(HttpMethod.GET, urlTemplate, urlVariables);
+ }
+
+ /**
+ * Create a {@link DefaultHttpRequestBuilder} for a POST request.
+ *
+ * @param urlTemplate a URL template; the resulting URL will be encoded
+ * @param urlVariables zero or more URL variables
+ */
+ public static DefaultHttpRequestBuilder post(String urlTemplate, Object... urlVariables) {
+ return new DefaultHttpRequestBuilder(HttpMethod.POST, urlTemplate, urlVariables);
+ }
+
+
+ /**
+ * Create a {@link DefaultHttpRequestBuilder} for a PUT request.
+ *
+ * @param urlTemplate a URL template; the resulting URL will be encoded
+ * @param urlVariables zero or more URL variables
+ */
+ public static DefaultHttpRequestBuilder put(String urlTemplate, Object... urlVariables) {
+ return new DefaultHttpRequestBuilder(HttpMethod.PUT, urlTemplate, urlVariables);
+ }
+
+ /**
+ * Create a {@link DefaultHttpRequestBuilder} for a PATCH request.
+ *
+ * @param urlTemplate a URL template; the resulting URL will be encoded
+ * @param urlVariables zero or more URL variables
+ */
+ public static DefaultHttpRequestBuilder patch(String urlTemplate, Object... urlVariables) {
+ return new DefaultHttpRequestBuilder(HttpMethod.PATCH, urlTemplate, urlVariables);
+ }
+
+ /**
+ * Create a {@link DefaultHttpRequestBuilder} for a DELETE request.
+ *
+ * @param urlTemplate a URL template; the resulting URL will be encoded
+ * @param urlVariables zero or more URL variables
+ */
+ public static DefaultHttpRequestBuilder delete(String urlTemplate, Object... urlVariables) {
+ return new DefaultHttpRequestBuilder(HttpMethod.DELETE, urlTemplate, urlVariables);
+ }
+
+ /**
+ * Create a {@link DefaultHttpRequestBuilder} for an OPTIONS request.
+ *
+ * @param urlTemplate a URL template; the resulting URL will be encoded
+ * @param urlVariables zero or more URL variables
+ */
+ public static DefaultHttpRequestBuilder options(String urlTemplate, Object... urlVariables) {
+ return new DefaultHttpRequestBuilder(HttpMethod.OPTIONS, urlTemplate, urlVariables);
+ }
+
+ /**
+ * Create a {@link DefaultHttpRequestBuilder} for a HEAD request.
+ *
+ * @param urlTemplate a URL template; the resulting URL will be encoded
+ * @param urlVariables zero or more URL variables
+ */
+ public static DefaultHttpRequestBuilder head(String urlTemplate, Object... urlVariables) {
+ return new DefaultHttpRequestBuilder(HttpMethod.HEAD, urlTemplate, urlVariables);
+ }
+
+ /**
+ * Create a {@link DefaultHttpRequestBuilder} for a request with the given HTTP method.
+ *
+ * @param httpMethod the HTTP method
+ * @param urlTemplate a URL template; the resulting URL will be encoded
+ * @param urlVariables zero or more URL variables
+ */
+ public static DefaultHttpRequestBuilder request(HttpMethod httpMethod, String urlTemplate, Object... urlVariables) {
+ return new DefaultHttpRequestBuilder(httpMethod, urlTemplate, urlVariables);
+ }
+
+}
\ No newline at end of file