/*
 * Ory APIs
 * Documentation for all public and administrative Ory APIs. Administrative APIs can only be accessed with a valid Personal Access Token. Public APIs are mostly used in browsers. 
 *
 * The version of the OpenAPI document: v1.1.51
 * Contact: support@ory.sh
 *
 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
 * https://openapi-generator.tech
 * Do not edit the class manually.
 */


package sh.ory;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
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 com.google.gson.JsonElement;
import io.gsonfire.GsonFireBuilder;
import io.gsonfire.TypeSelector;

import okio.ByteString;

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.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.HashMap;

/*
 * A JSON utility class
 *
 * NOTE: in the future, this class may be converted to static, which may break
 *       backward-compatibility
 */
public class JSON {
    private static Gson gson;
    private static boolean isLenientOnJson = false;
    private static DateTypeAdapter dateTypeAdapter = new DateTypeAdapter();
    private static SqlDateTypeAdapter sqlDateTypeAdapter = new SqlDateTypeAdapter();
    private static OffsetDateTimeTypeAdapter offsetDateTimeTypeAdapter = new OffsetDateTimeTypeAdapter();
    private static LocalDateTypeAdapter localDateTypeAdapter = new LocalDateTypeAdapter();
    private static ByteArrayAdapter byteArrayAdapter = new ByteArrayAdapter();

    @SuppressWarnings("unchecked")
    public static GsonBuilder createGson() {
        GsonFireBuilder fireBuilder = new GsonFireBuilder()
                .registerTypeSelector(sh.ory.model.ContinueWith.class, new TypeSelector<sh.ory.model.ContinueWith>() {
                    @Override
                    public Class<? extends sh.ory.model.ContinueWith> getClassForElement(JsonElement readElement) {
                        Map<String, Class> classByDiscriminatorValue = new HashMap<String, Class>();
                        classByDiscriminatorValue.put("continueWithSetOrySessionToken", sh.ory.model.ContinueWithSetOrySessionToken.class);
                        classByDiscriminatorValue.put("continueWithVerificationUi", sh.ory.model.ContinueWithVerificationUi.class);
                        classByDiscriminatorValue.put("set_ory_session_token", sh.ory.model.ContinueWithSetOrySessionToken.class);
                        classByDiscriminatorValue.put("show_verification_ui", sh.ory.model.ContinueWithVerificationUi.class);
                        classByDiscriminatorValue.put("continueWith", sh.ory.model.ContinueWith.class);
                        return getClassByDiscriminator(classByDiscriminatorValue,
                                getDiscriminatorValue(readElement, "action"));
                    }
          })
                .registerTypeSelector(sh.ory.model.UiNodeAttributes.class, new TypeSelector<sh.ory.model.UiNodeAttributes>() {
                    @Override
                    public Class<? extends sh.ory.model.UiNodeAttributes> getClassForElement(JsonElement readElement) {
                        Map<String, Class> classByDiscriminatorValue = new HashMap<String, Class>();
                        classByDiscriminatorValue.put("a", sh.ory.model.UiNodeAnchorAttributes.class);
                        classByDiscriminatorValue.put("img", sh.ory.model.UiNodeImageAttributes.class);
                        classByDiscriminatorValue.put("input", sh.ory.model.UiNodeInputAttributes.class);
                        classByDiscriminatorValue.put("script", sh.ory.model.UiNodeScriptAttributes.class);
                        classByDiscriminatorValue.put("text", sh.ory.model.UiNodeTextAttributes.class);
                        classByDiscriminatorValue.put("uiNodeAnchorAttributes", sh.ory.model.UiNodeAnchorAttributes.class);
                        classByDiscriminatorValue.put("uiNodeImageAttributes", sh.ory.model.UiNodeImageAttributes.class);
                        classByDiscriminatorValue.put("uiNodeInputAttributes", sh.ory.model.UiNodeInputAttributes.class);
                        classByDiscriminatorValue.put("uiNodeScriptAttributes", sh.ory.model.UiNodeScriptAttributes.class);
                        classByDiscriminatorValue.put("uiNodeTextAttributes", sh.ory.model.UiNodeTextAttributes.class);
                        classByDiscriminatorValue.put("uiNodeAttributes", sh.ory.model.UiNodeAttributes.class);
                        return getClassByDiscriminator(classByDiscriminatorValue,
                                getDiscriminatorValue(readElement, "node_type"));
                    }
          })
                .registerTypeSelector(sh.ory.model.UpdateLoginFlowBody.class, new TypeSelector<sh.ory.model.UpdateLoginFlowBody>() {
                    @Override
                    public Class<? extends sh.ory.model.UpdateLoginFlowBody> getClassForElement(JsonElement readElement) {
                        Map<String, Class> classByDiscriminatorValue = new HashMap<String, Class>();
                        classByDiscriminatorValue.put("lookup_secret", sh.ory.model.UpdateLoginFlowWithLookupSecretMethod.class);
                        classByDiscriminatorValue.put("oidc", sh.ory.model.UpdateLoginFlowWithOidcMethod.class);
                        classByDiscriminatorValue.put("password", sh.ory.model.UpdateLoginFlowWithPasswordMethod.class);
                        classByDiscriminatorValue.put("totp", sh.ory.model.UpdateLoginFlowWithTotpMethod.class);
                        classByDiscriminatorValue.put("updateLoginFlowWithLookupSecretMethod", sh.ory.model.UpdateLoginFlowWithLookupSecretMethod.class);
                        classByDiscriminatorValue.put("updateLoginFlowWithOidcMethod", sh.ory.model.UpdateLoginFlowWithOidcMethod.class);
                        classByDiscriminatorValue.put("updateLoginFlowWithPasswordMethod", sh.ory.model.UpdateLoginFlowWithPasswordMethod.class);
                        classByDiscriminatorValue.put("updateLoginFlowWithTotpMethod", sh.ory.model.UpdateLoginFlowWithTotpMethod.class);
                        classByDiscriminatorValue.put("updateLoginFlowWithWebAuthnMethod", sh.ory.model.UpdateLoginFlowWithWebAuthnMethod.class);
                        classByDiscriminatorValue.put("webauthn", sh.ory.model.UpdateLoginFlowWithWebAuthnMethod.class);
                        classByDiscriminatorValue.put("updateLoginFlowBody", sh.ory.model.UpdateLoginFlowBody.class);
                        return getClassByDiscriminator(classByDiscriminatorValue,
                                getDiscriminatorValue(readElement, "method"));
                    }
          })
                .registerTypeSelector(sh.ory.model.UpdateRecoveryFlowBody.class, new TypeSelector<sh.ory.model.UpdateRecoveryFlowBody>() {
                    @Override
                    public Class<? extends sh.ory.model.UpdateRecoveryFlowBody> getClassForElement(JsonElement readElement) {
                        Map<String, Class> classByDiscriminatorValue = new HashMap<String, Class>();
                        classByDiscriminatorValue.put("code", sh.ory.model.UpdateRecoveryFlowWithCodeMethod.class);
                        classByDiscriminatorValue.put("link", sh.ory.model.UpdateRecoveryFlowWithLinkMethod.class);
                        classByDiscriminatorValue.put("updateRecoveryFlowWithCodeMethod", sh.ory.model.UpdateRecoveryFlowWithCodeMethod.class);
                        classByDiscriminatorValue.put("updateRecoveryFlowWithLinkMethod", sh.ory.model.UpdateRecoveryFlowWithLinkMethod.class);
                        classByDiscriminatorValue.put("updateRecoveryFlowBody", sh.ory.model.UpdateRecoveryFlowBody.class);
                        return getClassByDiscriminator(classByDiscriminatorValue,
                                getDiscriminatorValue(readElement, "method"));
                    }
          })
                .registerTypeSelector(sh.ory.model.UpdateRegistrationFlowBody.class, new TypeSelector<sh.ory.model.UpdateRegistrationFlowBody>() {
                    @Override
                    public Class<? extends sh.ory.model.UpdateRegistrationFlowBody> getClassForElement(JsonElement readElement) {
                        Map<String, Class> classByDiscriminatorValue = new HashMap<String, Class>();
                        classByDiscriminatorValue.put("oidc", sh.ory.model.UpdateRegistrationFlowWithOidcMethod.class);
                        classByDiscriminatorValue.put("password", sh.ory.model.UpdateRegistrationFlowWithPasswordMethod.class);
                        classByDiscriminatorValue.put("updateRegistrationFlowWithOidcMethod", sh.ory.model.UpdateRegistrationFlowWithOidcMethod.class);
                        classByDiscriminatorValue.put("updateRegistrationFlowWithPasswordMethod", sh.ory.model.UpdateRegistrationFlowWithPasswordMethod.class);
                        classByDiscriminatorValue.put("updateRegistrationFlowWithWebAuthnMethod", sh.ory.model.UpdateRegistrationFlowWithWebAuthnMethod.class);
                        classByDiscriminatorValue.put("webauthn", sh.ory.model.UpdateRegistrationFlowWithWebAuthnMethod.class);
                        classByDiscriminatorValue.put("updateRegistrationFlowBody", sh.ory.model.UpdateRegistrationFlowBody.class);
                        return getClassByDiscriminator(classByDiscriminatorValue,
                                getDiscriminatorValue(readElement, "method"));
                    }
          })
                .registerTypeSelector(sh.ory.model.UpdateSettingsFlowBody.class, new TypeSelector<sh.ory.model.UpdateSettingsFlowBody>() {
                    @Override
                    public Class<? extends sh.ory.model.UpdateSettingsFlowBody> getClassForElement(JsonElement readElement) {
                        Map<String, Class> classByDiscriminatorValue = new HashMap<String, Class>();
                        classByDiscriminatorValue.put("lookup_secret", sh.ory.model.UpdateSettingsFlowWithLookupMethod.class);
                        classByDiscriminatorValue.put("oidc", sh.ory.model.UpdateSettingsFlowWithOidcMethod.class);
                        classByDiscriminatorValue.put("password", sh.ory.model.UpdateSettingsFlowWithPasswordMethod.class);
                        classByDiscriminatorValue.put("profile", sh.ory.model.UpdateSettingsFlowWithProfileMethod.class);
                        classByDiscriminatorValue.put("totp", sh.ory.model.UpdateSettingsFlowWithTotpMethod.class);
                        classByDiscriminatorValue.put("updateSettingsFlowWithLookupMethod", sh.ory.model.UpdateSettingsFlowWithLookupMethod.class);
                        classByDiscriminatorValue.put("updateSettingsFlowWithOidcMethod", sh.ory.model.UpdateSettingsFlowWithOidcMethod.class);
                        classByDiscriminatorValue.put("updateSettingsFlowWithPasswordMethod", sh.ory.model.UpdateSettingsFlowWithPasswordMethod.class);
                        classByDiscriminatorValue.put("updateSettingsFlowWithProfileMethod", sh.ory.model.UpdateSettingsFlowWithProfileMethod.class);
                        classByDiscriminatorValue.put("updateSettingsFlowWithTotpMethod", sh.ory.model.UpdateSettingsFlowWithTotpMethod.class);
                        classByDiscriminatorValue.put("updateSettingsFlowWithWebAuthnMethod", sh.ory.model.UpdateSettingsFlowWithWebAuthnMethod.class);
                        classByDiscriminatorValue.put("webauthn", sh.ory.model.UpdateSettingsFlowWithWebAuthnMethod.class);
                        classByDiscriminatorValue.put("updateSettingsFlowBody", sh.ory.model.UpdateSettingsFlowBody.class);
                        return getClassByDiscriminator(classByDiscriminatorValue,
                                getDiscriminatorValue(readElement, "method"));
                    }
          })
                .registerTypeSelector(sh.ory.model.UpdateVerificationFlowBody.class, new TypeSelector<sh.ory.model.UpdateVerificationFlowBody>() {
                    @Override
                    public Class<? extends sh.ory.model.UpdateVerificationFlowBody> getClassForElement(JsonElement readElement) {
                        Map<String, Class> classByDiscriminatorValue = new HashMap<String, Class>();
                        classByDiscriminatorValue.put("code", sh.ory.model.UpdateVerificationFlowWithCodeMethod.class);
                        classByDiscriminatorValue.put("link", sh.ory.model.UpdateVerificationFlowWithLinkMethod.class);
                        classByDiscriminatorValue.put("updateVerificationFlowWithCodeMethod", sh.ory.model.UpdateVerificationFlowWithCodeMethod.class);
                        classByDiscriminatorValue.put("updateVerificationFlowWithLinkMethod", sh.ory.model.UpdateVerificationFlowWithLinkMethod.class);
                        classByDiscriminatorValue.put("updateVerificationFlowBody", sh.ory.model.UpdateVerificationFlowBody.class);
                        return getClassByDiscriminator(classByDiscriminatorValue,
                                getDiscriminatorValue(readElement, "method"));
                    }
          })
        ;
        GsonBuilder builder = fireBuilder.createGsonBuilder();
        return builder;
    }

    private static String getDiscriminatorValue(JsonElement readElement, String discriminatorField) {
        JsonElement element = readElement.getAsJsonObject().get(discriminatorField);
        if (null == element) {
            throw new IllegalArgumentException("missing discriminator field: <" + discriminatorField + ">");
        }
        return element.getAsString();
    }

    /**
     * Returns the Java class that implements the OpenAPI schema for the specified discriminator value.
     *
     * @param classByDiscriminatorValue The map of discriminator values to Java classes.
     * @param discriminatorValue The value of the OpenAPI discriminator in the input data.
     * @return The Java class that implements the OpenAPI schema
     */
    private static Class getClassByDiscriminator(Map classByDiscriminatorValue, String discriminatorValue) {
        Class clazz = (Class) classByDiscriminatorValue.get(discriminatorValue);
        if (null == clazz) {
            throw new IllegalArgumentException("cannot determine model class of name: <" + discriminatorValue + ">");
        }
        return clazz;
    }

    {
        GsonBuilder gsonBuilder = createGson();
        gsonBuilder.registerTypeAdapter(Date.class, dateTypeAdapter);
        gsonBuilder.registerTypeAdapter(java.sql.Date.class, sqlDateTypeAdapter);
        gsonBuilder.registerTypeAdapter(OffsetDateTime.class, offsetDateTimeTypeAdapter);
        gsonBuilder.registerTypeAdapter(LocalDate.class, localDateTypeAdapter);
        gsonBuilder.registerTypeAdapter(byte[].class, byteArrayAdapter);
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.AcceptOAuth2ConsentRequest.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.AcceptOAuth2ConsentRequestSession.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.AcceptOAuth2LoginRequest.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ActiveProjectInConsole.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.BatchPatchIdentitiesResponse.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.CORS.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.CheckOplSyntaxResult.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.CheckPermissionResult.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.CloudAccount.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ContinueWith.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ContinueWithSetOrySessionToken.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ContinueWithVerificationUi.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ContinueWithVerificationUiFlow.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.CreateCustomDomainBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.CreateIdentityBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.CreateInviteResponse.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.CreateJsonWebKeySet.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.CreateProjectApiKeyRequest.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.CreateProjectBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.CreateProjectBranding.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.CreateProjectMemberInviteBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.CreateRecoveryCodeForIdentityBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.CreateRecoveryLinkForIdentityBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.CreateRelationshipBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.CreateSubscriptionBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.CreateVerifiableCredentialRequestBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.CredentialSupportedDraft00.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.CustomDomain.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.DeleteMySessionsCount.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.EmailTemplateData.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.EmailTemplateDataBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ErrorAuthenticatorAssuranceLevelNotSatisfied.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ErrorBrowserLocationChangeRequired.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ErrorFlowReplaced.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ErrorGeneric.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ErrorOAuth2.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ExpandedPermissionTree.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.FlowError.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.GenericError.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.GenericErrorContent.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.GenericUsage.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.GetManagedIdentitySchemaLocation.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.GetProjectMetricsResponse.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.GetVersion200Response.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.HealthNotReadyStatus.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.HealthStatus.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.Identity.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.IdentityCredentials.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.IdentityCredentialsOidc.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.IdentityCredentialsOidcProvider.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.IdentityCredentialsPassword.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.IdentityPatch.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.IdentityPatchResponse.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.IdentitySchemaContainer.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.IdentitySchemaPreset.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.IdentityWithCredentials.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.IdentityWithCredentialsOidc.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.IdentityWithCredentialsOidcConfig.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.IdentityWithCredentialsOidcConfigProvider.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.IdentityWithCredentialsPassword.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.IdentityWithCredentialsPasswordConfig.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.InternalGetProjectBrandingBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.InternalIsAXWelcomeScreenEnabledForProjectBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.InternalIsOwnerForProjectBySlugBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.InternalIsOwnerForProjectBySlugResponse.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.InternalProvisionMockSubscription.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.IntrospectedOAuth2Token.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.IsOwnerForProjectBySlug.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.IsReady200Response.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.IsReady503Response.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.JsonPatch.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.JsonWebKey.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.JsonWebKeySet.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.KetoNamespace.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.LoginFlow.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.LogoutFlow.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ManagedIdentitySchema.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ManagedIdentitySchemaValidationResult.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.MemberInvite.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.Message.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.MessageDispatch.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.MetricsDatapoint.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.Namespace.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.NeedsPrivilegedSessionError.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.NormalizedProject.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.NormalizedProjectRevision.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.NormalizedProjectRevisionHook.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.NormalizedProjectRevisionIdentitySchema.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.NormalizedProjectRevisionThirdPartyProvider.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.OAuth2Client.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.OAuth2ClientTokenLifespans.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.OAuth2ConsentRequest.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.OAuth2ConsentRequestOpenIDConnectContext.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.OAuth2ConsentSession.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.OAuth2ConsentSessionExpiresAt.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.OAuth2LoginRequest.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.OAuth2LogoutRequest.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.OAuth2RedirectTo.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.OAuth2TokenExchange.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.OidcConfiguration.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.OidcUserInfo.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.Pagination.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.PaginationHeaders.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ParseError.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.PatchIdentitiesBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.PerformNativeLogoutBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.Plan.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.PlanDetails.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.PostCheckPermissionBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.PostCheckPermissionOrErrorBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.Project.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ProjectApiKey.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ProjectBranding.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ProjectBrandingColors.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ProjectBrandingTheme.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ProjectHost.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ProjectMetadata.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ProjectServiceIdentity.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ProjectServiceOAuth2.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ProjectServicePermission.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.ProjectServices.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.QuotaUsage.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.RFC6749ErrorJson.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.RecoveryCodeForIdentity.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.RecoveryFlow.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.RecoveryIdentityAddress.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.RecoveryLinkForIdentity.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.RegistrationFlow.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.RejectOAuth2Request.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.RelationQuery.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.Relationship.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.RelationshipNamespaces.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.RelationshipPatch.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.Relationships.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.SchemaPatch.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.SelfServiceFlowExpiredError.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.Session.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.SessionAuthenticationMethod.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.SessionDevice.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.SetActiveProjectInConsoleBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.SetCustomDomainBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.SetProject.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.SetProjectBrandingThemeBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.SettingsFlow.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.SourcePosition.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.StripeCustomer.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.SubjectSet.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.Subscription.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.SuccessfulCodeExchangeResponse.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.SuccessfulNativeLogin.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.SuccessfulNativeRegistration.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.SuccessfulProjectUpdate.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.TokenPagination.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.TokenPaginationHeaders.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.TokenPaginationRequestParameters.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.TokenPaginationResponseHeaders.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.TrustOAuth2JwtGrantIssuer.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.TrustedOAuth2JwtGrantIssuer.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.TrustedOAuth2JwtGrantJsonWebKey.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UiContainer.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UiNode.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UiNodeAnchorAttributes.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UiNodeAttributes.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UiNodeImageAttributes.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UiNodeInputAttributes.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UiNodeMeta.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UiNodeScriptAttributes.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UiNodeTextAttributes.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UiText.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateIdentityBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateLoginFlowBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateLoginFlowWithLookupSecretMethod.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateLoginFlowWithOidcMethod.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateLoginFlowWithPasswordMethod.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateLoginFlowWithTotpMethod.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateLoginFlowWithWebAuthnMethod.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateRecoveryFlowBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateRecoveryFlowWithCodeMethod.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateRecoveryFlowWithLinkMethod.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateRegistrationFlowBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateRegistrationFlowWithOidcMethod.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateRegistrationFlowWithPasswordMethod.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateRegistrationFlowWithWebAuthnMethod.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateSettingsFlowBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateSettingsFlowWithLookupMethod.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateSettingsFlowWithOidcMethod.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateSettingsFlowWithPasswordMethod.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateSettingsFlowWithProfileMethod.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateSettingsFlowWithTotpMethod.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateSettingsFlowWithWebAuthnMethod.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateSubscriptionBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateVerificationFlowBody.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateVerificationFlowWithCodeMethod.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.UpdateVerificationFlowWithLinkMethod.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.Usage.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.VerifiableCredentialPrimingResponse.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.VerifiableCredentialProof.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.VerifiableCredentialResponse.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.VerifiableIdentityAddress.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.VerificationFlow.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.Version.CustomTypeAdapterFactory());
        gsonBuilder.registerTypeAdapterFactory(new sh.ory.model.Warning.CustomTypeAdapterFactory());
        gson = gsonBuilder.create();
    }

    /**
     * Get Gson.
     *
     * @return Gson
     */
    public static Gson getGson() {
        return gson;
    }

    /**
     * Set Gson.
     *
     * @param gson Gson
     */
    public static void setGson(Gson gson) {
        JSON.gson = gson;
    }

    public static void setLenientOnJson(boolean lenientOnJson) {
        isLenientOnJson = lenientOnJson;
    }

    /**
     * Serialize the given Java object into JSON string.
     *
     * @param obj Object
     * @return String representation of the JSON
     */
    public static String serialize(Object obj) {
        return gson.toJson(obj);
    }

    /**
     * Deserialize the given JSON string to Java object.
     *
     * @param <T>        Type
     * @param body       The JSON string
     * @param returnType The type to deserialize into
     * @return The deserialized Java object
     */
    @SuppressWarnings("unchecked")
    public static <T> T deserialize(String body, Type returnType) {
        try {
            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);
                return gson.fromJson(jsonReader, returnType);
            } else {
                return gson.fromJson(body, returnType);
            }
        } catch (JsonParseException e) {
            // Fallback processing when failed to parse JSON form response body:
            // return the response body string directly for the String return type;
            if (returnType.equals(String.class)) {
                return (T) body;
            } else {
                throw (e);
            }
        }
    }

    /**
     * Gson TypeAdapter for Byte Array type
     */
    public static class ByteArrayAdapter extends TypeAdapter<byte[]> {

        @Override
        public void write(JsonWriter out, byte[] value) throws IOException {
            if (value == null) {
                out.nullValue();
            } else {
                out.value(ByteString.of(value).base64());
            }
        }

        @Override
        public byte[] read(JsonReader in) throws IOException {
            switch (in.peek()) {
                case NULL:
                    in.nextNull();
                    return null;
                default:
                    String bytesAsBase64 = in.nextString();
                    ByteString byteString = ByteString.decodeBase64(bytesAsBase64);
                    return byteString.toByteArray();
            }
        }
    }

    /**
     * Gson TypeAdapter for JSR310 OffsetDateTime type
     */
    public static class OffsetDateTimeTypeAdapter extends TypeAdapter<OffsetDateTime> {

        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);
            }
        }
    }

    /**
     * Gson TypeAdapter for JSR310 LocalDate type
     */
    public static class LocalDateTypeAdapter extends TypeAdapter<LocalDate> {

        private DateTimeFormatter formatter;

        public LocalDateTypeAdapter() {
            this(DateTimeFormatter.ISO_LOCAL_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.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);
            }
        }
    }

    public static void setOffsetDateTimeFormat(DateTimeFormatter dateFormat) {
        offsetDateTimeTypeAdapter.setFormat(dateFormat);
    }

    public static void setLocalDateFormat(DateTimeFormatter dateFormat) {
        localDateTypeAdapter.setFormat(dateFormat);
    }

    /**
     * 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);
            }
        }

        @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 static void setDateFormat(DateFormat dateFormat) {
        dateTypeAdapter.setFormat(dateFormat);
    }

    public static void setSqlDateFormat(DateFormat dateFormat) {
        sqlDateTypeAdapter.setFormat(dateFormat);
    }
}
