Swagger:java.text.ParseException:无法解析的日期错误

时间:2017-08-15 05:06:51

标签: java android json gson swagger

我使用Swagger为我的android项目定义API规范。

这就是我的GsonBuilder的初始化方式

public static GsonBuilder gsonBuilder;

  static {
    gsonBuilder = new GsonBuilder();
    gsonBuilder.serializeNulls();
    gsonBuilder.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
  }

我的JSON数据返回参数' creationDate'之一。它的值是 2017-08-14To2:42:59.528Z 但是当它在Swagger模块中通过APIInvoker方法时,它给了我以下错误。

java.text.parseexception:unparseable date "2017-08-14To2:42:59.528Z" 

' creationDate'参数未被反序列化。

enter image description here

当我进一步调试代码时,我发现它在DefaultDateTypeAdapter.java类中失败了。它无法解析deserializeToDate方法中的任何3种格式。

private Date deserializeToDate(JsonElement json) {
    synchronized (localFormat) {
      try {
        return localFormat.parse(json.getAsString());
      } catch (ParseException ignored) {
      }
      try {
        return enUsFormat.parse(json.getAsString());
      } catch (ParseException ignored) {
      }
      try {
        return iso8601Format.parse(json.getAsString());
      } catch (ParseException e) {
        throw new JsonSyntaxException(json.getAsString(), e);
      }
    }
  }

enter image description here

有谁知道如何解决此错误?

注意:发布图像只是为了更清楚地说明错误。它基本上显示了我写的相同信息。

1 个答案:

答案 0 :(得分:0)

这个问题的答案已经解决了。显然,我没有在gradle应用程序文件中提到任何版本的GSON。因此,默认情况下它假定为2.3.1版本。但是,我的GSON数据是2.7版本。这就是它失败的原因。

如果我们使用Gson 2.3.1版本,则defaultdatetypeadapter.java具有以下方法

    final class DefaultDateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> {

  // TODO: migrate to streaming adapter

  private final DateFormat enUsFormat;
  private final DateFormat localFormat;
  private final DateFormat iso8601Format;

  DefaultDateTypeAdapter() {
    this(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US),
        DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT));
  }

  DefaultDateTypeAdapter(String datePattern) {
    this(new SimpleDateFormat(datePattern, Locale.US), new SimpleDateFormat(datePattern));
  }

  DefaultDateTypeAdapter(int style) {
    this(DateFormat.getDateInstance(style, Locale.US), DateFormat.getDateInstance(style));
  }

  public DefaultDateTypeAdapter(int dateStyle, int timeStyle) {
    this(DateFormat.getDateTimeInstance(dateStyle, timeStyle, Locale.US),
        DateFormat.getDateTimeInstance(dateStyle, timeStyle));
  }

  DefaultDateTypeAdapter(DateFormat enUsFormat, DateFormat localFormat) {
    this.enUsFormat = enUsFormat;
    this.localFormat = localFormat;
    this.iso8601Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
    this.iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC"));
  }

  // These methods need to be synchronized since JDK DateFormat classes are not thread-safe
  // See issue 162
  public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
    synchronized (localFormat) {
      String dateFormatAsString = enUsFormat.format(src);
      return new JsonPrimitive(dateFormatAsString);
    }
  }

  public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
      throws JsonParseException {
    if (!(json instanceof JsonPrimitive)) {
      throw new JsonParseException("The date should be a string value");
    }
    Date date = deserializeToDate(json);
    if (typeOfT == Date.class) {
      return date;
    } else if (typeOfT == Timestamp.class) {
      return new Timestamp(date.getTime());
    } else if (typeOfT == java.sql.Date.class) {
      return new java.sql.Date(date.getTime());
    } else {
      throw new IllegalArgumentException(getClass() + " cannot deserialize to " + typeOfT);
    }
  }

  private Date deserializeToDate(JsonElement json) {
    synchronized (localFormat) {
      try {
        return localFormat.parse(json.getAsString());
      } catch (ParseException ignored) {
      }
      try {
        return enUsFormat.parse(json.getAsString());
      } catch (ParseException ignored) {
      }
      try {
        return iso8601Format.parse(json.getAsString());
      } catch (ParseException e) {
        throw new JsonSyntaxException(json.getAsString(), e);
      }
    }
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append(DefaultDateTypeAdapter.class.getSimpleName());
    sb.append('(').append(localFormat.getClass().getSimpleName()).append(')');
    return sb.toString();
  }
}

如果您注意到deserializeToDate方法,则会生成3种格式

1)本地格式

2)enUsFormat

3)iso8601Format

其中

enUsFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")

localFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US)

localFormatiso8601Format都相同。参数creationDate的值为2017-08-14To2:42:59.528Z。出于某种原因,它没有通过3种格式中的任何一种进行解析。

后来,我意识到我使用的是错误的GSON版本,因此我在build.gradle文件中包含了这一行,并再次运行了应用程序。

compile 'com.google.code.gson:gson:2.7'

我运行调试代码并完成了每一步。这次我注意到defaultdatetypeadapter.java文件被更改了。

final class DefaultDateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> {

  // TODO: migrate to streaming adapter

  private final DateFormat enUsFormat;
  private final DateFormat localFormat;

  DefaultDateTypeAdapter() {
    this(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US),
        DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT));
  }

  DefaultDateTypeAdapter(String datePattern) {
    this(new SimpleDateFormat(datePattern, Locale.US), new SimpleDateFormat(datePattern));
  }

  DefaultDateTypeAdapter(int style) {
    this(DateFormat.getDateInstance(style, Locale.US), DateFormat.getDateInstance(style));
  }

  public DefaultDateTypeAdapter(int dateStyle, int timeStyle) {
    this(DateFormat.getDateTimeInstance(dateStyle, timeStyle, Locale.US),
        DateFormat.getDateTimeInstance(dateStyle, timeStyle));
  }

  DefaultDateTypeAdapter(DateFormat enUsFormat, DateFormat localFormat) {
    this.enUsFormat = enUsFormat;
    this.localFormat = localFormat;
  }

  // These methods need to be synchronized since JDK DateFormat classes are not thread-safe
  // See issue 162
  @Override
  public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
    synchronized (localFormat) {
      String dateFormatAsString = enUsFormat.format(src);
      return new JsonPrimitive(dateFormatAsString);
    }
  }

  @Override
  public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
      throws JsonParseException {
    if (!(json instanceof JsonPrimitive)) {
      throw new JsonParseException("The date should be a string value");
    }
    Date date = deserializeToDate(json);
    if (typeOfT == Date.class) {
      return date;
    } else if (typeOfT == Timestamp.class) {
      return new Timestamp(date.getTime());
    } else if (typeOfT == java.sql.Date.class) {
      return new java.sql.Date(date.getTime());
    } else {
      throw new IllegalArgumentException(getClass() + " cannot deserialize to " + typeOfT);
    }
  }

  private Date deserializeToDate(JsonElement json) {
    synchronized (localFormat) {
      try {
        return localFormat.parse(json.getAsString());
      } catch (ParseException ignored) {}
      try {
        return enUsFormat.parse(json.getAsString());
      } catch (ParseException ignored) {}
      try {
        return ISO8601Utils.parse(json.getAsString(), new ParsePosition(0));
      } catch (ParseException e) {
        throw new JsonSyntaxException(json.getAsString(), e);
      }
    }
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append(DefaultDateTypeAdapter.class.getSimpleName());
    sb.append('(').append(localFormat.getClass().getSimpleName()).append(')');
    return sb.toString();
  }
}

如果你现在注意到deserializeToDate方法,它会生成一种不同的格式,它显示的GSON版本是2.7。

1)localFormat

2)enUsFormat

3)ISO8601Utils

这次,通过creationDate方法成功解析了ISO8601Utils值。

我在努力寻找最后一周的解决方案。最后,build.gradle文件中的一行包含最终产生了不同。

希望这个解释有助于将来面临同样问题的人。