Skip to content

Instantly share code, notes, and snippets.

@dodgex
Last active December 20, 2015 01:19
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dodgex/6048213 to your computer and use it in GitHub Desktop.
Save dodgex/6048213 to your computer and use it in GitHub Desktop.
OkHttpRequestFactory for Spring Rest Template
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPOutputStream;
import org.springframework.http.ContentCodingType;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
final class OkHttpClientRequest implements ClientHttpRequest {
private final HttpURLConnection connection;
private final HttpHeaders headers = new HttpHeaders();
private boolean executed = false;
private GZIPOutputStream compressedBody;
private OutputStream body;
public OkHttpClientRequest(HttpURLConnection connection) {
this.connection = connection;
}
@Override
public OutputStream getBody() throws IOException {
if (this.body == null) {
writeHeaders(headers);
this.connection.connect();
this.body = this.connection.getOutputStream();
}
if (shouldCompress()) {
return getCompressedBody(this.body);
} else {
return this.body;
}
}
@Override
public HttpHeaders getHeaders() {
return (this.executed ? HttpHeaders.readOnlyHttpHeaders(this.headers) : this.headers);
}
@Override
public URI getURI() {
try {
return this.connection.getURL().toURI();
} catch (URISyntaxException ex) {
throw new IllegalStateException("Could not get HttpURLConnection URI: " + ex.getMessage(), ex);
}
}
@Override
public HttpMethod getMethod() {
return HttpMethod.valueOf(this.connection.getRequestMethod());
}
@Override
public ClientHttpResponse execute() throws IOException {
try {
if (this.body != null) {
this.body.close();
} else {
writeHeaders(headers);
this.connection.connect();
}
} catch (IOException ex) {
// ignore
}
this.executed = true;
return new OkHttpClientResponse(connection);
}
private boolean shouldCompress() {
List<ContentCodingType> contentCodingTypes = this.headers.getContentEncoding();
for (ContentCodingType contentCodingType : contentCodingTypes) {
if (contentCodingType.equals(ContentCodingType.GZIP)) {
return true;
}
}
return false;
}
private OutputStream getCompressedBody(OutputStream body) throws IOException {
if (this.compressedBody == null) {
this.compressedBody = new GZIPOutputStream(body);
}
return this.compressedBody;
}
private void writeHeaders(HttpHeaders headers) {
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
String headerName = entry.getKey();
for (String headerValue : entry.getValue()) {
this.connection.addRequestProperty(headerName, headerValue);
}
}
}
}
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.List;
import java.util.zip.GZIPInputStream;
import org.springframework.http.ContentCodingType;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.StringUtils;
final class OkHttpClientResponse implements ClientHttpResponse {
private final HttpURLConnection connection;
private static final String AUTH_ERROR = "Received authentication challenge is null";
private static final String AUTH_ERROR_JELLY_BEAN = "No authentication challenges found";
private static final String PROXY_AUTH_ERROR = "Received HTTP_PROXY_AUTH (407) code while not using proxy";
private HttpHeaders headers;
private GZIPInputStream compressedBody;
public OkHttpClientResponse(HttpURLConnection connection) {
this.connection = connection;
}
private int handleIOException(IOException ex) throws IOException {
if (AUTH_ERROR.equals(ex.getMessage()) || AUTH_ERROR_JELLY_BEAN.equals(ex.getMessage())) {
return HttpStatus.UNAUTHORIZED.value();
} else if (PROXY_AUTH_ERROR.equals(ex.getMessage())) {
return HttpStatus.PROXY_AUTHENTICATION_REQUIRED.value();
} else {
throw ex;
}
}
@Override
public InputStream getBody() throws IOException {
InputStream errorStream = this.connection.getErrorStream();
InputStream body = (errorStream != null ? errorStream : this.connection.getInputStream());
if (isCompressed()) {
return getCompressedBody(body);
}
return body;
}
@Override
public HttpHeaders getHeaders() {
if (this.headers == null) {
this.headers = new HttpHeaders();
// Header field 0 is the status line for most HttpURLConnections, but not on GAE
String name = this.connection.getHeaderFieldKey(0);
if (StringUtils.hasLength(name)) {
this.headers.add(name, this.connection.getHeaderField(0));
}
int i = 1;
while (true) {
name = this.connection.getHeaderFieldKey(i);
if (!StringUtils.hasLength(name)) {
break;
}
this.headers.add(name, this.connection.getHeaderField(i));
i++;
}
}
return this.headers;
}
@Override
public int getRawStatusCode() throws IOException {
try {
return this.connection.getResponseCode();
} catch (IOException ex) {
return handleIOException(ex);
}
}
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.valueOf(getRawStatusCode());
}
@Override
public String getStatusText() throws IOException {
try {
return this.connection.getResponseMessage();
} catch (IOException ex) {
return HttpStatus.valueOf(handleIOException(ex)).getReasonPhrase();
}
}
@Override
public void close() {
if (this.compressedBody != null) {
try {
this.compressedBody.close();
} catch (IOException e) {
// ignore
}
}
this.connection.disconnect();
}
private boolean isCompressed() {
List<ContentCodingType> contentCodingTypes = this.getHeaders().getContentEncoding();
for (ContentCodingType contentCodingType : contentCodingTypes) {
if (contentCodingType.equals(ContentCodingType.GZIP)) {
return true;
}
}
return false;
}
private InputStream getCompressedBody(InputStream body) throws IOException {
if (this.compressedBody == null) {
this.compressedBody = new GZIPInputStream(body);
}
return this.compressedBody;
}
}
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URI;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpRequestFactory;
import com.squareup.okhttp.OkHttpClient;
public class OkHttpFactory implements ClientHttpRequestFactory {
private final OkHttpClient client = new OkHttpClient();
private int connectTimeout = -1;
private int readTimeout = -1;
@Override
public ClientHttpRequest createRequest(final URI uri, final HttpMethod httpMethod) throws IOException {
final HttpURLConnection connection = this.client.open(uri.toURL());
prepareConnection(connection, httpMethod.name());
return new OkHttpClientRequest(connection);
}
public void setProxy(Proxy proxy) {
this.client.setProxy(proxy);
}
public void setConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
}
public void setReadTimeout(int readTimeout) {
this.readTimeout = readTimeout;
}
protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
if (this.connectTimeout >= 0) {
connection.setConnectTimeout(this.connectTimeout);
}
if (this.readTimeout >= 0) {
connection.setReadTimeout(this.readTimeout);
}
connection.setDoInput(true);
if ("GET".equals(httpMethod)) {
connection.setInstanceFollowRedirects(true);
} else {
connection.setInstanceFollowRedirects(false);
}
if ("PUT".equals(httpMethod) || "POST".equals(httpMethod)) {
connection.setDoOutput(true);
} else {
connection.setDoOutput(false);
}
connection.setRequestMethod(httpMethod);
}
}
@beppeben
Copy link

Good work.
However the "open" method of OkHttpClient is deprecated and no longer present in the current versions. Are you planning to update this in the future?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment