[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
This commit is contained in:
cbornet
2016-09-13 15:57:34 +02:00
parent 766b04a2bd
commit 2a0574a3ad
9 changed files with 760 additions and 928 deletions

View File

@@ -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 <code>lenientDatetimeFormat</code> 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<String, String> defaultHeaderMap = new HashMap<String, String>();
private String tempFolderPath = null;
private Map<String, Authentication> 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 <code>parseDatetime</code>.
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 <code>dateFormat</code> 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 <a href="https://en.wikipedia.org/wiki/ISO_8601">ISO 8601</a>
* @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 <code>LENIENT_DATETIME_FORMAT</code> 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 <a href="https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/stream/JsonReader.html#setLenient(boolean)">setLenient</a>
*
* @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.

View File

@@ -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 <T> Type
* @param body The JSON string
* @param <T> Type
* @param body The JSON string
* @param returnType The type to deserialize into
* @return The deserialized Java object
*/
@SuppressWarnings("unchecked")
public <T> 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<Date>, JsonDeserializer<Date> {
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<DateTime> {
/**
* 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<LocalDate> {
private DateTimeFormatter formatter;
public LocalDateTypeAdapter() {
this(ISODateTimeFormat.date());
}
}
}
{{^java8}}
/**
* Gson TypeAdapter for Joda DateTime type
*/
class DateTimeTypeAdapter extends TypeAdapter<DateTime> {
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<LocalDate> {
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<OffsetDateTime> {
@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<LocalDate> {
private DateTimeFormatter formatter;
public LocalDateTypeAdapter() {
this(DateTimeFormatter.ISO_LOCAL_DATE);
}
}
}
{{/java8}}
{{#java8}}
/**
* Gson TypeAdapter for jsr310 OffsetDateTime type
*/
class OffsetDateTimeTypeAdapter extends TypeAdapter<OffsetDateTime> {
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<java.sql.Date> {
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<Date> {
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<LocalDate> {
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}}