Java tutorial
// Copyright (c) 2015 ServiceStack LLC. All rights reserved. // License: https://servicestack.net/bsd-license.txt package net.servicestack.client; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.lang.reflect.Field; import java.lang.reflect.Type; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.nio.charset.Charset; import java.util.Date; import java.util.Iterator; import java.util.Map; import java.util.UUID; import org.json.JSONException; import org.json.JSONObject; import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class JsonServiceClient implements ServiceClient { static Charset UTF8 = Charset.forName("UTF-8"); String baseUrl; String replyUrl; Integer timeoutMs; public ConnectionFilter RequestFilter; public ConnectionFilter ResponseFilter; public ExceptionFilter ExceptionFilter; public static ConnectionFilter GlobalRequestFilter; public static ConnectionFilter GlobalResponseFilter; public static ExceptionFilter GlobalExceptionFilter; Gson gson; public JsonServiceClient(String baseUrl) { this.baseUrl = baseUrl.endsWith("/") ? baseUrl : baseUrl + "/"; this.replyUrl = this.baseUrl + "json/reply/"; } public void setTimeout(int timeoutMs) { this.timeoutMs = timeoutMs; } public GsonBuilder getGsonBuilder() { return new GsonBuilder().registerTypeAdapter(Date.class, JsonSerializers.getDateSerializer()) .registerTypeAdapter(Date.class, JsonSerializers.getDateDeserializer()) .registerTypeAdapter(TimeSpan.class, JsonSerializers.getTimeSpanSerializer()) .registerTypeAdapter(TimeSpan.class, JsonSerializers.getTimeSpanDeserializer()) .registerTypeAdapter(UUID.class, JsonSerializers.getGuidSerializer()) .registerTypeAdapter(UUID.class, JsonSerializers.getGuidDeserializer()); } public Gson getGson() { if (gson == null) { gson = getGsonBuilder().create(); } return gson; } public String toJson(Object o) { String json = getGson().toJson(o); return json; } public Object fromJson(String json, Class c) { Object o = getGson().fromJson(json, c); return o; } public void setGson(Gson gson) { this.gson = gson; } public String createUrl(Object requestDto) { return createUrl(requestDto, null); } public String createUrl(Object requestDto, Map<String, String> query) { String requestUrl = this.replyUrl + requestDto.getClass().getSimpleName(); StringBuilder sb = new StringBuilder(); Field lastField = null; try { for (Field f : Utils.getSerializableFields(requestDto.getClass())) { Object val = f.get(requestDto); if (val == null) { continue; } sb.append(sb.length() == 0 ? "?" : "&"); sb.append(URLEncoder.encode(f.getName(), "UTF-8")); sb.append("="); sb.append(URLEncoder.encode(val.toString(), "UTF-8")); } if (query != null) { for (Map.Entry<String, String> entry : query.entrySet()) { String key = entry.getKey(); String val = entry.getValue(); sb.append(sb.length() == 0 ? "?" : "&"); sb.append(URLEncoder.encode(key, "UTF-8")); sb.append("="); if (val != null) { sb.append(URLEncoder.encode(val, "UTF-8")); } } } } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } return requestUrl + sb.toString(); } public HttpURLConnection createRequest(String url, String httpMethod) { return createRequest(url, httpMethod, null, null); } public HttpURLConnection createRequest(String url, String httpMethod, Object request) { String contentType = null; byte[] requestBody = null; if (request != null) { contentType = MimeTypes.Json; String json = getGson().toJson(request); if (Log.isDebugEnabled()) { Log.d(json); } requestBody = json.getBytes(UTF8); } return createRequest(url, httpMethod, requestBody, contentType); } public HttpURLConnection createRequest(String requestUrl, String httpMethod, byte[] requestBody, String requestType) { try { URL url = new URL(requestUrl); HttpURLConnection req = (HttpURLConnection) url.openConnection(); req.setDoOutput(true); if (timeoutMs != null) { req.setConnectTimeout(timeoutMs); req.setReadTimeout(timeoutMs); } req.setRequestMethod(httpMethod); req.setRequestProperty(HttpHeaders.Accept, MimeTypes.Json); if (requestType != null) { req.setRequestProperty(HttpHeaders.ContentType, requestType); } if (requestBody != null) { req.setRequestProperty(HttpHeaders.ContentLength, Integer.toString(requestBody.length)); DataOutputStream wr = new DataOutputStream(req.getOutputStream()); wr.write(requestBody); wr.flush(); wr.close(); } if (RequestFilter != null) { RequestFilter.exec(req); } if (GlobalRequestFilter != null) { GlobalRequestFilter.exec(req); } return req; } catch (IOException e) { throw new RuntimeException(e); } } public static RuntimeException createException(HttpURLConnection res, int responseCode) { WebServiceException webEx = null; try { String responseBody = Utils.readToEnd(res.getErrorStream(), UTF8.name()); webEx = new WebServiceException(responseCode, res.getResponseMessage(), responseBody); if (Utils.matchesContentType(res.getHeaderField(HttpHeaders.ContentType), MimeTypes.Json)) { JSONObject jResponse = new JSONObject(responseBody); Iterator<?> keys = jResponse.keys(); while (keys.hasNext()) { String key = (String) keys.next(); String varName = Utils.sanitizeVarName(key); if (varName.equals("responsestatus")) { webEx.setResponseStatus(Utils.createResponseStatus(jResponse.get(key))); break; } } } return webEx; } catch (IOException e) { if (webEx != null) { return webEx; } return new RuntimeException(e); } catch (JSONException e) { if (webEx != null) { return webEx; } return new RuntimeException(e); } } public <TResponse> TResponse send(HttpURLConnection req, Object responseClass) { try { Class resClass = responseClass instanceof Class ? (Class) responseClass : null; Type resType = responseClass instanceof Type ? (Type) responseClass : null; if (resClass == null && resType == null) { throw new RuntimeException( "responseClass '" + responseClass.getClass().getSimpleName() + "' must be a Class or Type"); } int responseCode = req.getResponseCode(); if (responseCode >= 400) { RuntimeException ex = createException(req, responseCode); if (ExceptionFilter != null) { ExceptionFilter.exec(req, ex); } if (GlobalExceptionFilter != null) { GlobalExceptionFilter.exec(req, ex); } throw ex; } if (RequestFilter != null) { RequestFilter.exec(req); } if (GlobalRequestFilter != null) { GlobalRequestFilter.exec(req); } InputStream is = req.getInputStream(); if (Log.isDebugEnabled()) { String json = Utils.readToEnd(is, UTF8.name()); Log.d(json); TResponse response = resClass != null ? (TResponse) getGson().fromJson(json, resClass) : (TResponse) getGson().fromJson(json, resType); return response; } else { BufferedReader reader = new BufferedReader(new InputStreamReader(is)); TResponse response = resClass != null ? (TResponse) getGson().fromJson(reader, resClass) : (TResponse) getGson().fromJson(reader, resType); reader.close(); return response; } } catch (IOException e) { throw new RuntimeException(e); } finally { req.disconnect(); } } static String typeName(Object o) { return o.getClass().getSimpleName(); } private String resolveUrl(String relativeOrAbsoluteUrl) { return relativeOrAbsoluteUrl.startsWith("http:") || relativeOrAbsoluteUrl.startsWith("https:") ? relativeOrAbsoluteUrl : Utils.combinePath(baseUrl, relativeOrAbsoluteUrl); } @Override public <TResponse> TResponse get(IReturn<TResponse> request) { return send(createRequest(createUrl(request), HttpMethods.Get), request.getResponseType()); } @Override public <TResponse> TResponse get(IReturn<TResponse> request, Map<String, String> queryParams) { return send(createRequest(createUrl(request, queryParams), HttpMethods.Get), request.getResponseType()); } @Override public <TResponse> TResponse get(String path, Class responseType) { return send(createRequest(resolveUrl(path), HttpMethods.Get), responseType); } @Override public <TResponse> TResponse get(String path, Type responseType) { return send(createRequest(resolveUrl(path), HttpMethods.Get), responseType); } @Override public HttpURLConnection get(String path) { return createRequest(resolveUrl(path), HttpMethods.Get); } @Override public <TResponse> TResponse post(IReturn<TResponse> request) { return send(createRequest(Utils.combinePath(replyUrl, typeName(request)), HttpMethods.Post, request), request.getResponseType()); } @Override public <TResponse> TResponse post(String path, Object request, Class responseType) { return send(createRequest(resolveUrl(path), HttpMethods.Post, request), responseType); } @Override public <TResponse> TResponse post(String path, Object request, Type responseType) { return send(createRequest(resolveUrl(path), HttpMethods.Post, request), responseType); } @Override public <TResponse> TResponse post(String path, byte[] requestBody, String contentType, Class responseType) { return send(createRequest(resolveUrl(path), HttpMethods.Post, requestBody, contentType), responseType); } @Override public <TResponse> TResponse post(String path, byte[] requestBody, String contentType, Type responseType) { return send(createRequest(resolveUrl(path), HttpMethods.Post, requestBody, contentType), responseType); } @Override public HttpURLConnection post(String path, byte[] requestBody, String contentType) { return createRequest(resolveUrl(path), HttpMethods.Post, requestBody, contentType); } @Override public <TResponse> TResponse put(IReturn<TResponse> request) { return send(createRequest(Utils.combinePath(replyUrl, typeName(request)), HttpMethods.Put, request), request.getResponseType()); } @Override public <TResponse> TResponse put(String path, Object request, Class responseType) { return send(createRequest(resolveUrl(path), HttpMethods.Put, request), responseType); } @Override public <TResponse> TResponse put(String path, Object request, Type responseType) { return send(createRequest(resolveUrl(path), HttpMethods.Put, request), responseType); } @Override public <TResponse> TResponse put(String path, byte[] requestBody, String contentType, Class responseType) { return send(createRequest(resolveUrl(path), HttpMethods.Put, requestBody, contentType), responseType); } @Override public <TResponse> TResponse put(String path, byte[] requestBody, String contentType, Type responseType) { return send(createRequest(resolveUrl(path), HttpMethods.Put, requestBody, contentType), responseType); } @Override public HttpURLConnection put(String path, byte[] requestBody, String contentType) { return createRequest(resolveUrl(path), HttpMethods.Put, requestBody, contentType); } @Override public <TResponse> TResponse delete(IReturn<TResponse> request) { return send(createRequest(createUrl(request), HttpMethods.Delete), request.getResponseType()); } @Override public <TResponse> TResponse delete(IReturn<TResponse> request, Map<String, String> queryParams) { return send(createRequest(createUrl(request, queryParams), HttpMethods.Delete), request.getResponseType()); } @Override public <TResponse> TResponse delete(String path, Class responseType) { return send(createRequest(resolveUrl(path), HttpMethods.Delete), responseType); } @Override public <TResponse> TResponse delete(String path, Type responseType) { return send(createRequest(resolveUrl(path), HttpMethods.Delete), responseType); } @Override public HttpURLConnection delete(String path) { return createRequest(resolveUrl(path), HttpMethods.Delete); } }