2013-03-22 9 views
28

Il mio server JSON restituisce con due diversi tipi di DateFormat. "MMM GG, aaaa" e "MMM GG, aaaa hh: mm: ss"Conversione da Gson a JSON con due DateFormat

Quando converto il JSON con il seguente va bene:

Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy").create(); 

Ma quando voglio il formato dettagliato della data e lo cambiò a questo, viene generata un'eccezione com.google.gson.JsonSyntaxException: Mar 21, 2013

Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy HH:mm:ss").create(); 

c'è un modo per GSON di gestire due DateFormat diverso per la sua conversione JSON?

risposta

60

Mi trovavo di fronte allo stesso problema. Ecco la mia soluzione tramite deserializzazione personalizzato:

new GsonBuilder().registerTypeAdapter(Date.class, new DateDeserializer()); 

private static final String[] DATE_FORMATS = new String[] { 
     "MMM dd, yyyy HH:mm:ss", 
     "MMM dd, yyyy" 
}; 


private class DateDeserializer implements JsonDeserializer<Date> { 

    @Override 
    public Date deserialize(JsonElement jsonElement, Type typeOF, 
      JsonDeserializationContext context) throws JsonParseException { 
     for (String format : DATE_FORMATS) { 
      try { 
       return new SimpleDateFormat(format, Locale.US).parse(jsonElement.getAsString()); 
      } catch (ParseException e) { 
      } 
     } 
     throw new JsonParseException("Unparseable date: \"" + jsonElement.getAsString() 
       + "\". Supported formats: " + Arrays.toString(DATE_FORMATS)); 
    } 
} 
2

È necessaria la deserializzazione personalizzata. Una soluzione decente sarebbe utilizzare Apache Commons DateUtil, che può gestire più formati di date contemporaneamente. Inoltre, l'API JodaTime potrebbe avere una funzionalità simile.

4

Anche se la risposta è stata accettata ho voluto condividere una soluzione ancora più estensibile simile. Puoi trovare lo gist here.

DateDeserializer.java

public class DateDeserializer<T extends Date> implements JsonDeserializer<T> { 

    private static final String TAG = DateDeserializer.class.getSimpleName(); 

    private final SimpleDateFormat mSimpleDateFormat; 
    private final Class<T> mClazz; 

    public DateDeserializer(SimpleDateFormat simpleDateFormat, Class<T> clazz) { 
     mSimpleDateFormat = simpleDateFormat; 
     mClazz = clazz; 
    } 

    @Override 
    public T deserialize(JsonElement element, Type arg1, JsonDeserializationContext context) throws JsonParseException { 
     String dateString = element.getAsString(); 
     try { 
      T date = mClazz.newInstance(); 
      date.setTime(mSimpleDateFormat.parse(dateString).getTime()); 
      return date; 
     } catch (InstantiationException e) { 
      throw new JsonParseException(e.getMessage(), e); 
     } catch (IllegalAccessException e) { 
      throw new JsonParseException(e.getMessage(), e); 
     } catch (ParseException e) { 
      throw new JsonParseException(e.getMessage(), e); 
     } 
    } 
} 

Quindi registrare i diversi formati come ...

sGson = new GsonBuilder() 
        .registerTypeAdapter(Event.EventDateTime.class, 
          new DateDeserializer<Event.EventDateTime>(
            Event.EventDateTime.DATE_FORMAT, Event.EventDateTime.class)) 
        .registerTypeAdapter(Event.StartEndDateTime.class, 
          new DateDeserializer<Event.StartEndDateTime>(
            Event.StartEndDateTime.DATE_FORMAT, Event.StartEndDateTime.class)) 
        .registerTypeAdapter(Event.SimpleDate.class, 
          new DateDeserializer<Event.SimpleDate>(
            Event.SimpleDate.DATE_FORMAT, Event.SimpleDate.class)) 
        .create(); 

Ogni formato viene poi associata a una classe di ...

public class Event { 

    @SerializedName("created") 
    private EventDateTime mCreated; 

    //@SerializedName("updated") 
    private EventDateTime mUpdated; 

    ... 

    @SerializedName("start") 
    private ConditionalDateTime mStart; 

    @SerializedName("end") 
    private ConditionalDateTime mEnd; 

    public static class ConditionalDateTime { 
     @SerializedName("dateTime") 
     private StartEndDateTime mDateTime; 

     @SerializedName("date") 
     private SimpleDate mDate; 

     public SimpleDate getDate() { 
      return mDate; 
     } 

     public StartEndDateTime getDateTime() { 
      return mDateTime; 
     } 

     /** 
     * If it is an all day event then only date is populated (not DateTime) 
     * @return 
     */ 
     public boolean isAllDayEvent() { 
      return mDate != null; 
     } 
    } 

    public static class EventDateTime extends Date { 
     public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); 
    } 

    public static class StartEndDateTime extends Date { 
     public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZZZ"); 
    } 

    public static class SimpleDate extends java.util.Date { 
     public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); 
    } 
} 
+0

Molto bella soluzione e sicuramente più estensibile. –

+1

Mi piace molto, ma mi chiedo se potrebbe esserci un problema con SimpleDateFormats e sicurezza dei thread. In tal caso, forse è più semplice memorizzare il formato String, e creare un nuovo SimpleDateFormat in ogni chiamata a DateDeserializer.deserialize()? –

Problemi correlati