From 2a0574a3ad2184afc1ddd02543b97fa38dffcac9 Mon Sep 17 00:00:00 2001 From: cbornet Date: Tue, 13 Sep 2016 15:57:34 +0200 Subject: [PATCH] [okhttp] use gson ISO8601Utils to parse dates this allows to remove a lot of code in the ApiClient. Tests for the ApiClient thus have been move to JSONTest. Also allow to configure the date formatter of all date types individually. An assertion in testCreateAndGetPetAsync() is removed because it's useless and makes the test fail randomly. See #3727 --- .../languages/AbstractJavaCodegen.java | 1 + .../libraries/okhttp-gson/ApiClient.mustache | 315 ++--------- .../Java/libraries/okhttp-gson/JSON.mustache | 503 +++++++++++------- .../java/io/swagger/client/ApiClient.java | 302 ++--------- .../src/main/java/io/swagger/client/JSON.java | 382 ++++++++----- .../java/io/swagger/client/ApiClientTest.java | 62 +-- .../test/java/io/swagger/client/JSONTest.java | 99 +++- .../io/swagger/client/api/PetApiTest.java | 14 +- .../io/swagger/client/api/StoreApiTest.java | 10 +- 9 files changed, 760 insertions(+), 928 deletions(-) diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractJavaCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractJavaCodegen.java index cabd29103538..4de984e5cf35 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractJavaCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/AbstractJavaCodegen.java @@ -260,6 +260,7 @@ public abstract class AbstractJavaCodegen extends DefaultCodegen implements Code } if("joda".equals(dateLibrary)) { + additionalProperties.put("joda", "true"); typeMapping.put("date", "LocalDate"); typeMapping.put("DateTime", "DateTime"); diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache index 9c75d6716077..f0b4cc64334c 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/ApiClient.mustache @@ -2,43 +2,26 @@ package {{invokerPackage}}; -import com.squareup.okhttp.Call; -import com.squareup.okhttp.Callback; -import com.squareup.okhttp.OkHttpClient; -import com.squareup.okhttp.Request; -import com.squareup.okhttp.Response; -import com.squareup.okhttp.RequestBody; -import com.squareup.okhttp.FormEncodingBuilder; -import com.squareup.okhttp.MultipartBuilder; -import com.squareup.okhttp.MediaType; -import com.squareup.okhttp.Headers; +import com.squareup.okhttp.*; import com.squareup.okhttp.internal.http.HttpMethod; import com.squareup.okhttp.logging.HttpLoggingInterceptor; import com.squareup.okhttp.logging.HttpLoggingInterceptor.Level; +import okio.BufferedSink; +import okio.Okio; +{{#joda}} +import org.joda.time.DateTime; +import org.joda.time.LocalDate; +import org.joda.time.format.DateTimeFormatter; +{{/joda}} -import java.lang.reflect.Type; - -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.Map.Entry; -import java.util.HashMap; -import java.util.List; -import java.util.ArrayList; -import java.util.Date; -import java.util.TimeZone; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import java.net.URLEncoder; -import java.net.URLConnection; - +import javax.net.ssl.*; import java.io.File; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.io.UnsupportedEncodingException; - +import java.lang.reflect.Type; +import java.net.URLConnection; +import java.net.URLEncoder; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.SecureRandom; @@ -46,22 +29,17 @@ import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; - import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.text.ParseException; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; - -import okio.BufferedSink; -import okio.Okio; +{{#java8}} +import java.time.LocalDate; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +{{/java8}} +import java.util.*; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import {{invokerPackage}}.auth.Authentication; import {{invokerPackage}}.auth.HttpBasicAuth; @@ -69,51 +47,14 @@ import {{invokerPackage}}.auth.ApiKeyAuth; import {{invokerPackage}}.auth.OAuth; public class ApiClient { - public static final double JAVA_VERSION; - public static final boolean IS_ANDROID; - public static final int ANDROID_SDK_VERSION; - - static { - JAVA_VERSION = Double.parseDouble(System.getProperty("java.specification.version")); - boolean isAndroid; - try { - Class.forName("android.app.Activity"); - isAndroid = true; - } catch (ClassNotFoundException e) { - isAndroid = false; - } - IS_ANDROID = isAndroid; - int sdkVersion = 0; - if (IS_ANDROID) { - try { - sdkVersion = Class.forName("android.os.Build$VERSION").getField("SDK_INT").getInt(null); - } catch (Exception e) { - try { - sdkVersion = Integer.parseInt((String) Class.forName("android.os.Build$VERSION").getField("SDK").get(null)); - } catch (Exception e2) { } - } - } - ANDROID_SDK_VERSION = sdkVersion; - } - - /** - * The datetime format to be used when lenientDatetimeFormat is enabled. - */ - public static final String LENIENT_DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; private String basePath = "{{{basePath}}}"; - private boolean lenientOnJson = false; private boolean debugging = false; private Map defaultHeaderMap = new HashMap(); private String tempFolderPath = null; private Map authentications; - private DateFormat dateFormat; - private DateFormat datetimeFormat; - private boolean lenientDatetimeFormat; - private int dateLength; - private InputStream sslCaCert; private boolean verifyingSsl; @@ -127,23 +68,8 @@ public class ApiClient { */ public ApiClient() { httpClient = new OkHttpClient(); - verifyingSsl = true; - - json = new JSON(this); - - /* - * Use RFC3339 format for date and datetime. - * See http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14 - */ - this.dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - // Always use UTC as the default time zone when dealing with date (without time). - this.dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - initDatetimeFormat(); - - // Be lenient on datetime formats when parsing datetime from string. - // See parseDatetime. - this.lenientDatetimeFormat = true; + json = new JSON(); // Set default User-Agent. setUserAgent("{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}Swagger-Codegen/{{{artifactVersion}}}/java{{/httpUserAgent}}"); @@ -262,143 +188,43 @@ public class ApiClient { return this; } - public DateFormat getDateFormat() { - return dateFormat; - } - public ApiClient setDateFormat(DateFormat dateFormat) { - this.dateFormat = dateFormat; - this.dateLength = this.dateFormat.format(new Date()).length(); + this.json.setDateFormat(dateFormat); return this; } - public DateFormat getDatetimeFormat() { - return datetimeFormat; - } - - public ApiClient setDatetimeFormat(DateFormat datetimeFormat) { - this.datetimeFormat = datetimeFormat; + public ApiClient setSqlDateFormat(DateFormat dateFormat) { + this.json.setSqlDateFormat(dateFormat); return this; } - /** - * Whether to allow various ISO 8601 datetime formats when parsing a datetime string. - * @see #parseDatetime(String) - * @return True if lenientDatetimeFormat flag is set to true - */ - public boolean isLenientDatetimeFormat() { - return lenientDatetimeFormat; - } - - public ApiClient setLenientDatetimeFormat(boolean lenientDatetimeFormat) { - this.lenientDatetimeFormat = lenientDatetimeFormat; + {{#joda}} + public ApiClient setDateTimeFormat(DateTimeFormatter dateFormat) { + this.json.setDateTimeFormat(dateFormat); return this; } - /** - * Parse the given date string into Date object. - * The default dateFormat supports these ISO 8601 date formats: - * 2015-08-16 - * 2015-8-16 - * @param str String to be parsed - * @return Date - */ - public Date parseDate(String str) { - if (str == null) - return null; - try { - return dateFormat.parse(str); - } catch (ParseException e) { - throw new RuntimeException(e); - } + public ApiClient setLocalDateFormat(DateTimeFormatter dateFormat) { + this.json.setLocalDateFormat(dateFormat); + return this; } - /** - * Parse the given datetime string into Date object. - * When lenientDatetimeFormat is enabled, the following ISO 8601 datetime formats are supported: - * 2015-08-16T08:20:05Z - * 2015-8-16T8:20:05Z - * 2015-08-16T08:20:05+00:00 - * 2015-08-16T08:20:05+0000 - * 2015-08-16T08:20:05.376Z - * 2015-08-16T08:20:05.376+00:00 - * 2015-08-16T08:20:05.376+00 - * Note: The 3-digit milli-seconds is optional. Time zone is required and can be in one of - * these formats: - * Z (same with +0000) - * +08:00 (same with +0800) - * -02 (same with -0200) - * -0200 - * @see ISO 8601 - * @param str Date time string to be parsed - * @return Date representation of the string - */ - public Date parseDatetime(String str) { - if (str == null) - return null; - - DateFormat format; - if (lenientDatetimeFormat) { - /* - * When lenientDatetimeFormat is enabled, normalize the date string - * into LENIENT_DATETIME_FORMAT to support various formats - * defined by ISO 8601. - */ - // normalize time zone - // trailing "Z": 2015-08-16T08:20:05Z => 2015-08-16T08:20:05+0000 - str = str.replaceAll("[zZ]\\z", "+0000"); - // remove colon in time zone: 2015-08-16T08:20:05+00:00 => 2015-08-16T08:20:05+0000 - str = str.replaceAll("([+-]\\d{2}):(\\d{2})\\z", "$1$2"); - // expand time zone: 2015-08-16T08:20:05+00 => 2015-08-16T08:20:05+0000 - str = str.replaceAll("([+-]\\d{2})\\z", "$100"); - // add milliseconds when missing - // 2015-08-16T08:20:05+0000 => 2015-08-16T08:20:05.000+0000 - str = str.replaceAll("(:\\d{1,2})([+-]\\d{4})\\z", "$1.000$2"); - format = new SimpleDateFormat(LENIENT_DATETIME_FORMAT); - } else { - format = this.datetimeFormat; - } - - try { - return format.parse(str); - } catch (ParseException e) { - throw new RuntimeException(e); - } + {{/joda}} + {{#java8}} + public ApiClient setOffsetDateTimeFormat(DateTimeFormatter dateFormat) { + this.json.setOffsetDateTimeFormat(dateFormat); + return this; } - /* - * Parse date or date time in string format into Date object. - * - * @param str Date time string to be parsed - * @return Date representation of the string - */ - public Date parseDateOrDatetime(String str) { - if (str == null) - return null; - else if (str.length() <= dateLength) - return parseDate(str); - else - return parseDatetime(str); + public ApiClient setLocalDateFormat(DateTimeFormatter dateFormat) { + this.json.setLocalDateFormat(dateFormat); + return this; } - /** - * Format the given Date object into string (Date format). - * - * @param date Date object - * @return Formatted date in string representation - */ - public String formatDate(Date date) { - return dateFormat.format(date); - } - - /** - * Format the given Date object into string (Datetime format). - * - * @param date Date object - * @return Formatted datetime in string representation - */ - public String formatDatetime(Date date) { - return datetimeFormat.format(date); + {{/java8}} + public ApiClient setLenientOnJson(boolean lenientOnJson) { + this.json.setLenientOnJson(lenientOnJson); + return this; } /** @@ -518,26 +344,6 @@ public class ApiClient { return this; } - /** - * @see setLenient - * - * @return True if lenientOnJson is enabled, false otherwise. - */ - public boolean isLenientOnJson() { - return lenientOnJson; - } - - /** - * Set LenientOnJson - * - * @param lenient True to enable lenientOnJson - * @return ApiClient - */ - public ApiClient setLenientOnJson(boolean lenient) { - this.lenientOnJson = lenient; - return this; - } - /** * Check that whether debugging is enabled for this API client. * @@ -621,8 +427,10 @@ public class ApiClient { public String parameterToString(Object param) { if (param == null) { return ""; - } else if (param instanceof Date) { - return formatDatetime((Date) param); + } else if (param instanceof Date {{#joda}}|| param instanceof DateTime || param instanceof LocalDate{{/joda}}{{#java8}}|| param instanceof OffsetDateTime || param instanceof LocalDate{{/java8}}) { + //Serialize to json string and remove the " enclosing characters + String jsonStr = json.serialize(param); + return jsonStr.substring(1, jsonStr.length() - 1); } else if (param instanceof Collection) { StringBuilder b = new StringBuilder(); for (Object o : (Collection)param) { @@ -1212,31 +1020,6 @@ public class ApiClient { } } - /** - * Initialize datetime format according to the current environment, e.g. Java 1.7 and Android. - */ - private void initDatetimeFormat() { - String formatWithTimeZone = null; - if (IS_ANDROID) { - if (ANDROID_SDK_VERSION >= 18) { - // The time zone format "ZZZZZ" is available since Android 4.3 (SDK version 18) - formatWithTimeZone = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"; - } - } else if (JAVA_VERSION >= 1.7) { - // The time zone format "XXX" is available since Java 1.7 - formatWithTimeZone = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"; - } - if (formatWithTimeZone != null) { - this.datetimeFormat = new SimpleDateFormat(formatWithTimeZone); - // NOTE: Use the system's default time zone (mainly for datetime formatting). - } else { - // Use a common format that works across all systems. - this.datetimeFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); - // Always use the UTC time zone as we are using a constant trailing "Z" here. - this.datetimeFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - } - } - /** * Apply SSL related settings to httpClient according to the current values of * verifyingSsl and sslCaCert. diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/JSON.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/JSON.mustache index 06f26da304bb..d43376a992ce 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/JSON.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/okhttp-gson/JSON.mustache @@ -4,55 +4,57 @@ package {{invokerPackage}}; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonNull; import com.google.gson.JsonParseException; -import com.google.gson.JsonPrimitive; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; import com.google.gson.TypeAdapter; +import com.google.gson.internal.bind.util.ISO8601Utils; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; - -import java.io.IOException; -import java.io.StringReader; -import java.lang.reflect.Type; -import java.util.Date; - -{{^java8}} +{{#joda}} import org.joda.time.DateTime; import org.joda.time.LocalDate; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; -{{/java8}} +{{/joda}} + +import java.io.IOException; +import java.io.StringReader; +import java.lang.reflect.Type; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.ParsePosition; {{#java8}} import java.time.LocalDate; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; {{/java8}} +import java.util.Date; public class JSON { - private ApiClient apiClient; private Gson gson; + private boolean isLenientOnJson = false; + private DateTypeAdapter dateTypeAdapter = new DateTypeAdapter(); + private SqlDateTypeAdapter sqlDateTypeAdapter = new SqlDateTypeAdapter(); + {{#joda}} + private DateTimeTypeAdapter dateTimeTypeAdapter = new DateTimeTypeAdapter(); + private LocalDateTypeAdapter localDateTypeAdapter = new LocalDateTypeAdapter(); + {{/joda}} + {{#java8}} + private OffsetDateTimeTypeAdapter offsetDateTimeTypeAdapter = new OffsetDateTimeTypeAdapter(); + private LocalDateTypeAdapter localDateTypeAdapter = new LocalDateTypeAdapter(); + {{/java8}} - /** - * JSON constructor. - * - * @param apiClient An instance of ApiClient - */ - public JSON(ApiClient apiClient) { - this.apiClient = apiClient; + public JSON() { gson = new GsonBuilder() - .registerTypeAdapter(Date.class, new DateAdapter(apiClient)) - {{^java8}} - .registerTypeAdapter(DateTime.class, new DateTimeTypeAdapter()) - {{/java8}} + .registerTypeAdapter(Date.class, dateTypeAdapter) + .registerTypeAdapter(java.sql.Date.class, sqlDateTypeAdapter) + {{#joda}} + .registerTypeAdapter(DateTime.class, dateTimeTypeAdapter) + .registerTypeAdapter(LocalDate.class, localDateTypeAdapter) + {{/joda}} {{#java8}} - .registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeTypeAdapter()) + .registerTypeAdapter(OffsetDateTime.class, offsetDateTimeTypeAdapter) + .registerTypeAdapter(LocalDate.class, localDateTypeAdapter) {{/java8}} - .registerTypeAdapter(LocalDate.class, new LocalDateTypeAdapter()) .create(); } @@ -70,8 +72,14 @@ public class JSON { * * @param gson Gson */ - public void setGson(Gson gson) { + public JSON setGson(Gson gson) { this.gson = gson; + return this; + } + + public JSON setLenientOnJson(boolean lenientOnJson) { + isLenientOnJson = lenientOnJson; + return this; } /** @@ -87,15 +95,15 @@ public class JSON { /** * Deserialize the given JSON string to Java object. * - * @param Type - * @param body The JSON string + * @param Type + * @param body The JSON string * @param returnType The type to deserialize into * @return The deserialized Java object */ @SuppressWarnings("unchecked") public T deserialize(String body, Type returnType) { try { - if (apiClient.isLenientOnJson()) { + if (isLenientOnJson) { JsonReader jsonReader = new JsonReader(new StringReader(body)); // see https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/stream/JsonReader.html#setLenient(boolean) jsonReader.setLenient(true); @@ -105,186 +113,325 @@ public class JSON { } } catch (JsonParseException e) { // Fallback processing when failed to parse JSON form response body: - // return the response body string directly for the String return type; - // parse response body into date or datetime for the Date return type. + // return the response body string directly for the String return type; if (returnType.equals(String.class)) return (T) body; - else if (returnType.equals(Date.class)) - return (T) apiClient.parseDateOrDatetime(body); - else throw(e); + else throw (e); } } -} - -class DateAdapter implements JsonSerializer, JsonDeserializer { - private final ApiClient apiClient; + {{#joda}} /** - * Constructor for DateAdapter - * - * @param apiClient Api client + * Gson TypeAdapter for Joda DateTime type */ - public DateAdapter(ApiClient apiClient) { - super(); - this.apiClient = apiClient; - } + public static class DateTimeTypeAdapter extends TypeAdapter { - /** - * Serialize - * - * @param src Date - * @param typeOfSrc Type - * @param context Json Serialization Context - * @return Json Element - */ - @Override - public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) { - if (src == null) { - return JsonNull.INSTANCE; - } else { - return new JsonPrimitive(apiClient.formatDatetime(src)); + private DateTimeFormatter formatter; + + public DateTimeTypeAdapter() { + this(ISODateTimeFormat.dateTime().withOffsetParsed()); + } + + public DateTimeTypeAdapter(DateTimeFormatter formatter) { + this.formatter = formatter; + } + + public void setFormat(DateTimeFormatter dateFormat) { + this.formatter = dateFormat; + } + + @Override + public void write(JsonWriter out, DateTime date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + out.value(formatter.print(date)); + } + } + + @Override + public DateTime read(JsonReader in) throws IOException { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + return formatter.parseDateTime(date); + } } } /** - * Deserialize - * - * @param json Json element - * @param date Type - * @param context Json Serialization Context - * @return Date - * @throws JsonParseException if fail to parse + * Gson TypeAdapter for Joda LocalDate type */ - @Override - public Date deserialize(JsonElement json, Type date, JsonDeserializationContext context) throws JsonParseException { - String str = json.getAsJsonPrimitive().getAsString(); - try { - return apiClient.parseDateOrDatetime(str); - } catch (RuntimeException e) { - throw new JsonParseException(e); + public class LocalDateTypeAdapter extends TypeAdapter { + + private DateTimeFormatter formatter; + + public LocalDateTypeAdapter() { + this(ISODateTimeFormat.date()); } - } -} -{{^java8}} -/** - * Gson TypeAdapter for Joda DateTime type - */ -class DateTimeTypeAdapter extends TypeAdapter { + public LocalDateTypeAdapter(DateTimeFormatter formatter) { + this.formatter = formatter; + } - private final DateTimeFormatter formatter = ISODateTimeFormat.dateTime(); + public void setFormat(DateTimeFormatter dateFormat) { + this.formatter = dateFormat; + } - @Override - public void write(JsonWriter out, DateTime date) throws IOException { - if (date == null) { - out.nullValue(); - } else { - out.value(formatter.print(date)); + @Override + public void write(JsonWriter out, LocalDate date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + out.value(formatter.print(date)); + } + } + + @Override + public LocalDate read(JsonReader in) throws IOException { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + return formatter.parseLocalDate(date); + } } } - @Override - public DateTime read(JsonReader in) throws IOException { - switch (in.peek()) { - case NULL: - in.nextNull(); - return null; - default: - String date = in.nextString(); - return formatter.parseDateTime(date); - } + public JSON setDateTimeFormat(DateTimeFormatter dateFormat) { + dateTimeTypeAdapter.setFormat(dateFormat); + return this; } -} -/** - * Gson TypeAdapter for Joda LocalDate type - */ -class LocalDateTypeAdapter extends TypeAdapter { + public JSON setLocalDateFormat(DateTimeFormatter dateFormat) { + localDateTypeAdapter.setFormat(dateFormat); + return this; + } - private final DateTimeFormatter formatter = ISODateTimeFormat.date(); + {{/joda}} + {{#java8}} + /** + * Gson TypeAdapter for JSR310 OffsetDateTime type + */ + public static class OffsetDateTimeTypeAdapter extends TypeAdapter { - @Override - public void write(JsonWriter out, LocalDate date) throws IOException { - if (date == null) { - out.nullValue(); - } else { - out.value(formatter.print(date)); + private DateTimeFormatter formatter; + + public OffsetDateTimeTypeAdapter() { + this(DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } + + public OffsetDateTimeTypeAdapter(DateTimeFormatter formatter) { + this.formatter = formatter; + } + + public void setFormat(DateTimeFormatter dateFormat) { + this.formatter = dateFormat; + } + + @Override + public void write(JsonWriter out, OffsetDateTime date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + out.value(formatter.format(date)); + } + } + + @Override + public OffsetDateTime read(JsonReader in) throws IOException { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + if (date.endsWith("+0000")) { + date = date.substring(0, date.length()-5) + "Z"; + } + return OffsetDateTime.parse(date, formatter); + } } } - @Override - public LocalDate read(JsonReader in) throws IOException { - switch (in.peek()) { - case NULL: - in.nextNull(); - return null; - default: - String date = in.nextString(); - return formatter.parseLocalDate(date); + /** + * Gson TypeAdapter for JSR310 LocalDate type + */ + public class LocalDateTypeAdapter extends TypeAdapter { + + private DateTimeFormatter formatter; + + public LocalDateTypeAdapter() { + this(DateTimeFormatter.ISO_LOCAL_DATE); } - } -} -{{/java8}} -{{#java8}} -/** - * Gson TypeAdapter for jsr310 OffsetDateTime type - */ -class OffsetDateTimeTypeAdapter extends TypeAdapter { - private final DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME; + public LocalDateTypeAdapter(DateTimeFormatter formatter) { + this.formatter = formatter; + } - @Override - public void write(JsonWriter out, OffsetDateTime date) throws IOException { - if (date == null) { - out.nullValue(); - } else { - out.value(formatter.format(date)); + public void setFormat(DateTimeFormatter dateFormat) { + this.formatter = dateFormat; + } + + @Override + public void write(JsonWriter out, LocalDate date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + out.value(formatter.format(date)); + } + } + + @Override + public LocalDate read(JsonReader in) throws IOException { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + return LocalDate.parse(date, formatter); + } } } - @Override - public OffsetDateTime read(JsonReader in) throws IOException { - switch (in.peek()) { - case NULL: - in.nextNull(); - return null; - default: - String date = in.nextString(); - if (date.endsWith("+0000")) { - date = date.substring(0, date.length()-5) + "Z"; + public JSON setOffsetDateTimeFormat(DateTimeFormatter dateFormat) { + offsetDateTimeTypeAdapter.setFormat(dateFormat); + return this; + } + + public JSON setLocalDateFormat(DateTimeFormatter dateFormat) { + localDateTypeAdapter.setFormat(dateFormat); + return this; + } + + {{/java8}} + /** + * Gson TypeAdapter for java.sql.Date type + * If the dateFormat is null, a simple "yyyy-MM-dd" format will be used + * (more efficient than SimpleDateFormat). + */ + public static class SqlDateTypeAdapter extends TypeAdapter { + + private DateFormat dateFormat; + + public SqlDateTypeAdapter() { + } + + public SqlDateTypeAdapter(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + public void setFormat(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + @Override + public void write(JsonWriter out, java.sql.Date date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + String value; + if (dateFormat != null) { + value = dateFormat.format(date); + } else { + value = date.toString(); } + out.value(value); + } + } - return OffsetDateTime.parse(date, formatter); + @Override + public java.sql.Date read(JsonReader in) throws IOException { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + try { + if (dateFormat != null) { + return new java.sql.Date(dateFormat.parse(date).getTime()); + } + return new java.sql.Date(ISO8601Utils.parse(date, new ParsePosition(0)).getTime()); + } catch (ParseException e) { + throw new JsonParseException(e); + } + } } } + + /** + * Gson TypeAdapter for java.util.Date type + * If the dateFormat is null, ISO8601Utils will be used. + */ + public static class DateTypeAdapter extends TypeAdapter { + + private DateFormat dateFormat; + + public DateTypeAdapter() { + } + + public DateTypeAdapter(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + public void setFormat(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + @Override + public void write(JsonWriter out, Date date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + String value; + if (dateFormat != null) { + value = dateFormat.format(date); + } else { + value = ISO8601Utils.format(date, true); + } + out.value(value); + } + } + + @Override + public Date read(JsonReader in) throws IOException { + try { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + try { + if (dateFormat != null) { + return dateFormat.parse(date); + } + return ISO8601Utils.parse(date, new ParsePosition(0)); + } catch (ParseException e) { + throw new JsonParseException(e); + } + } + } catch (IllegalArgumentException e) { + throw new JsonParseException(e); + } + } + } + + public JSON setDateFormat(DateFormat dateFormat) { + dateTypeAdapter.setFormat(dateFormat); + return this; + } + + public JSON setSqlDateFormat(DateFormat dateFormat) { + sqlDateTypeAdapter.setFormat(dateFormat); + return this; + } + } - -/** - * Gson TypeAdapter for jsr310 LocalDate type - */ -class LocalDateTypeAdapter extends TypeAdapter { - - private final DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE; - - @Override - public void write(JsonWriter out, LocalDate date) throws IOException { - if (date == null) { - out.nullValue(); - } else { - out.value(formatter.format(date)); - } - } - - @Override - public LocalDate read(JsonReader in) throws IOException { - switch (in.peek()) { - case NULL: - in.nextNull(); - return null; - default: - String date = in.nextString(); - return LocalDate.parse(date, formatter); - } - } -} -{{/java8}} diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/ApiClient.java b/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/ApiClient.java index c4137dcb8169..0f388ea6e603 100644 --- a/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/ApiClient.java +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/ApiClient.java @@ -25,43 +25,24 @@ package io.swagger.client; -import com.squareup.okhttp.Call; -import com.squareup.okhttp.Callback; -import com.squareup.okhttp.OkHttpClient; -import com.squareup.okhttp.Request; -import com.squareup.okhttp.Response; -import com.squareup.okhttp.RequestBody; -import com.squareup.okhttp.FormEncodingBuilder; -import com.squareup.okhttp.MultipartBuilder; -import com.squareup.okhttp.MediaType; -import com.squareup.okhttp.Headers; +import com.squareup.okhttp.*; import com.squareup.okhttp.internal.http.HttpMethod; import com.squareup.okhttp.logging.HttpLoggingInterceptor; import com.squareup.okhttp.logging.HttpLoggingInterceptor.Level; +import okio.BufferedSink; +import okio.Okio; +import org.joda.time.DateTime; +import org.joda.time.LocalDate; +import org.joda.time.format.DateTimeFormatter; -import java.lang.reflect.Type; - -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.Map.Entry; -import java.util.HashMap; -import java.util.List; -import java.util.ArrayList; -import java.util.Date; -import java.util.TimeZone; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import java.net.URLEncoder; -import java.net.URLConnection; - +import javax.net.ssl.*; import java.io.File; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.io.UnsupportedEncodingException; - +import java.lang.reflect.Type; +import java.net.URLConnection; +import java.net.URLEncoder; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.SecureRandom; @@ -69,22 +50,12 @@ import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; - import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.text.ParseException; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; - -import okio.BufferedSink; -import okio.Okio; +import java.util.*; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import io.swagger.client.auth.Authentication; import io.swagger.client.auth.HttpBasicAuth; @@ -92,51 +63,14 @@ import io.swagger.client.auth.ApiKeyAuth; import io.swagger.client.auth.OAuth; public class ApiClient { - public static final double JAVA_VERSION; - public static final boolean IS_ANDROID; - public static final int ANDROID_SDK_VERSION; - - static { - JAVA_VERSION = Double.parseDouble(System.getProperty("java.specification.version")); - boolean isAndroid; - try { - Class.forName("android.app.Activity"); - isAndroid = true; - } catch (ClassNotFoundException e) { - isAndroid = false; - } - IS_ANDROID = isAndroid; - int sdkVersion = 0; - if (IS_ANDROID) { - try { - sdkVersion = Class.forName("android.os.Build$VERSION").getField("SDK_INT").getInt(null); - } catch (Exception e) { - try { - sdkVersion = Integer.parseInt((String) Class.forName("android.os.Build$VERSION").getField("SDK").get(null)); - } catch (Exception e2) { } - } - } - ANDROID_SDK_VERSION = sdkVersion; - } - - /** - * The datetime format to be used when lenientDatetimeFormat is enabled. - */ - public static final String LENIENT_DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; private String basePath = "http://petstore.swagger.io/v2"; - private boolean lenientOnJson = false; private boolean debugging = false; private Map defaultHeaderMap = new HashMap(); private String tempFolderPath = null; private Map authentications; - private DateFormat dateFormat; - private DateFormat datetimeFormat; - private boolean lenientDatetimeFormat; - private int dateLength; - private InputStream sslCaCert; private boolean verifyingSsl; @@ -150,23 +84,8 @@ public class ApiClient { */ public ApiClient() { httpClient = new OkHttpClient(); - verifyingSsl = true; - - json = new JSON(this); - - /* - * Use RFC3339 format for date and datetime. - * See http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14 - */ - this.dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - // Always use UTC as the default time zone when dealing with date (without time). - this.dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - initDatetimeFormat(); - - // Be lenient on datetime formats when parsing datetime from string. - // See parseDatetime. - this.lenientDatetimeFormat = true; + json = new JSON(); // Set default User-Agent. setUserAgent("Swagger-Codegen/1.0.0/java"); @@ -285,143 +204,29 @@ public class ApiClient { return this; } - public DateFormat getDateFormat() { - return dateFormat; - } - public ApiClient setDateFormat(DateFormat dateFormat) { - this.dateFormat = dateFormat; - this.dateLength = this.dateFormat.format(new Date()).length(); + this.json.setDateFormat(dateFormat); return this; } - public DateFormat getDatetimeFormat() { - return datetimeFormat; - } - - public ApiClient setDatetimeFormat(DateFormat datetimeFormat) { - this.datetimeFormat = datetimeFormat; + public ApiClient setSqlDateFormat(DateFormat dateFormat) { + this.json.setSqlDateFormat(dateFormat); return this; } - /** - * Whether to allow various ISO 8601 datetime formats when parsing a datetime string. - * @see #parseDatetime(String) - * @return True if lenientDatetimeFormat flag is set to true - */ - public boolean isLenientDatetimeFormat() { - return lenientDatetimeFormat; - } - - public ApiClient setLenientDatetimeFormat(boolean lenientDatetimeFormat) { - this.lenientDatetimeFormat = lenientDatetimeFormat; + public ApiClient setDateTimeFormat(DateTimeFormatter dateFormat) { + this.json.setDateTimeFormat(dateFormat); return this; } - /** - * Parse the given date string into Date object. - * The default dateFormat supports these ISO 8601 date formats: - * 2015-08-16 - * 2015-8-16 - * @param str String to be parsed - * @return Date - */ - public Date parseDate(String str) { - if (str == null) - return null; - try { - return dateFormat.parse(str); - } catch (ParseException e) { - throw new RuntimeException(e); - } + public ApiClient setLocalDateFormat(DateTimeFormatter dateFormat) { + this.json.setLocalDateFormat(dateFormat); + return this; } - /** - * Parse the given datetime string into Date object. - * When lenientDatetimeFormat is enabled, the following ISO 8601 datetime formats are supported: - * 2015-08-16T08:20:05Z - * 2015-8-16T8:20:05Z - * 2015-08-16T08:20:05+00:00 - * 2015-08-16T08:20:05+0000 - * 2015-08-16T08:20:05.376Z - * 2015-08-16T08:20:05.376+00:00 - * 2015-08-16T08:20:05.376+00 - * Note: The 3-digit milli-seconds is optional. Time zone is required and can be in one of - * these formats: - * Z (same with +0000) - * +08:00 (same with +0800) - * -02 (same with -0200) - * -0200 - * @see ISO 8601 - * @param str Date time string to be parsed - * @return Date representation of the string - */ - public Date parseDatetime(String str) { - if (str == null) - return null; - - DateFormat format; - if (lenientDatetimeFormat) { - /* - * When lenientDatetimeFormat is enabled, normalize the date string - * into LENIENT_DATETIME_FORMAT to support various formats - * defined by ISO 8601. - */ - // normalize time zone - // trailing "Z": 2015-08-16T08:20:05Z => 2015-08-16T08:20:05+0000 - str = str.replaceAll("[zZ]\\z", "+0000"); - // remove colon in time zone: 2015-08-16T08:20:05+00:00 => 2015-08-16T08:20:05+0000 - str = str.replaceAll("([+-]\\d{2}):(\\d{2})\\z", "$1$2"); - // expand time zone: 2015-08-16T08:20:05+00 => 2015-08-16T08:20:05+0000 - str = str.replaceAll("([+-]\\d{2})\\z", "$100"); - // add milliseconds when missing - // 2015-08-16T08:20:05+0000 => 2015-08-16T08:20:05.000+0000 - str = str.replaceAll("(:\\d{1,2})([+-]\\d{4})\\z", "$1.000$2"); - format = new SimpleDateFormat(LENIENT_DATETIME_FORMAT); - } else { - format = this.datetimeFormat; - } - - try { - return format.parse(str); - } catch (ParseException e) { - throw new RuntimeException(e); - } - } - - /* - * Parse date or date time in string format into Date object. - * - * @param str Date time string to be parsed - * @return Date representation of the string - */ - public Date parseDateOrDatetime(String str) { - if (str == null) - return null; - else if (str.length() <= dateLength) - return parseDate(str); - else - return parseDatetime(str); - } - - /** - * Format the given Date object into string (Date format). - * - * @param date Date object - * @return Formatted date in string representation - */ - public String formatDate(Date date) { - return dateFormat.format(date); - } - - /** - * Format the given Date object into string (Datetime format). - * - * @param date Date object - * @return Formatted datetime in string representation - */ - public String formatDatetime(Date date) { - return datetimeFormat.format(date); + public ApiClient setLenientOnJson(boolean lenientOnJson) { + this.json.setLenientOnJson(lenientOnJson); + return this; } /** @@ -541,26 +346,6 @@ public class ApiClient { return this; } - /** - * @see setLenient - * - * @return True if lenientOnJson is enabled, false otherwise. - */ - public boolean isLenientOnJson() { - return lenientOnJson; - } - - /** - * Set LenientOnJson - * - * @param lenient True to enable lenientOnJson - * @return ApiClient - */ - public ApiClient setLenientOnJson(boolean lenient) { - this.lenientOnJson = lenient; - return this; - } - /** * Check that whether debugging is enabled for this API client. * @@ -644,8 +429,10 @@ public class ApiClient { public String parameterToString(Object param) { if (param == null) { return ""; - } else if (param instanceof Date) { - return formatDatetime((Date) param); + } else if (param instanceof Date || param instanceof DateTime || param instanceof LocalDate) { + //Serialize to json string and remove the " enclosing characters + String jsonStr = json.serialize(param); + return jsonStr.substring(1, jsonStr.length() - 1); } else if (param instanceof Collection) { StringBuilder b = new StringBuilder(); for (Object o : (Collection)param) { @@ -1235,31 +1022,6 @@ public class ApiClient { } } - /** - * Initialize datetime format according to the current environment, e.g. Java 1.7 and Android. - */ - private void initDatetimeFormat() { - String formatWithTimeZone = null; - if (IS_ANDROID) { - if (ANDROID_SDK_VERSION >= 18) { - // The time zone format "ZZZZZ" is available since Android 4.3 (SDK version 18) - formatWithTimeZone = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"; - } - } else if (JAVA_VERSION >= 1.7) { - // The time zone format "XXX" is available since Java 1.7 - formatWithTimeZone = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"; - } - if (formatWithTimeZone != null) { - this.datetimeFormat = new SimpleDateFormat(formatWithTimeZone); - // NOTE: Use the system's default time zone (mainly for datetime formatting). - } else { - // Use a common format that works across all systems. - this.datetimeFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); - // Always use the UTC time zone as we are using a constant trailing "Z" here. - this.datetimeFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - } - } - /** * Apply SSL related settings to httpClient according to the current values of * verifyingSsl and sslCaCert. diff --git a/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/JSON.java b/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/JSON.java index a734bec47f1b..64c68da1f251 100644 --- a/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/JSON.java +++ b/samples/client/petstore/java/okhttp-gson/src/main/java/io/swagger/client/JSON.java @@ -27,43 +27,38 @@ package io.swagger.client; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonNull; import com.google.gson.JsonParseException; -import com.google.gson.JsonPrimitive; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; import com.google.gson.TypeAdapter; +import com.google.gson.internal.bind.util.ISO8601Utils; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; - -import java.io.IOException; -import java.io.StringReader; -import java.lang.reflect.Type; -import java.util.Date; - import org.joda.time.DateTime; import org.joda.time.LocalDate; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; -public class JSON { - private ApiClient apiClient; - private Gson gson; +import java.io.IOException; +import java.io.StringReader; +import java.lang.reflect.Type; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.ParsePosition; +import java.util.Date; - /** - * JSON constructor. - * - * @param apiClient An instance of ApiClient - */ - public JSON(ApiClient apiClient) { - this.apiClient = apiClient; +public class JSON { + private Gson gson; + private boolean isLenientOnJson = false; + private DateTypeAdapter dateTypeAdapter = new DateTypeAdapter(); + private SqlDateTypeAdapter sqlDateTypeAdapter = new SqlDateTypeAdapter(); + private DateTimeTypeAdapter dateTimeTypeAdapter = new DateTimeTypeAdapter(); + private LocalDateTypeAdapter localDateTypeAdapter = new LocalDateTypeAdapter(); + + public JSON() { gson = new GsonBuilder() - .registerTypeAdapter(Date.class, new DateAdapter(apiClient)) - .registerTypeAdapter(DateTime.class, new DateTimeTypeAdapter()) - .registerTypeAdapter(LocalDate.class, new LocalDateTypeAdapter()) + .registerTypeAdapter(Date.class, dateTypeAdapter) + .registerTypeAdapter(java.sql.Date.class, sqlDateTypeAdapter) + .registerTypeAdapter(DateTime.class, dateTimeTypeAdapter) + .registerTypeAdapter(LocalDate.class, localDateTypeAdapter) .create(); } @@ -81,8 +76,14 @@ public class JSON { * * @param gson Gson */ - public void setGson(Gson gson) { + public JSON setGson(Gson gson) { this.gson = gson; + return this; + } + + public JSON setLenientOnJson(boolean lenientOnJson) { + isLenientOnJson = lenientOnJson; + return this; } /** @@ -98,15 +99,15 @@ public class JSON { /** * Deserialize the given JSON string to Java object. * - * @param Type - * @param body The JSON string + * @param Type + * @param body The JSON string * @param returnType The type to deserialize into * @return The deserialized Java object */ @SuppressWarnings("unchecked") public T deserialize(String body, Type returnType) { try { - if (apiClient.isLenientOnJson()) { + if (isLenientOnJson) { JsonReader jsonReader = new JsonReader(new StringReader(body)); // see https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/stream/JsonReader.html#setLenient(boolean) jsonReader.setLenient(true); @@ -116,121 +117,226 @@ public class JSON { } } catch (JsonParseException e) { // Fallback processing when failed to parse JSON form response body: - // return the response body string directly for the String return type; - // parse response body into date or datetime for the Date return type. + // return the response body string directly for the String return type; if (returnType.equals(String.class)) return (T) body; - else if (returnType.equals(Date.class)) - return (T) apiClient.parseDateOrDatetime(body); - else throw(e); - } - } -} - -class DateAdapter implements JsonSerializer, JsonDeserializer { - private final ApiClient apiClient; - - /** - * Constructor for DateAdapter - * - * @param apiClient Api client - */ - public DateAdapter(ApiClient apiClient) { - super(); - this.apiClient = apiClient; - } - - /** - * Serialize - * - * @param src Date - * @param typeOfSrc Type - * @param context Json Serialization Context - * @return Json Element - */ - @Override - public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) { - if (src == null) { - return JsonNull.INSTANCE; - } else { - return new JsonPrimitive(apiClient.formatDatetime(src)); + else throw (e); } } /** - * Deserialize - * - * @param json Json element - * @param date Type - * @param context Json Serialization Context - * @return Date - * @throws JsonParseException if fail to parse + * Gson TypeAdapter for Joda DateTime type */ - @Override - public Date deserialize(JsonElement json, Type date, JsonDeserializationContext context) throws JsonParseException { - String str = json.getAsJsonPrimitive().getAsString(); - try { - return apiClient.parseDateOrDatetime(str); - } catch (RuntimeException e) { - throw new JsonParseException(e); - } - } -} - -/** - * Gson TypeAdapter for Joda DateTime type - */ -class DateTimeTypeAdapter extends TypeAdapter { - - private final DateTimeFormatter formatter = ISODateTimeFormat.dateTime(); - - @Override - public void write(JsonWriter out, DateTime date) throws IOException { - if (date == null) { - out.nullValue(); - } else { - out.value(formatter.print(date)); - } - } - - @Override - public DateTime read(JsonReader in) throws IOException { - switch (in.peek()) { - case NULL: - in.nextNull(); - return null; - default: - String date = in.nextString(); - return formatter.parseDateTime(date); - } - } -} - -/** - * Gson TypeAdapter for Joda LocalDate type - */ -class LocalDateTypeAdapter extends TypeAdapter { - - private final DateTimeFormatter formatter = ISODateTimeFormat.date(); - - @Override - public void write(JsonWriter out, LocalDate date) throws IOException { - if (date == null) { - out.nullValue(); - } else { - out.value(formatter.print(date)); - } - } - - @Override - public LocalDate read(JsonReader in) throws IOException { - switch (in.peek()) { - case NULL: - in.nextNull(); - return null; - default: - String date = in.nextString(); - return formatter.parseLocalDate(date); + public static class DateTimeTypeAdapter extends TypeAdapter { + + private DateTimeFormatter formatter; + + public DateTimeTypeAdapter() { + this(ISODateTimeFormat.dateTime().withOffsetParsed()); + } + + public DateTimeTypeAdapter(DateTimeFormatter formatter) { + this.formatter = formatter; + } + + public void setFormat(DateTimeFormatter dateFormat) { + this.formatter = dateFormat; + } + + @Override + public void write(JsonWriter out, DateTime date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + out.value(formatter.print(date)); + } + } + + @Override + public DateTime read(JsonReader in) throws IOException { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + return formatter.parseDateTime(date); + } } } + + /** + * Gson TypeAdapter for Joda LocalDate type + */ + public class LocalDateTypeAdapter extends TypeAdapter { + + private DateTimeFormatter formatter; + + public LocalDateTypeAdapter() { + this(ISODateTimeFormat.date()); + } + + public LocalDateTypeAdapter(DateTimeFormatter formatter) { + this.formatter = formatter; + } + + public void setFormat(DateTimeFormatter dateFormat) { + this.formatter = dateFormat; + } + + @Override + public void write(JsonWriter out, LocalDate date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + out.value(formatter.print(date)); + } + } + + @Override + public LocalDate read(JsonReader in) throws IOException { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + return formatter.parseLocalDate(date); + } + } + } + + public JSON setDateTimeFormat(DateTimeFormatter dateFormat) { + dateTimeTypeAdapter.setFormat(dateFormat); + return this; + } + + public JSON setLocalDateFormat(DateTimeFormatter dateFormat) { + localDateTypeAdapter.setFormat(dateFormat); + return this; + } + + /** + * Gson TypeAdapter for java.sql.Date type + * If the dateFormat is null, a simple "yyyy-MM-dd" format will be used + * (more efficient than SimpleDateFormat). + */ + public static class SqlDateTypeAdapter extends TypeAdapter { + + private DateFormat dateFormat; + + public SqlDateTypeAdapter() { + } + + public SqlDateTypeAdapter(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + public void setFormat(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + @Override + public void write(JsonWriter out, java.sql.Date date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + String value; + if (dateFormat != null) { + value = dateFormat.format(date); + } else { + value = date.toString(); + } + out.value(value); + } + } + + @Override + public java.sql.Date read(JsonReader in) throws IOException { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + try { + if (dateFormat != null) { + return new java.sql.Date(dateFormat.parse(date).getTime()); + } + return new java.sql.Date(ISO8601Utils.parse(date, new ParsePosition(0)).getTime()); + } catch (ParseException e) { + throw new JsonParseException(e); + } + } + } + } + + /** + * Gson TypeAdapter for java.util.Date type + * If the dateFormat is null, ISO8601Utils will be used. + */ + public static class DateTypeAdapter extends TypeAdapter { + + private DateFormat dateFormat; + + public DateTypeAdapter() { + } + + public DateTypeAdapter(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + public void setFormat(DateFormat dateFormat) { + this.dateFormat = dateFormat; + } + + @Override + public void write(JsonWriter out, Date date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + String value; + if (dateFormat != null) { + value = dateFormat.format(date); + } else { + value = ISO8601Utils.format(date, true); + } + out.value(value); + } + } + + @Override + public Date read(JsonReader in) throws IOException { + try { + switch (in.peek()) { + case NULL: + in.nextNull(); + return null; + default: + String date = in.nextString(); + try { + if (dateFormat != null) { + return dateFormat.parse(date); + } + return ISO8601Utils.parse(date, new ParsePosition(0)); + } catch (ParseException e) { + throw new JsonParseException(e); + } + } + } catch (IllegalArgumentException e) { + throw new JsonParseException(e); + } + } + } + + public JSON setDateFormat(DateFormat dateFormat) { + dateTypeAdapter.setFormat(dateFormat); + return this; + } + + public JSON setSqlDateFormat(DateFormat dateFormat) { + sqlDateTypeAdapter.setFormat(dateFormat); + return this; + } + } diff --git a/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/ApiClientTest.java b/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/ApiClientTest.java index 5345e2a1646e..df6cff4ecb79 100644 --- a/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/ApiClientTest.java +++ b/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/ApiClientTest.java @@ -12,69 +12,13 @@ import static org.junit.Assert.*; public class ApiClientTest { - ApiClient apiClient = null; + ApiClient apiClient; + JSON json; @Before public void setup() { apiClient = new ApiClient(); - } - - @Test - public void testParseAndFormatDatetime() { - // default datetime format with UTC time zone - apiClient.getDatetimeFormat().setTimeZone(TimeZone.getTimeZone("UTC")); - String dateStr = "2015-11-07T03:49:09.356Z"; - assertTrue(apiClient.isLenientDatetimeFormat()); - assertEquals(dateStr, apiClient.formatDatetime(apiClient.parseDatetime("2015-11-07T03:49:09.356+00:00"))); - assertEquals(dateStr, apiClient.formatDatetime(apiClient.parseDatetime("2015-11-07T05:49:09.356+02:00"))); - assertEquals(dateStr, apiClient.formatDatetime(apiClient.parseDatetime("2015-11-07T02:49:09.356-01:00"))); - // support various cases - assertEquals(dateStr, apiClient.formatDatetime(apiClient.parseDatetime("2015-11-07T03:49:09.356Z"))); - assertEquals(dateStr, apiClient.formatDatetime(apiClient.parseDatetime("2015-11-07T03:49:09.356+00"))); - assertEquals(dateStr, apiClient.formatDatetime(apiClient.parseDatetime("2015-11-07T02:49:09.356-0100"))); - dateStr = "2015-11-07T03:49:09.000Z"; - assertEquals(dateStr, apiClient.formatDatetime(apiClient.parseDatetime("2015-11-07T05:49:09+02"))); - - // custom datetime format: without milli-seconds, custom time zone - DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX"); - format.setTimeZone(TimeZone.getTimeZone("GMT+10")); - apiClient.setDatetimeFormat(format); - // disable support of various datetime format - apiClient.setLenientDatetimeFormat(false); - dateStr = "2015-11-07T13:49:09+10:00"; - assertEquals(dateStr, apiClient.formatDatetime(apiClient.parseDatetime("2015-11-07T03:49:09+00:00"))); - assertEquals(dateStr, apiClient.formatDatetime(apiClient.parseDatetime("2015-11-07T03:49:09Z"))); - assertEquals(dateStr, apiClient.formatDatetime(apiClient.parseDatetime("2015-11-07T00:49:09-03:00"))); - - try { - // invalid time zone format - apiClient.parseDatetime("2015-11-07T03:49:09+00"); - fail("parseDatetime should fail"); - } catch (RuntimeException e) { - // OK - } - try { - // unexpected miliseconds - apiClient.parseDatetime("2015-11-07T03:49:09.000Z"); - fail("parseDatetime should fail"); - } catch (RuntimeException e) { - // OK - } - } - - @Test - public void testParseAndFormatDate() { - // default date format - String dateStr = "2015-11-07"; - assertEquals(dateStr, apiClient.formatDate(apiClient.parseDatetime("2015-11-07T03:49:09.356+00:00"))); - assertEquals(dateStr, apiClient.formatDate(apiClient.parseDate("2015-11-07"))); - - // custom date format: without day - DateFormat format = new SimpleDateFormat("yyyy-MM"); - apiClient.setDateFormat(format); - dateStr = "2015-11"; - assertEquals(dateStr, apiClient.formatDate(apiClient.parseDatetime("2015-11-07T03:49:09Z"))); - assertEquals(dateStr, apiClient.formatDate(apiClient.parseDate("2015-11"))); + json = apiClient.getJSON(); } @Test diff --git a/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/JSONTest.java b/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/JSONTest.java index 8dab64b289e2..13ad996920a5 100644 --- a/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/JSONTest.java +++ b/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/JSONTest.java @@ -6,8 +6,16 @@ import io.swagger.client.model.Order; import java.lang.Exception; import java.lang.reflect.Type; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; +import org.joda.time.DateTime; import org.joda.time.DateTimeZone; +import org.joda.time.LocalDate; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; import org.junit.*; @@ -21,10 +29,99 @@ public class JSONTest { @Before public void setup() { apiClient = new ApiClient(); - json = new JSON(apiClient); + json = apiClient.getJSON(); order = new Order(); } + @Test + public void testSqlDateTypeAdapter() { + final String str = "\"2015-11-07\""; + final java.sql.Date date = java.sql.Date.valueOf("2015-11-07"); + + assertEquals(str, json.serialize(date)); + assertEquals(json.deserialize(str, java.sql.Date.class), date); + assertEquals(json.deserialize("\"2015-11-07T03:49:09.356+00:00\"", java.sql.Date.class).toString(), date.toString()); + + // custom date format: without day + DateFormat format = new SimpleDateFormat("yyyy-MM"); + apiClient.setSqlDateFormat(format); + String dateStr = "\"2015-11\""; + assertEquals(dateStr, json.serialize(json.deserialize("\"2015-11-07T03:49:09Z\"", java.sql.Date.class))); + assertEquals(dateStr, json.serialize(json.deserialize("\"2015-11\"", java.sql.Date.class))); + } + + @Test + public void testDateTypeAdapter() { + Calendar cal = new GregorianCalendar(2015, 10, 7, 3, 49, 9); + cal.setTimeZone(TimeZone.getTimeZone("UTC")); + + assertEquals(json.deserialize("\"2015-11-07T05:49:09+02\"", Date.class), cal.getTime()); + + cal.set(Calendar.MILLISECOND, 300); + assertEquals(json.deserialize("\"2015-11-07T03:49:09.3Z\"", Date.class), cal.getTime()); + + cal.set(Calendar.MILLISECOND, 356); + Date date = cal.getTime(); + + final String utcDate = "\"2015-11-07T03:49:09.356Z\""; + assertEquals(json.deserialize(utcDate, Date.class), date); + assertEquals(json.deserialize("\"2015-11-07T03:49:09.356+00:00\"", Date.class), date); + assertEquals(json.deserialize("\"2015-11-07T05:49:09.356+02:00\"", Date.class), date); + assertEquals(json.deserialize("\"2015-11-07T02:49:09.356-01:00\"", Date.class), date); + assertEquals(json.deserialize("\"2015-11-07T03:49:09.356Z\"", Date.class), date); + assertEquals(json.deserialize("\"2015-11-07T03:49:09.356+00\"", Date.class), date); + assertEquals(json.deserialize("\"2015-11-07T02:49:09.356-0100\"", Date.class), date); + assertEquals(json.deserialize("\"2015-11-07T03:49:09.356456789Z\"", Date.class), date); + + assertEquals(utcDate, json.serialize(date)); + + // custom datetime format: without milli-seconds, custom time zone + DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX"); + format.setTimeZone(TimeZone.getTimeZone("GMT+10")); + apiClient.setDateFormat(format); + + String dateStr = "\"2015-11-07T13:49:09+10:00\""; + assertEquals(dateStr, json.serialize(json.deserialize("\"2015-11-07T03:49:09+00:00\"", Date.class))); + assertEquals(dateStr, json.serialize(json.deserialize("\"2015-11-07T03:49:09Z\"", Date.class))); + assertEquals(dateStr, json.serialize(json.deserialize("\"2015-11-07T00:49:09-03:00\"", Date.class))); + + try { + // invalid time zone format + json.deserialize("\"2015-11-07T03:49:09+00\"", Date.class); + fail("json parsing should fail"); + } catch (RuntimeException e) { + // OK + } + try { + // unexpected miliseconds + json.deserialize("\"2015-11-07T03:49:09.000Z\"", Date.class); + fail("json parsing should fail"); + } catch (RuntimeException e) { + // OK + } + + } + + @Test + public void testDateTimeTypeAdapter() { + final String str = "\"2016-09-09T08:02:03.123-03:00\""; + DateTime date = new DateTime(2016, 9, 9, 8, 2, 3, 123, DateTimeZone.forID("Etc/GMT+3")); + + assertEquals(str, json.serialize(date)); + //Use toString() instead of isEqual to verify that the offset is preserved + assertEquals(json.deserialize(str, DateTime.class).toString(), date.toString()); + } + + @Test + public void testLocalDateTypeAdapter() { + final String str = "\"2016-09-09\""; + final LocalDate date = new LocalDate(2016, 9, 9); + + assertEquals(str, json.serialize(date)); + assertEquals(json.deserialize(str, LocalDate.class), date); + } + + @Test public void testDefaultDate() throws Exception { final DateTimeFormatter datetimeFormat = ISODateTimeFormat.dateTime().withZone(DateTimeZone.UTC); diff --git a/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/api/PetApiTest.java b/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/api/PetApiTest.java index 8bfb76050930..497c31d6b1bf 100644 --- a/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/api/PetApiTest.java +++ b/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/api/PetApiTest.java @@ -153,7 +153,7 @@ public class PetApiTest { // test getting a nonexistent pet result.clear(); - api.getPetByIdAsync(new Long(-10000), new ApiCallback() { + api.getPetByIdAsync(-10000L, new ApiCallback() { @Override public void onFailure(ApiException e, int statusCode, Map> responseHeaders) { result.put("exception", e); @@ -174,8 +174,6 @@ public class PetApiTest { //empty } }); - // the API call should be executed asynchronously, so result should be empty at the moment - assertTrue(result.isEmpty()); // wait for the asynchronous call to finish (at most 10 seconds) tryCount = 1; @@ -254,7 +252,7 @@ public class PetApiTest { api.updatePet(pet); - List pets = api.findPetsByStatus(Arrays.asList(new String[]{"pending"})); + List pets = api.findPetsByStatus(Arrays.asList("pending")); assertNotNull(pets); boolean found = false; @@ -284,7 +282,7 @@ public class PetApiTest { api.updatePet(pet); - List pets = api.findPetsByTags(Arrays.asList(new String[]{"friendly"})); + List pets = api.findPetsByTags(Arrays.asList("friendly")); assertNotNull(pets); boolean found = false; @@ -353,7 +351,7 @@ public class PetApiTest { assertTrue(pet1.hashCode() == pet1.hashCode()); pet2.setName("really-happy"); - pet2.setPhotoUrls(Arrays.asList(new String[]{"http://foo.bar.com/1", "http://foo.bar.com/2"})); + pet2.setPhotoUrls(Arrays.asList("http://foo.bar.com/1", "http://foo.bar.com/2")); assertFalse(pet1.equals(pet2)); assertFalse(pet2.equals(pet1)); assertFalse(pet1.hashCode() == (pet2.hashCode())); @@ -361,7 +359,7 @@ public class PetApiTest { assertTrue(pet2.hashCode() == pet2.hashCode()); pet1.setName("really-happy"); - pet1.setPhotoUrls(Arrays.asList(new String[]{"http://foo.bar.com/1", "http://foo.bar.com/2"})); + pet1.setPhotoUrls(Arrays.asList("http://foo.bar.com/1", "http://foo.bar.com/2")); assertTrue(pet1.equals(pet2)); assertTrue(pet2.equals(pet1)); assertTrue(pet1.hashCode() == pet2.hashCode()); @@ -379,7 +377,7 @@ public class PetApiTest { pet.setCategory(category); pet.setStatus(Pet.StatusEnum.AVAILABLE); - List photos = Arrays.asList(new String[]{"http://foo.bar.com/1", "http://foo.bar.com/2"}); + List photos = Arrays.asList("http://foo.bar.com/1", "http://foo.bar.com/2"); pet.setPhotoUrls(photos); return pet; diff --git a/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/api/StoreApiTest.java b/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/api/StoreApiTest.java index 0e18ce8e07a7..84a20f33392f 100644 --- a/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/api/StoreApiTest.java +++ b/samples/client/petstore/java/okhttp-gson/src/test/java/io/swagger/client/api/StoreApiTest.java @@ -22,12 +22,6 @@ public class StoreApiTest { // setup authentication ApiKeyAuth apiKeyAuth = (ApiKeyAuth) api.getApiClient().getAuthentication("api_key"); apiKeyAuth.setApiKey("special-key"); - // set custom date format that is used by the petstore server - // Note: it would still work without this setting as okhttp-gson Java client supports - // various date formats by default (with lenientDatetimeFormat enabled), including - // the one used by petstore server - api.getApiClient().setDatetimeFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")); - api.getApiClient().setLenientDatetimeFormat(false); } @Test @@ -84,8 +78,8 @@ public class StoreApiTest { private Order createOrder() { Order order = new Order(); - order.setPetId(new Long(200)); - order.setQuantity(new Integer(13)); + order.setPetId(200L); + order.setQuantity(13); order.setShipDate(org.joda.time.DateTime.now()); order.setStatus(Order.StatusEnum.PLACED); order.setComplete(true);