2017-08-15 109 views
0

我正在使用Swagger來爲我的android項目定義API規範。Swagger:java.text.ParseException:無法解析的日期錯誤

這是我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

有誰知道如何解決這個問題?

注意:這些圖像僅用於提供有關錯誤的更加清晰的信息。它基本上顯示了我寫的信息。

+0

請閱讀[爲什麼不在上傳圖片的時候提出問題?](https://meta.stackoverflow.com/questions/285551/why-not-to-upload-images-of-code-在問什麼時候問),然後相應地編輯你的問題。 –

+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文件中的一行包含在最後。

希望這種解釋有助於未來面臨同樣問題的人。